Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FR | image files #2

Open
wants to merge 39 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
acabb86
FR | image files
Farah-Rashid Jun 24, 2022
706c384
FR | final commit
Farah-Rashid Jun 24, 2022
c89032b
FR | added }
Farah-Rashid Jul 25, 2022
fa94c15
FR | removed commented code
Farah-Rashid Jul 25, 2022
ffc2bba
FR | added _ instead of seat variable
Farah-Rashid Jul 25, 2022
db82ee9
FR | updated conditional rendering
Farah-Rashid Jul 25, 2022
124d5bc
FR | extracted logic into a new component
Farah-Rashid Jul 25, 2022
abbc1bf
FR | added key attribute
Farah-Rashid Jul 25, 2022
102a6ea
FR | removed inline styles
Farah-Rashid Jul 25, 2022
d9dfeea
FR | updated modal styles
Farah-Rashid Jul 25, 2022
5fa282a
FR | added dynamic routing
Farah-Rashid Jul 25, 2022
f2aff88
FR | added separate file for constants
Farah-Rashid Jul 25, 2022
b7f632e
FR | added switch statements
Farah-Rashid Jul 25, 2022
d79be22
FR | added switch statements
Farah-Rashid Jul 25, 2022
d9f6de7
FR | deleted images files
Farah-Rashid Jul 25, 2022
1b69899
FR | resolved comma issue
Farah-Rashid Jul 26, 2022
8e16b5e
FR | added const variable
Farah-Rashid Jul 26, 2022
46b0e78
FR | renamed style files
Farah-Rashid Jul 26, 2022
fc7f9a7
FR |removed button border
Farah-Rashid Jul 26, 2022
051834f
FR |refactor component to smaller components
Farah-Rashid Jul 26, 2022
e1e306d
FR |added INTER font
Farah-Rashid Jul 27, 2022
70ba1fd
FR |updated selected seat logic
Farah-Rashid Jul 27, 2022
067098c
FR | refactor nested switch cases
Farah-Rashid Aug 16, 2022
099f869
FR | refactor nested switch cases
Farah-Rashid Aug 16, 2022
6312008
FR | refactor booking URL path
Farah-Rashid Aug 16, 2022
ef55983
FR | updated seat designs
Farah-Rashid Aug 16, 2022
32987fa
FR | updated varaible names
Farah-Rashid Aug 16, 2022
79eefde
FR | removed article
Farah-Rashid Aug 16, 2022
6d5973a
FR | changed the order of function calling
Farah-Rashid Aug 16, 2022
faffc41
FR | used arrow functions
Farah-Rashid Aug 16, 2022
68bb5a4
FR | moved img url to constant file
Farah-Rashid Aug 16, 2022
feb06af
FR | moved global styles to index.js
Farah-Rashid Aug 16, 2022
a6f41d3
FR | renamed icon
Farah-Rashid Aug 17, 2022
068f237
FR | moved constant file to src directory
Farah-Rashid Aug 17, 2022
cdaabc6
FR | changed path of constant file
Farah-Rashid Aug 17, 2022
72f9293
FR | updated prettier settings
Farah-Rashid Aug 17, 2022
ecf9496
FR | added try catch block
Farah-Rashid Aug 17, 2022
baceccf
FR | made button reusable
Farah-Rashid Aug 17, 2022
bcbb92d
FR | made booked seat non-clickable
Farah-Rashid Aug 17, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
"react": "^18.1.0",
"react-dom": "^18.1.0",
"react-redux": "^8.0.2",
"react-router": "^6.3.0",
"react-router-dom": "^6.3.0",
"react-scripts": "5.0.1",
"redux": "^4.2.0",
"styled-components": "^5.3.5"
Expand Down
4 changes: 4 additions & 0 deletions public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@
content="Web site created using create-react-app"
/>
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />


