diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b512c09 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +node_modules \ No newline at end of file diff --git a/README.md b/README.md index 7beb7ce..533a744 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,7 @@

- -👋 Hej välkommen på [AgileSearch](agilesearch) fullstack challenge! +👋 Hej välkommen på [AgileSearch](agilesearch) fullstack challenge! My name is Broodar Plawind and I'm living in a far far away solar system located in the Arkanis sector of the Outer Rim Territories, in the Tatooine desert. @@ -11,14 +10,14 @@ I'm would love to spend the next months travelling around the universe, my idea Could you help me to get the right spaceship tickets for me? I'm afraid that I'm not good enough with today's technology and I don't know where to start. ----- +--- _How would you help Brooday to get the **best experience** for planning his vacations?_ We are going to evaluate everything, but the main focus will be: -* :bulb: Creativity. -* :wrench: Tools. -* :man_technologist: Good practice in the choosen technology. +- :bulb: Creativity. +- :wrench: Tools. +- :man_technologist: Good practice in the choosen technology. ## Dataset @@ -31,9 +30,9 @@ The `dataset.json` has all the necessary information for searching with the foll destination: String, price: Float, availability: Number, - date: String - } -] + date: String, + }, +]; ``` ## Planets @@ -46,10 +45,48 @@ We encourage you to fork this repository and when you are done with the challeng If your solution needs to prepare an environment of any kind, please don't forget to let us know. -###### 🙌 Psst, One more thing! +###### 🙌 Psst, One more thing! The challenge is open to any solution. You can use your imagination, creativity and skills to deliver the best of the worlds you like the most. You can always reach us by writing an email with all your questions and/or feedback about this challenge. [agilesearch]: https://www.agilesearch.io + +## Prerequisite + +To run the project you will need the latest/LTS version of Nodejs + +## Setting up the project + +Clone the repository and install the dependencies using the following command. + +``` + yarn install +``` + +## Development + +You can start the project by running the following command. + +``` +yarn start +``` + +### Libraries used + +The following libraries are used in the project. + +- [semantic-ui-react](https://react.semantic-ui.com/) : For UI components +- [react-router-dom](https://reactrouter.com/en/main) : For routing to SPA app +- [react-semantic-ui-datepickers](https://github.com/arthurdenner/react-semantic-ui-datepickers) : Datepicker component with semantic-ui-react touch +- [dayjs](https://day.js.org/) : To deal with complex date tasks (adding dates, checking dates etc.) + +### Known issues + +- The _Clear_ button in home page doesnt clear the date picker +- The dates selected by _react-semantic-ui-datepickers_ gives a day prior to what the user selects (to mitigate this I add an extra day) + +### Demo + +You can test the Demo application using the [live site](https://starwars-planet-travel.netlify.app/). diff --git a/package.json b/package.json new file mode 100644 index 0000000..d3de12e --- /dev/null +++ b/package.json @@ -0,0 +1,53 @@ +{ + "name": "starwars", + "version": "0.1.0", + "private": true, + "dependencies": { + "@testing-library/jest-dom": "^5.16.5", + "@testing-library/react": "^13.3.0", + "@testing-library/user-event": "^13.5.0", + "@types/jest": "^27.5.2", + "@types/node": "^16.11.50", + "@types/react": "^18.0.17", + "@types/react-dom": "^18.0.6", + "dayjs": "^1.11.5", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-router-dom": "6", + "react-scripts": "5.0.1", + "react-select": "^5.4.0", + "react-semantic-ui-datepickers": "^2.17.1", + "semantic-ui-css": "^2.4.1", + "semantic-ui-react": "^2.1.3", + "typescript": "^4.7.4", + "web-vitals": "^2.1.4" + }, + "scripts": { + "start": "react-scripts start", + "build": "react-scripts build", + "test": "react-scripts test", + "eject": "react-scripts eject", + "postinstall": "semantic-ui-css-patch" + }, + "eslintConfig": { + "extends": [ + "react-app", + "react-app/jest" + ] + }, + "browserslist": { + "production": [ + ">0.2%", + "not dead", + "not op_mini all" + ], + "development": [ + "last 1 chrome version", + "last 1 firefox version", + "last 1 safari version" + ] + }, + "devDependencies": { + "@semantic-ui-react/css-patch": "^1.1.2" + } +} diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 0000000..a11777c Binary files /dev/null and b/public/favicon.ico differ diff --git a/public/index.html b/public/index.html new file mode 100644 index 0000000..aa069f2 --- /dev/null +++ b/public/index.html @@ -0,0 +1,43 @@ + + + + + + + + + + + + + React App + + + +
+ + + diff --git a/public/logo192.png b/public/logo192.png new file mode 100644 index 0000000..fc44b0a Binary files /dev/null and b/public/logo192.png differ diff --git a/public/logo512.png b/public/logo512.png new file mode 100644 index 0000000..a4e47a6 Binary files /dev/null and b/public/logo512.png differ diff --git a/public/manifest.json b/public/manifest.json new file mode 100644 index 0000000..080d6c7 --- /dev/null +++ b/public/manifest.json @@ -0,0 +1,25 @@ +{ + "short_name": "React App", + "name": "Create React App Sample", + "icons": [ + { + "src": "favicon.ico", + "sizes": "64x64 32x32 24x24 16x16", + "type": "image/x-icon" + }, + { + "src": "logo192.png", + "type": "image/png", + "sizes": "192x192" + }, + { + "src": "logo512.png", + "type": "image/png", + "sizes": "512x512" + } + ], + "start_url": ".", + "display": "standalone", + "theme_color": "#000000", + "background_color": "#ffffff" +} diff --git a/public/robots.txt b/public/robots.txt new file mode 100644 index 0000000..e9e57dc --- /dev/null +++ b/public/robots.txt @@ -0,0 +1,3 @@ +# https://www.robotstxt.org/robotstxt.html +User-agent: * +Disallow: diff --git a/src/App.test.tsx b/src/App.test.tsx new file mode 100644 index 0000000..2a68616 --- /dev/null +++ b/src/App.test.tsx @@ -0,0 +1,9 @@ +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import App from './App'; + +test('renders learn react link', () => { + render(); + const linkElement = screen.getByText(/learn react/i); + expect(linkElement).toBeInTheDocument(); +}); diff --git a/src/App.tsx b/src/App.tsx new file mode 100644 index 0000000..5754066 --- /dev/null +++ b/src/App.tsx @@ -0,0 +1,20 @@ +import Home from "./pages/Home"; +import Final from "./pages/Final"; +import Navigation from "./components/Navigation"; +import { BrowserRouter, Routes, Route } from "react-router-dom"; + +function App() { + return ( + + + + } /> + } /> + } /> + + + + ); +} + +export default App; diff --git a/src/AppType.ts b/src/AppType.ts new file mode 100644 index 0000000..230f170 --- /dev/null +++ b/src/AppType.ts @@ -0,0 +1,25 @@ +export type PlanetType = { + name: string; + code: string; +}; + +export type FlightType = { + id?: number; + data: string; + origin: string; + destination: string; + price: number; + nodays: number; + availability: number; +}; + +export type DetailsType = { + origin: string; + destinations: Array; + date: string; +}; + +export interface FlightRowType extends FlightType { + addTrip: (data: FlightType) => void; + getNameByCode: (code: string) => string; +} diff --git a/src/components/FlightRows.tsx b/src/components/FlightRows.tsx new file mode 100644 index 0000000..f69001b --- /dev/null +++ b/src/components/FlightRows.tsx @@ -0,0 +1,77 @@ +import { Fragment, useState } from "react"; +import dayjs from "dayjs"; +import { Button, Card, Input, Icon, Modal } from "semantic-ui-react"; + +import { FlightRowType } from "../AppType"; + +function FlightRows({ + data, + destination, + origin, + price, + availability, + addTrip, + getNameByCode, +}: FlightRowType) { + const [nodays, setNoDays] = useState(0); + const [open, setOpen] = useState(false); + + return ( + + ${getNameByCode(destination)}`} + meta={dayjs(data).toISOString().slice(0, 10)} + description={`Price : ${price}`} + extra={ + + + {availability} + + } + onClick={() => { + setOpen(true); + }} + /> + setOpen(false)} open={open}> + Number of days + + +

Enter the number of days you are planing to stay

+ { + setNoDays(parseInt(value)); + }} + > +
+
+ + + + + + + + + {details?.destinations?.length === 0 ? ( + + + +
Please select Origin and Date
+
+ +
+ ) : null} + + + + {showTrips ? ( + + + + +
Select Flight
+
+ +
+ + + + + {selectFlightData?.length > 0 ? ( + selectFlightData.map((trip) => { + return ( + + ); + }) + ) : ( + + )} + + + + +
+ ) : null} +
+ + {details?.destinations?.length > 0 ? ( + + + + +
Selected Flight
+
+ +
+ + + + + {details?.destinations.map((trip: FlightType) => { + return ( + + ); + })} + + + + + + + +