<link href="https://fonts.googleapis.com/css2?family=Inter&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Roboto+Mono:wght@500&family=Rubik:wght@600&display=swap" rel="stylesheet">
<!--
manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
Expand Down
18 changes: 15 additions & 3 deletions src/App.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
import React from "react";
import {Routes, Route} from "react-router-dom";
import HomePage from "../src/components/HomePage";
import BookingSeat from "../src/components/BookingSeat";
function App() {
return (
<>
<Routes>
<Route path="/" element={<HomePage/>}/>
<Route path="/bookingseat/:id/:path" element={<BookingSeat/>}/>
Copy link
Collaborator

@hhkk28 hhkk28 Aug 1, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The redirected url when a movie is clicked - http://localhost:3000/bookingseat/438148/wKiOkZTN9lUUUNZLmtnwubZYONg.jpg The url should be - http://localhost:3000/book/438148/minions-the-rise-of-gru

</Routes>

export default function App() {
return <h1>Hello world!</h1>
}
</>
);
}

export default App;
16 changes: 16 additions & 0 deletions src/Asset/SvgImg.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import React from 'react'
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please rename the file to be more specific may be like SeatIcon or SeatComponent. Since this is a react component, change extension to jsx to stay consistent with naming and move it with other react components.


const SvgImg = ({colorName}) => {
return (
<svg width="100" height="80" viewBox="0 0 100 80" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="29.5" y="12.5" width="41" height="41" fill={colorName} stroke="white"/>
<mask id="path-2-inside-1_324_100" fill="white">
<path fillRule="evenodd" clipRule="evenodd" d="M28 26H6V71H94V26H72V55H28V26Z"/>
</mask>
<path fillRule="evenodd" clipRule="evenodd" d="M28 26H6V71H94V26H72V55H28V26Z" fill={colorName}/>
<path d="M6 26V25H5V26H6ZM28 26H29V25H28V26ZM6 71H5V72H6V71ZM94 71V72H95V71H94ZM94 26H95V25H94V26ZM72 26V25H71V26H72ZM72 55V56H73V55H72ZM28 55H27V56H28V55ZM6 27H28V25H6V27ZM7 71V26H5V71H7ZM94 70H6V72H94V70ZM93 26V71H95V26H93ZM72 27H94V25H72V27ZM71 26V55H73V26H71ZM72 54H28V56H72V54ZM29 55V26H27V55H29Z" fill="white" mask="url(#path-2-inside-1_324_100)"/>
</svg>
)
}

export default SvgImg
Binary file added src/Asset/Vector 1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/Asset/Vector.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/Asset/Xclose.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/Asset/undraw.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
66 changes: 66 additions & 0 deletions src/components/BookingSeat.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import React, { useState } from "react";
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refactor this component to smaller components and separate logic from presentation.

import { useParams } from "react-router-dom";
import Modal from "./Modal";
import vector from "../Asset/Vector 1.png";
import {
BookingStyles,
VectorImg,
ConfirmButton,
} from "../styles/Booking.styled";
import MovieSeats from "./MovieSeats";

function BookingSeat() {
const [modalVisible, setModalVisible] = useState(false);
const [selectedSeats, setSelectedSeats] = useState([]);

let param = useParams();
let selected = [];
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please elaborate the difference between the variable names selectedSeats and selected array.


if (JSON.stringify(localStorage.getItem(param.id)) !== "null") {
selected = localStorage.getItem(param.id);
}

const modalHandle = () => {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please refactor this nested switch case to single switch statement.

setModalVisible(true);
switch (selectedSeats.length > 10) {
case true:
setModalVisible(false);
alert(`you can't select more than 10 seats..
you have selected ${selectedSeats.length} seats.
Please deselect ${selectedSeats.length - 10} seats`);
break;
default:
switch (selectedSeats.length) {
case 0:
setModalVisible(false);
alert(" Please select seats first");
break;
default:
selected = selected + selectedSeats + ",";
localStorage.setItem(param.id, selected);
selected = localStorage.getItem(param.id)
}
}
};

return (
<BookingStyles>
<VectorImg src={vector} alt="vector" />
<MovieSeats selectedSeats ={selectedSeats}
selected ={selected}
setSelectedSeats={setSelectedSeats}
/>
<ConfirmButton onClick={modalHandle}>Confirm booking</ConfirmButton>
<article>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove this article tag.

{modalVisible && (
<Modal
setVisible={setModalVisible}
selectedSeats={selectedSeats}
setSelectedSeats={setSelectedSeats}
/>
)}
</article>
</BookingStyles>
);
}
export default BookingSeat;
64 changes: 64 additions & 0 deletions src/components/HomePage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import React, { useState, useEffect } from "react";
import axios from "axios";
import MovieCard from "./MovieCard";

import { Container } from "../styles/Container.styled";
import GlobalStyles from "../styles/Global.styled";
import { Cards } from "../styles/Cards.styled"
import PageNotFound from "./PageNotFound";
import {apiUrl,searchUrl} from "./constants/Global"


function HomePage(){
const [movies, setMovies] = useState([]);
const [searchTerm, setSearchTerm] = useState("");

useEffect(() => {
getMovies(apiUrl)
},
[])

async function getMovies(url) {
Copy link
Collaborator

@hhkk28 hhkk28 Aug 1, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please declare function before calling the function.

const response = await axios.get(url);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add error handling. Always wrap the API calls inside try catch block and handle errors if any.

const result = response.data.results;

setMovies(result);
}

const submit = (e) => {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please be consistent with syntax. either choose function keyword and use it across the app or choose arrow function syntax and use it across the app. Do not mix both.

e.preventDefault();
if (searchTerm) {
getMovies(`${searchUrl}&query=${searchTerm}`)
} else {
getMovies(apiUrl)
}
}

return (
<>
<GlobalStyles />
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add global styles in the index.js file instead of using it in a particular component.

<Container>
<h1>Book Tickets</h1>
<form onSubmit={submit}>
<input type="text" placeholder="search"
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
/>
</form>
</Container>
{movies.length > 0 ? (
<Cards>
{movies.map((movie) =>
<MovieCard movie={movie} key = {movie.id}/>
)}
</Cards>
) : (
<PageNotFound/>
)}


</>
);
}

export default HomePage;
74 changes: 74 additions & 0 deletions src/components/Modal.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import React from "react";
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adjust the modal styling to always be in the center.


import {
ModalStyle,
CloseButton,
DataFlex,
MoviePic,
ModalH1,
ModalH3,
ModalH5,
ModalSmall,
ModalDiv,
ModalDivSeat,
ModalSeatH1,
ModalScreen,
} from "../styles/Booking.styled";

import close from "../Asset/Xclose.png";
import { useParams } from "react-router";
const imgUrl = "https://image.tmdb.org/t/p/w500/";
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is already a constant file to maintain all the urls, please move this variable to that file.

export default function Modal({ setVisible, selectedSeats, setSelectedSeats }) {
const modalClose = () => {
setVisible(false);
setSelectedSeats([]);
};
const param = useParams();
return (
<ModalScreen>
<ModalStyle>
<CloseButton onClick={modalClose} src={close} alt="close" />
<ModalH1>Thank you for booking</ModalH1>
<ModalH3>Order Summary</ModalH3>
<ModalDiv>
<MoviePic src={imgUrl + param.path} alt="movie" />

<article>
<h3>Seats:</h3>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The seats text is not as per the design. Please check and update.

<ModalDivSeat>
<ModalSeatH1>{selectedSeats.toString()}</ModalSeatH1>
</ModalDivSeat>
<DataFlex>
<article>
<ModalH5>{selectedSeats.length}*250</ModalH5>
<br />
<ModalSmall>CGST(12%)</ModalSmall>
<br />
<ModalSmall>SGST(12%)</ModalSmall>
</article>
<article>
<ModalH5>{selectedSeats.length * 250}</ModalH5>
<br />
<ModalSmall>
{12 * (1 / 100) * (selectedSeats.length * 250)}
</ModalSmall>
<br />
<ModalSmall>
{12 * (1 / 100) * (selectedSeats.length * 250)}
</ModalSmall>
</article>
</DataFlex>
<hr />
<DataFlex>
<ModalH5>Total</ModalH5>
<ModalH5>
{selectedSeats.length * 250 +
12 * (1 / 100) * (selectedSeats.length * 250) * 2}
</ModalH5>
</DataFlex>
</article>
</ModalDiv>
</ModalStyle>
</ModalScreen>
);
}
20 changes: 20 additions & 0 deletions src/components/MovieCard.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import React from "react";
import { NavLink } from "react-router-dom";
import { Card } from "../styles/MovieCard.styled";
import {imgUrl,fakeImg} from './constants/Global'
const MovieCard = ({ movie }) => {

return (
<Card key={movie.id}>
<h3>{movie.title}</h3>
<img src={movie.poster_path?imgUrl + movie.poster_path:fakeImg} alt={movie.id} />
<NavLink to={`/bookingseat/${movie.id}${movie.poster_path}`}>
<button>Book now</button>
</NavLink>
</Card>
)

}


export default MovieCard;
74 changes: 74 additions & 0 deletions src/components/MovieSeats.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import React from "react";
import { data } from "./constants/Global";
import { BookingTableSeats, SeatRow } from "../styles/Booking.styled";
import SvgImg from "../Asset/SvgImg";

const MovieSeats = ({ selectedSeats, selected, setSelectedSeats }) => {
function handleSeats(id) {
if (selected.includes(id)) {
alert("already selected");
let data = selectedSeats.filter((item) => {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Conflicting variable names. Please fix it.

return selected.includes(id) !== selectedSeats[item];
});
setSelectedSeats(data);
} else {
if (selectedSeats.includes(id)) {
const updatedSeats = selectedSeats.filter((seatId) => seatId !== id);
setSelectedSeats(updatedSeats);
} else {
setSelectedSeats((prevSeats) => [...prevSeats, id]);
}
}
}
return (
<BookingTableSeats>
<thead>
<tr>
<th> </th>
{data.seats.map((seatno) => (
<th key={seatno}>{seatno}</th>
))}
</tr>
</thead>
<tbody>
{data.id.map((id) => {
return (
<React.Fragment key={id}>
<tr>
<SeatRow>{id}</SeatRow>
{data.seats.map((_, index) => {
return (
<React.Fragment key={index}>
<td
key={id + index}
onClick={() => handleSeats(id + (index + 1))}
>
{(() => {
switch (selected.includes(id + (index + 1))) {
case true:
return <SvgImg colorName="#626262" />;
default:
switch (
selectedSeats.includes(id + (index + 1))
) {
case true:
return <SvgImg colorName="#724FD8" />;
default:
return <SvgImg colorName="#DADADA" />;
}
}
})()}
</td>
</React.Fragment>
);
})}
</tr>
</React.Fragment>
);
})}
</tbody>
</BookingTableSeats>
);
};

export default MovieSeats;
13 changes: 13 additions & 0 deletions src/components/PageNotFound.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import React from "react";
import img from "../Asset/undraw.png";
import { Empty } from "../styles/Empty.styled";
const PageNotFound = () => {
return (
<Empty>
<h2>Sorry, there is no result for keyword you searched.</h2>
<img src={img} alt="no img found" />
</Empty>
);
};

export default PageNotFound;
11 changes: 11 additions & 0 deletions src/components/constants/Global.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export const imgUrl = "https://image.tmdb.org/t/p/w500/";
Copy link
Collaborator

@hhkk28 hhkk28 Aug 1, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The global constants should be under src director and should available to access from anywhere in the codebase.

export const fakeImg = "http://via.placeholder.com/1080x1580/";
export const apiKey = "api_key=" + process.env.REACT_APP_API_KEY;
export const baseUrl = "https://api.themoviedb.org/3";
export const apiUrl =
baseUrl + "/discover/movie?sort_by=popularity.desc&" + apiKey;
export const searchUrl = baseUrl + "/search/movie?" + apiKey + "&query=";
export const data = {
id: ["A", "B", "C", "D"],
seats: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
};
Loading