From 51db72ed549b740c372b9384128f579d671bed6b Mon Sep 17 00:00:00 2001 From: Santiago Lo Coco Date: Mon, 30 Oct 2023 19:31:58 -0300 Subject: [PATCH] Update screen-domain Also, add new methods in flights-domain --- .gitignore | 3 +- browser-domain/src/components/Home/Home.tsx | 4 +- .../src/api/cruds/flight.py | 25 ++- .../src/api/routes/flights.py | 11 +- gateway/src/api/routes/flights.py | 4 +- run.sh | 1 + screen-domain/Dockerfile.prod | 4 +- screen-domain/package-lock.json | 80 ++++++++++ screen-domain/package.json | 4 +- screen-domain/src/Api.ts | 3 +- screen-domain/src/App.tsx | 9 +- screen-domain/src/components/Home/Arrival.tsx | 98 ++++++++++++ .../src/components/Home/Departure.tsx | 113 ++++++++++++++ screen-domain/src/components/Home/Home.css | 42 ++++++ .../src/components/Home/Home.test.tsx | 2 +- screen-domain/src/components/Home/Home.tsx | 25 ++- screen-domain/src/components/Home/Page.css | 33 ++++ screen-domain/src/db.ts | 75 ++++----- .../src/hooks/useFetchDestination.tsx | 142 ++++++++++++++++++ screen-domain/src/hooks/useFetchOrigin.tsx | 142 ++++++++++++++++++ screen-domain/src/hooks/useFetchZones.tsx | 90 ----------- screen-domain/src/hooks/useIsConnected.tsx | 12 +- screen-domain/test.sh | 7 +- 23 files changed, 765 insertions(+), 164 deletions(-) create mode 100644 screen-domain/src/components/Home/Arrival.tsx create mode 100644 screen-domain/src/components/Home/Departure.tsx create mode 100644 screen-domain/src/components/Home/Home.css create mode 100644 screen-domain/src/components/Home/Page.css create mode 100644 screen-domain/src/hooks/useFetchDestination.tsx create mode 100644 screen-domain/src/hooks/useFetchOrigin.tsx delete mode 100644 screen-domain/src/hooks/useFetchZones.tsx diff --git a/.gitignore b/.gitignore index 7c4f084..ff58439 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,5 @@ node_modules *.xml notification-domain/ TODO.txt -*.sh \ No newline at end of file +*.sh +coverage/ \ No newline at end of file diff --git a/browser-domain/src/components/Home/Home.tsx b/browser-domain/src/components/Home/Home.tsx index 6e9b8c6..ba29b5f 100644 --- a/browser-domain/src/components/Home/Home.tsx +++ b/browser-domain/src/components/Home/Home.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from "react"; +import React from "react"; import { Card } from "./Card/Card"; import { useFetchZones } from "../../hooks/useFetchZones"; import { Flight } from "../../Types"; @@ -23,7 +23,7 @@ export const Home: React.FC = (props) => { return (
- {isAirline ? : <>} + {isAirline ? : <>}

Flights

{(props.flights ? props.flights : zones).map((u) => { diff --git a/flights-domain/flights-information/src/api/cruds/flight.py b/flights-domain/flights-information/src/api/cruds/flight.py index 130be7c..cd1f159 100644 --- a/flights-domain/flights-information/src/api/cruds/flight.py +++ b/flights-domain/flights-information/src/api/cruds/flight.py @@ -1,3 +1,4 @@ +from sqlalchemy import Date from sqlalchemy.orm import Session from sqlalchemy.sql import func @@ -48,9 +49,29 @@ def get_flights_by_origin(db: Session, origin: str): return db.query(Flight).filter(Flight.origin == origin).all() -def get_flights_update(db: Session, origin: str, lastUpdate: str): +def get_flights_by_destination(db: Session, destination: str): + return db.query(Flight).filter(Flight.destination == destination).all() + + +def get_flights_update_origin(db: Session, origin: str, lastUpdate: str): return ( db.query(Flight) - .filter((Flight.origin == origin) & (Flight.last_updated >= lastUpdate)) + .filter( + (Flight.origin == origin) + & (Flight.last_updated >= lastUpdate) + & (Flight.departure_time.cast(Date) >= func.current_date()) + ) + .all() + ) + + +def get_flights_update_destination(db: Session, destination: str, lastUpdate: str): + return ( + db.query(Flight) + .filter( + (Flight.destination == destination) + & (Flight.last_updated >= lastUpdate) + & (Flight.arrival_time.cast(Date) >= func.current_date()) + ) .all() ) diff --git a/flights-domain/flights-information/src/api/routes/flights.py b/flights-domain/flights-information/src/api/routes/flights.py index cb7c178..9b1ba67 100644 --- a/flights-domain/flights-information/src/api/routes/flights.py +++ b/flights-domain/flights-information/src/api/routes/flights.py @@ -51,13 +51,20 @@ async def update_flight( @router.get("", response_model=list[Flight]) def get_flights( origin: Optional[str] = None, + destination: Optional[str] = None, lastUpdated: Optional[str] = None, db: Session = Depends(get_db), ): if origin and lastUpdated: - flights = flight_crud.get_flights_update(db, origin, lastUpdated) + flights = flight_crud.get_flights_update_origin(db, origin, lastUpdated) + elif destination and lastUpdated: + flights = flight_crud.get_flights_update_destination( + db, destination, lastUpdated + ) elif origin: - flights = flight_crud.get_flights_by_origin(db, origin) + flights = flight_crud.get_flights_by_origin(db=db, origin=origin) + elif destination: + flights = flight_crud.get_flights_by_destination(db=db, destination=destination) else: flights = flight_crud.get_flights(db=db) diff --git a/gateway/src/api/routes/flights.py b/gateway/src/api/routes/flights.py index f1315c2..45bce7f 100644 --- a/gateway/src/api/routes/flights.py +++ b/gateway/src/api/routes/flights.py @@ -51,10 +51,12 @@ async def update_flight( @router.get("", response_model=list[Flight]) -async def get_flights(origin: Optional[str] = None, lastUpdated: Optional[str] = None): +async def get_flights(origin: Optional[str] = None, destination: Optional[str] = None, lastUpdated: Optional[str] = None): query = {} if origin: query["origin"] = origin + if destination: + query["destination"] = destination if lastUpdated: query["lastUpdated"] = lastUpdated (response, status, _) = await request(f"{API_FLIGHTS}", "GET", query=query) diff --git a/run.sh b/run.sh index 6005839..c4b191b 100755 --- a/run.sh +++ b/run.sh @@ -144,6 +144,7 @@ else export SUBSCRIPTION_MANAGER=subscription-domain/subscription-manager docker build $SUBSCRIPTION_MANAGER -f $SUBSCRIPTION_MANAGER/Dockerfile.prod -t $USER/subs-manager:prod + export REACT_APP_ORIGIN=Frankfurt docker build screen-domain -f screen-domain/Dockerfile.prod --build-arg "REACT_APP_ORIGIN=$REACT_APP_ORIGIN" -t $USER/screen-client:prod docker build browser-domain -f browser-domain/Dockerfile.prod -t $USER/browser-client:prod diff --git a/screen-domain/Dockerfile.prod b/screen-domain/Dockerfile.prod index 8bf6e5a..552d8e6 100644 --- a/screen-domain/Dockerfile.prod +++ b/screen-domain/Dockerfile.prod @@ -1,7 +1,7 @@ FROM node:17.9.1 AS app WORKDIR /app -COPY package.json /app/package.json -RUN npm -v && ls -al +COPY package.json . +COPY package-lock.json . RUN npm install COPY . . diff --git a/screen-domain/package-lock.json b/screen-domain/package-lock.json index 98a6dee..fe35f91 100644 --- a/screen-domain/package-lock.json +++ b/screen-domain/package-lock.json @@ -15,6 +15,7 @@ "react-router": "^6.10.0", "react-router-dom": "^6.10.0", "react-scripts": "5.0.1", + "react-super-responsive-table": "^5.2.2", "web-vitals": "^2.1.4" }, "devDependencies": { @@ -27,6 +28,7 @@ "@types/react-dom": "^18.0.11", "jest": "^28.0.0", "jest-environment-jsdom": "^28.0.0", + "jest-junit": "^16.0.0", "ts-jest": "^28.0.0", "typescript": "^4.9.5" } @@ -10330,6 +10332,33 @@ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, + "node_modules/jest-junit": { + "version": "16.0.0", + "resolved": "https://registry.npmjs.org/jest-junit/-/jest-junit-16.0.0.tgz", + "integrity": "sha512-A94mmw6NfJab4Fg/BlvVOUXzXgF0XIH6EmTgJ5NDPp4xoKq0Kr7sErb+4Xs9nZvu58pJojz5RFGpqnZYJTrRfQ==", + "dev": true, + "dependencies": { + "mkdirp": "^1.0.4", + "strip-ansi": "^6.0.1", + "uuid": "^8.3.2", + "xml": "^1.0.1" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/jest-junit/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/jest-leak-detector": { "version": "28.1.3", "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-28.1.3.tgz", @@ -15749,6 +15778,19 @@ "node": ">=10" } }, + "node_modules/react-super-responsive-table": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/react-super-responsive-table/-/react-super-responsive-table-5.2.2.tgz", + "integrity": "sha512-LDsGq8X3TBn0AMv5gX/0wFeWoFMMmiZXNTD1kIMMWz3WflPMHUZOSHXXlG5EOO2u3WSNcVl7MLIk83maS/Xj0g==", + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "prop-types": ">= 15", + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, "node_modules/read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", @@ -18569,6 +18611,12 @@ } } }, + "node_modules/xml": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/xml/-/xml-1.0.1.tgz", + "integrity": "sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw==", + "dev": true + }, "node_modules/xml-name-validator": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", @@ -26044,6 +26092,26 @@ } } }, + "jest-junit": { + "version": "16.0.0", + "resolved": "https://registry.npmjs.org/jest-junit/-/jest-junit-16.0.0.tgz", + "integrity": "sha512-A94mmw6NfJab4Fg/BlvVOUXzXgF0XIH6EmTgJ5NDPp4xoKq0Kr7sErb+4Xs9nZvu58pJojz5RFGpqnZYJTrRfQ==", + "dev": true, + "requires": { + "mkdirp": "^1.0.4", + "strip-ansi": "^6.0.1", + "uuid": "^8.3.2", + "xml": "^1.0.1" + }, + "dependencies": { + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true + } + } + }, "jest-leak-detector": { "version": "28.1.3", "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-28.1.3.tgz", @@ -29825,6 +29893,12 @@ } } }, + "react-super-responsive-table": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/react-super-responsive-table/-/react-super-responsive-table-5.2.2.tgz", + "integrity": "sha512-LDsGq8X3TBn0AMv5gX/0wFeWoFMMmiZXNTD1kIMMWz3WflPMHUZOSHXXlG5EOO2u3WSNcVl7MLIk83maS/Xj0g==", + "requires": {} + }, "read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", @@ -31929,6 +32003,12 @@ "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", "requires": {} }, + "xml": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/xml/-/xml-1.0.1.tgz", + "integrity": "sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw==", + "dev": true + }, "xml-name-validator": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", diff --git a/screen-domain/package.json b/screen-domain/package.json index 3e9b487..b716302 100644 --- a/screen-domain/package.json +++ b/screen-domain/package.json @@ -10,12 +10,13 @@ "react-router": "^6.10.0", "react-router-dom": "^6.10.0", "react-scripts": "5.0.1", + "react-super-responsive-table": "^5.2.2", "web-vitals": "^2.1.4" }, "scripts": { "start": "react-scripts start", "build": "react-scripts build", - "test": "jest --coverage --collectCoverageFrom=\"./src/**\"", + "test": "jest --coverage --collectCoverageFrom=\"./src/**\" --reporters=jest-junit", "test:integration": "jest integration", "eject": "react-scripts eject", "docker:build": "docker build -t client-users .", @@ -49,6 +50,7 @@ "@types/react-dom": "^18.0.11", "jest": "^28.0.0", "jest-environment-jsdom": "^28.0.0", + "jest-junit": "^16.0.0", "ts-jest": "^28.0.0", "typescript": "^4.9.5" } diff --git a/screen-domain/src/Api.ts b/screen-domain/src/Api.ts index 1454d22..c8dde03 100644 --- a/screen-domain/src/Api.ts +++ b/screen-domain/src/Api.ts @@ -29,8 +29,9 @@ export const ping = () => { return instance.get("health"); }; -export const fetchZones = (origin: string | undefined, lastUpdate: string | null): Promise => { +export const fetchZones = (origin: string | undefined, destination: string | undefined, lastUpdate: string | null): Promise => { return instance.get("flights" + (origin ? "?origin=" + origin : "") + + (destination ? "?destination=" + destination : "") + (lastUpdate ? ( origin ? "&lastUpdated=" : "?lastUpdated=") + lastUpdate : "")) }; diff --git a/screen-domain/src/App.tsx b/screen-domain/src/App.tsx index 81fbb31..fc655f8 100644 --- a/screen-domain/src/App.tsx +++ b/screen-domain/src/App.tsx @@ -1,19 +1,22 @@ import React, { useEffect } from "react"; import { useIsConnected } from "./hooks/useIsConnected"; import { Route, Routes } from "react-router"; +import { Departure } from "./components/Home/Departure"; +import { Arrival } from "./components/Home/Arrival"; import { Home } from "./components/Home/Home"; import { Button } from "antd"; import { initDB } from "./db"; function App() { const connection = useIsConnected(); - initDB(); + // initDB(); return (
- } /> - } /> + } /> + } /> + } />
{connection}
diff --git a/screen-domain/src/components/Home/Arrival.tsx b/screen-domain/src/components/Home/Arrival.tsx new file mode 100644 index 0000000..ff7ee43 --- /dev/null +++ b/screen-domain/src/components/Home/Arrival.tsx @@ -0,0 +1,98 @@ +import React, { useEffect, useState } from "react"; +import { Card } from "./Card/Card"; +import { Flight } from "../../Types"; +import './Home.css' +import { Table, Thead, Tbody, Tr, Th, Td } from 'react-super-responsive-table'; +import 'react-super-responsive-table/dist/SuperResponsiveTableStyle.css'; +import { useFetchDestination } from "../../hooks/useFetchDestination"; + +interface Props { + flights?: Flight[]; +} + +export const Arrival: React.FC = (props) => { + // let origin = process.env.REACT_APP_ORIGIN; + let destination = process.env.REACT_APP_ORIGIN; + + const { zones, error } = useFetchDestination(destination); + const [startIndex, setStartIndex] = useState(0); + + useEffect(() => { + const interval = setInterval(() => { + if (zones.length <= 10) { + return; + } + // setStartIndex((prevIndex) => (prevIndex + 10) % zones.length); + setStartIndex((prevIndex) => (prevIndex + 10) >= zones.length ? 0 : (prevIndex + 10)); + }, 5000); + + return () => clearInterval(interval); + }, [zones]); + + + return ( +
+

Arrival

+
+ {/* {(props.flights ? props.flights : zones).map((u) => { + return ; + })} */} + {/* + + + + + + + + + + + + */} +
Flight codeDepartureDeparture timeDestinationArrival timeGateStatus
+ + + + {/* */} + {/* */} + {/* */} + + + + + + + + {zones.length > 0 && ( + <> + {zones.slice(startIndex, startIndex + 10).map((flight) => ( + // {/* {Array.from({ length: zones.length < 10 ? zones.length : 10 }).map((_, index) => { + // const flightIndex = (startIndex + index) % zones.length; + // const flight = zones[flightIndex]; + + // return ( */} + + {/* */} + + + {/* */} + {/* */} + + + + + // ); + ))} + {/* })} */} + + )} + +
CodeDepartureTimeDestinationOriginTimeGateStatus
{flight.id}{flight.id}-{flight.flight_code}{flight.origin}{flight.departure_time}{flight.destination}{flight.arrival_time}{flight.gate}{flight.status}
+ {/* + */} + {error ?
{error}
: <>} +
+
+ ); +}; diff --git a/screen-domain/src/components/Home/Departure.tsx b/screen-domain/src/components/Home/Departure.tsx new file mode 100644 index 0000000..2758fbc --- /dev/null +++ b/screen-domain/src/components/Home/Departure.tsx @@ -0,0 +1,113 @@ +import React, { useEffect, useState } from "react"; +import { Card } from "./Card/Card"; +import { useFetchOrigin } from "../../hooks/useFetchOrigin"; +import { Flight } from "../../Types"; +import './Home.css' +import { Table, Thead, Tbody, Tr, Th, Td } from 'react-super-responsive-table'; +import 'react-super-responsive-table/dist/SuperResponsiveTableStyle.css'; + +interface Props { + flights?: Flight[]; +} + +export const Departure: React.FC = (props) => { + let origin = process.env.REACT_APP_ORIGIN; + // let destination = process.env.REACT_APP_ORIGIN; + + const { zones, error } = useFetchOrigin(origin); + const [startIndex, setStartIndex] = useState(0); + + useEffect(() => { + const interval = setInterval(() => { + if (zones.length <= 10) { + return; + } + // setStartIndex((prevIndex) => (prevIndex + 10) % zones.length); + setStartIndex((prevIndex) => (prevIndex + 10) >= zones.length ? 0 : (prevIndex + 10)); + }, 5000); + + return () => clearInterval(interval); + }, [zones]); + + + return ( +
+

Departure

+
+ {/* {(props.flights ? props.flights : zones).map((u) => { + return ; + })} */} + {/* + + + + + + + + + + + + */} +
Flight codeDepartureDeparture timeDestinationArrival timeGateStatus
+ + + + {/* */} + + + {/* */} + + + + + + {zones.length > 0 && ( + <> + {zones.slice(startIndex, startIndex + 10).map((flight) => ( + // {/* {Array.from({ length: zones.length < 10 ? zones.length : 10 }).map((_, index) => { + // const flightIndex = (startIndex + index) % zones.length; + // const flight = zones[flightIndex]; + + // return ( */} + + {/* */} + + {/* */} + + + {/* */} + + + + // ); + ))} + {startIndex + 10 >= zones.length && ( + <> + {Array.from({ length: startIndex + 10 - zones.length }).map((_, index) => { + return ( + + + + + + + + ) + }) } + + ) + } + {/* })} */} + + )} + +
CodeDepartureTimeDestinationArrival timeGateStatus
{flight.id}{flight.id}-{flight.flight_code}{flight.origin}{flight.departure_time}{flight.destination}{flight.arrival_time}{flight.gate}{flight.status}
+ {/* + */} + {error ?
{error}
: <>} +
+
+ ); +}; diff --git a/screen-domain/src/components/Home/Home.css b/screen-domain/src/components/Home/Home.css new file mode 100644 index 0000000..4a1f5ac --- /dev/null +++ b/screen-domain/src/components/Home/Home.css @@ -0,0 +1,42 @@ +body { +font-family: 'Arial', sans-serif; +background-color: #f0f0f0; +} + +.App { +text-align: center; +margin-top: 20px; +} + +table { +width: 80%; +margin: 20px auto; +border-collapse: collapse; +box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); +background-color: #fff; +} + +th, td { +border: 1px solid #ddd; +padding: 10px; +text-align: left; +} + +th { +background-color: #4CAF50; +color: #fff; +} + +tbody tr:hover { +background-color: #f5f5f5; +} + +tfoot { +background-color: #4CAF50; +color: #fff; +} + +.delayed-flight { +background-color: #ffcccc; /* Light red for delayed flights */ +color: #ff0000; /* Red text for delayed flights */ +} \ No newline at end of file diff --git a/screen-domain/src/components/Home/Home.test.tsx b/screen-domain/src/components/Home/Home.test.tsx index b0940c0..773ca5b 100644 --- a/screen-domain/src/components/Home/Home.test.tsx +++ b/screen-domain/src/components/Home/Home.test.tsx @@ -8,7 +8,7 @@ jest.mock("react-router-dom", () => ({ import "../../matchMedia.mock"; import "@testing-library/jest-dom"; import { render, screen } from "@testing-library/react"; -import { Home } from "./Home"; +// import { Home } from "./Departure"; describe("Home View Test", () => { test("Display initial, name and icon", async () => { diff --git a/screen-domain/src/components/Home/Home.tsx b/screen-domain/src/components/Home/Home.tsx index 4469ef3..6aa5de2 100644 --- a/screen-domain/src/components/Home/Home.tsx +++ b/screen-domain/src/components/Home/Home.tsx @@ -1,27 +1,24 @@ import React from "react"; -import { Card } from "./Card/Card"; -import { useFetchZones } from "../../hooks/useFetchZones"; import { Flight } from "../../Types"; +import './Home.css' +import { useNavigate } from "react-router"; +import './Page.css' interface Props { flights?: Flight[]; } export const Home: React.FC = (props) => { - // const urlParams = new URLSearchParams(window.location.search); - // const origin = urlParams.get('origin'); - // const { zones, error } = useFetchZones(origin); - const { zones, error } = useFetchZones(); + const navigate = useNavigate(); + + const submitHandler = (path: string) => { + navigate(path); + }; return ( -
-

Flights

-
- {(props.flights ? props.flights : zones).map((u) => { - return ; - })} - {error ?
{error}
: <>} -
+
+ +
); }; diff --git a/screen-domain/src/components/Home/Page.css b/screen-domain/src/components/Home/Page.css new file mode 100644 index 0000000..e80cde8 --- /dev/null +++ b/screen-domain/src/components/Home/Page.css @@ -0,0 +1,33 @@ +body { + font-family: 'Arial', sans-serif; + background-color: #f0f0f0; + margin: 0; + padding: 0; + display: flex; + justify-content: center; + align-items: center; + height: 100vh; + } + + div { + text-align: center; + } + + button { + background-color: #4CAF50; /* Green */ + border: none; + color: white; + padding: 15px 32px; + text-align: center; + text-decoration: none; + display: inline-block; + font-size: 16px; + margin: 10px; + cursor: pointer; + border-radius: 5px; + transition: background-color 0.3s ease; + } + + button:hover { + background-color: #45a049; /* Darker green on hover */ + } \ No newline at end of file diff --git a/screen-domain/src/db.ts b/screen-domain/src/db.ts index 9a63554..ee32080 100644 --- a/screen-domain/src/db.ts +++ b/screen-domain/src/db.ts @@ -3,7 +3,8 @@ let db: IDBDatabase; let version = 1; export enum Stores { - Flight = 'flights', + Departure = 'departure', + Arrival = 'arrival' } interface EventTarget { @@ -18,8 +19,11 @@ export const initDB = (): Promise => { let req = (e.target as IDBOpenDBRequest) db = req.result; - if (!db.objectStoreNames.contains(Stores.Flight)) { - db.createObjectStore(Stores.Flight, { keyPath: 'id' }); + if (!db.objectStoreNames.contains(Stores.Arrival)) { + db.createObjectStore(Stores.Arrival, { keyPath: 'id' }); + } + if (!db.objectStoreNames.contains(Stores.Departure)) { + db.createObjectStore(Stores.Departure, { keyPath: 'id' }); } }; @@ -38,55 +42,58 @@ export const initDB = (): Promise => { export const addData = (storeName: string, data: T): Promise => { return new Promise((resolve) => { - request = indexedDB.open('myDB', version); + // request = indexedDB.open('myDB', version); - request.onsuccess = (e) => { - let req = (e.target as IDBOpenDBRequest) - db = req.result; + // request.onsuccess = (e) => { + // let req = (e.target as IDBOpenDBRequest) + // db = req.result; const tx = db.transaction(storeName, 'readwrite'); const store = tx.objectStore(storeName); store.add(data); resolve(data); - }; + // }; - request.onerror = () => { - const error = request.error?.message - if (error) { - resolve(error); - } else { - resolve('Unknown error'); - } - }; + // request.onerror = () => { + // const error = request.error?.message + // if (error) { + // resolve(error); + // } else { + // resolve('Unknown error'); + // } + // }; }); }; export const deleteData = (storeName: string, key: number): Promise => { return new Promise((resolve) => { - request = indexedDB.open('myDB', version); + // request = indexedDB.open('myDB', version); - request.onsuccess = (e) => { - let req = (e.target as IDBOpenDBRequest) - db = req.result; + // request.onsuccess = (e) => { + // let req = (e.target as IDBOpenDBRequest) + // db = req.result; const tx = db.transaction(storeName, 'readwrite'); const store = tx.objectStore(storeName); const res = store.delete(key); + console.log("removing" + key) res.onsuccess = () => { + console.log("success") resolve(true); }; res.onerror = () => { + console.log("error") resolve(false); } - }; + // }; }); }; export const updateData = (storeName: string, key: number, data: T): Promise => { return new Promise((resolve) => { - request = indexedDB.open('myDB', version); + // request = indexedDB.open('myDB', version); - request.onsuccess = (e) => { - let req = (e.target as IDBOpenDBRequest) - db = req.result; + // request.onsuccess = (e) => { + // let req = (e.target as IDBOpenDBRequest) + // db = req.result; const tx = db.transaction(storeName, 'readwrite'); const store = tx.objectStore(storeName); const res = store.get(key); @@ -98,27 +105,27 @@ export const updateData = (storeName: string, key: number, data: T): Promise< res.onerror = () => { resolve(null); } - }; + // }; }); }; export const getStoreData = (storeName: Stores): Promise => { return new Promise((resolve) => { - request = indexedDB.open('myDB'); + // request = indexedDB.open('myDB'); - request.onsuccess = (e) => { - let req = (e.target as IDBOpenDBRequest) - if (!req.result) { - resolve(null); - } - db = req.result; + // request.onsuccess = (e) => { + // let req = (e.target as IDBOpenDBRequest) + // if (!req.result) { + // resolve(null); + // } + // db = req.result; const tx = db.transaction(storeName, 'readonly'); const store = tx.objectStore(storeName); const res = store.getAll(); res.onsuccess = () => { resolve(res.result); }; - }; + // }; }); }; diff --git a/screen-domain/src/hooks/useFetchDestination.tsx b/screen-domain/src/hooks/useFetchDestination.tsx new file mode 100644 index 0000000..e352a7f --- /dev/null +++ b/screen-domain/src/hooks/useFetchDestination.tsx @@ -0,0 +1,142 @@ +import React, { useEffect } from "react"; +import { useState } from "react"; +import { User, Flight } from "../Types"; +import { fetchZones } from "../Api"; +import { Stores, addData, deleteData, getStoreData, updateData, initDB } from '../db'; + +export const useFetchDestination = (destination: string | undefined) => { + const [error, setError] = useState(null); + const [zones, setZones] = useState([]); + // const [today, setToday] = useState(new Date()); + + const isToday = (someDate: Date) => { + let today = new Date(); + return someDate.getDate() == today.getDate() && + someDate.getMonth() == today.getMonth() && + someDate.getFullYear() == today.getFullYear() + } + + useEffect(() => { + const intervalId = setInterval(() => { + // {isToday(new Date(flight.departure_time)) ? 's' : 'n'} + let today = localStorage.getItem('date') + + if (today && !isToday(new Date(today))) { + getStoreData(Stores.Arrival) + .then((data) => { + if (data) { + data.map((u) => { + deleteData(Stores.Arrival, u.id) + }) + } + }) + localStorage.setItem('date', new Date().toString()) + } + + }, 36000) + + return () => clearInterval(intervalId); + }, []) + + + useEffect(() => { + setError(null); + let newUpdate = new Date().toISOString() + + localStorage.setItem('date', new Date().toString()) + + initDB().then((x) => { + console.log(x) + getStoreData(Stores.Arrival) + .then((data) => { + console.log(data) + if (data && data.length > 0) { + data.sort((a,b) => new Date(a.departure_time).getTime() - new Date(b.departure_time).getTime()) + setZones(data) + } else { + fetchZones(undefined, destination, null) + .then((data) => { + localStorage.setItem('lastUpdated', newUpdate) + let toAdd: Flight[] = [] + data.map((u) => { + if (u.status != 'Deleted') { + addData(Stores.Arrival, u) + toAdd.push(u) + } + }) + // toAdd.sort((a,b) => new Date(a.departure_time).getTime() - new Date(b.departure_time).getTime()) + toAdd.sort((a,b) => new Date(a.departure_time).getTime() - new Date(b.departure_time).getTime()) + setZones(toAdd); + }) + .catch((error) => {}); + } + }) + } + ) + + }, [origin]); + + useEffect(() => { + const intervalId = setInterval(() => { + let lastUpdate = localStorage.getItem('lastUpdated') + let newUpdate = new Date().toISOString() + // let newUpdate = new Date().toTimeString() + + fetchZones(undefined, destination, lastUpdate) + .then((data) => { + localStorage.setItem('lastUpdated', newUpdate) + let toAdd: Flight[] = [] + let toRemove: Flight[] = [] + + zones.forEach((c, i) => { + let index = data.findIndex(x => x.id === c.id) + if (index >= 0) { + console.log(data[index].departure_time + 'nuevo') + if (data[index].status == 'Deleted' || new Date(data[index].departure_time) < new Date()) { + console.log("sacamos") + toRemove.push(data[index]) + deleteData(Stores.Arrival, c.id) + } else { + toAdd.push(data[index]); + updateData(Stores.Arrival, c.id, data[index]) + } + } else { + console.log(new Date(c.departure_time)) + if (c.status == 'Deleted' || new Date(c.departure_time) < new Date()) { + console.log("sacamos?") + toRemove.push(c); + deleteData(Stores.Arrival, c.id) + } else { + toAdd.push(c); + } + } + }); + + // console.log(toAdd) + // console.log(toRemove) + let filtered = data.filter(o => + !toAdd.some(b => { return o.id === b.id}) && !toRemove.some(b => { return o.id === b.id}) && !(new Date(o.departure_time) < new Date()) + ) + const newArray = toAdd.concat(filtered); + console.log(filtered) + console.log(newArray) + filtered.forEach(c => { + addData(Stores.Arrival, c) + }) + + // newArray.sort((a,b) => new Date(a.departure_time).getTime() - new Date(b.departure_time).getTime()) + newArray.sort((a,b) => new Date(a.departure_time).getTime() - new Date(b.departure_time).getTime()) + setZones(newArray); + }) + .catch((error) => { + if (!!error.isAxiosError && !error.response) { + // + } + }); + }, 5000) + + return () => clearInterval(intervalId); + }, [origin, zones]) + + return { zones, error }; +}; diff --git a/screen-domain/src/hooks/useFetchOrigin.tsx b/screen-domain/src/hooks/useFetchOrigin.tsx new file mode 100644 index 0000000..86e3248 --- /dev/null +++ b/screen-domain/src/hooks/useFetchOrigin.tsx @@ -0,0 +1,142 @@ +import React, { useEffect } from "react"; +import { useState } from "react"; +import { User, Flight } from "../Types"; +import { fetchZones } from "../Api"; +import { Stores, addData, deleteData, getStoreData, updateData, initDB } from '../db'; + +export const useFetchOrigin = (origin: string | undefined) => { + const [error, setError] = useState(null); + const [zones, setZones] = useState([]); + // const [today, setToday] = useState(new Date()); + + const isToday = (someDate: Date) => { + let today = new Date(); + return someDate.getDate() == today.getDate() && + someDate.getMonth() == today.getMonth() && + someDate.getFullYear() == today.getFullYear() + } + + useEffect(() => { + const intervalId = setInterval(() => { + // {isToday(new Date(flight.departure_time)) ? 's' : 'n'} + let today = localStorage.getItem('date') + + if (today && !isToday(new Date(today))) { + getStoreData(Stores.Departure) + .then((data) => { + if (data) { + data.map((u) => { + deleteData(Stores.Departure, u.id) + }) + } + }) + localStorage.setItem('date', new Date().toString()) + } + + }, 36000) + + return () => clearInterval(intervalId); + }, []) + + + useEffect(() => { + setError(null); + let newUpdate = new Date().toISOString() + + localStorage.setItem('date', new Date().toString()) + + initDB().then((x) => { + console.log(x) + getStoreData(Stores.Departure) + .then((data) => { + console.log(data) + if (data && data.length > 0) { + data.sort((a,b) => new Date(a.origin).getTime() - new Date(b.origin).getTime()) + setZones(data) + } else { + fetchZones(origin, undefined, null) + .then((data) => { + localStorage.setItem('lastUpdated', newUpdate) + let toAdd: Flight[] = [] + data.map((u) => { + if (u.status != 'Deleted') { + addData(Stores.Departure, u) + toAdd.push(u) + } + }) + // toAdd.sort((a,b) => new Date(a.departure_time).getTime() - new Date(b.departure_time).getTime()) + toAdd.sort((a,b) => new Date(a.origin).getTime() - new Date(b.origin).getTime()) + setZones(toAdd); + }) + .catch((error) => {}); + } + }) + } + ) + + }, [origin]); + + useEffect(() => { + const intervalId = setInterval(() => { + let lastUpdate = localStorage.getItem('lastUpdated') + let newUpdate = new Date().toISOString() + // let newUpdate = new Date().toTimeString() + + fetchZones(origin, undefined, lastUpdate) + .then((data) => { + localStorage.setItem('lastUpdated', newUpdate) + let toAdd: Flight[] = [] + let toRemove: Flight[] = [] + + zones.forEach((c, i) => { + let index = data.findIndex(x => x.id === c.id) + if (index >= 0) { + console.log(data[index].departure_time + 'nuevo') + if (data[index].status == 'Deleted' || new Date(data[index].departure_time) < new Date()) { + console.log("sacamos") + toRemove.push(data[index]) + deleteData(Stores.Departure, c.id) + } else { + toAdd.push(data[index]); + updateData(Stores.Departure, c.id, data[index]) + } + } else { + console.log(new Date(c.departure_time)) + if (c.status == 'Deleted' || new Date(c.departure_time) < new Date()) { + console.log("sacamos?") + toRemove.push(c); + deleteData(Stores.Departure, c.id) + } else { + toAdd.push(c); + } + } + }); + + // console.log(toAdd) + // console.log(toRemove) + let filtered = data.filter(o => + !toAdd.some(b => { return o.id === b.id}) && !toRemove.some(b => { return o.id === b.id}) && !(new Date(o.departure_time) < new Date()) + ) + const newArray = toAdd.concat(filtered); + console.log(filtered) + console.log(newArray) + filtered.forEach(c => { + addData(Stores.Departure, c) + }) + + // newArray.sort((a,b) => new Date(a.departure_time).getTime() - new Date(b.departure_time).getTime()) + newArray.sort((a,b) => new Date(a.origin).getTime() - new Date(b.origin).getTime()) + setZones(newArray); + }) + .catch((error) => { + if (!!error.isAxiosError && !error.response) { + // + } + }); + }, 5000) + + return () => clearInterval(intervalId); + }, [origin, zones]) + + return { zones, error }; +}; diff --git a/screen-domain/src/hooks/useFetchZones.tsx b/screen-domain/src/hooks/useFetchZones.tsx deleted file mode 100644 index 73cf036..0000000 --- a/screen-domain/src/hooks/useFetchZones.tsx +++ /dev/null @@ -1,90 +0,0 @@ -import React, { useEffect } from "react"; -import { useState } from "react"; -import { User, Flight } from "../Types"; -import { fetchZones } from "../Api"; -import { Stores, addData, deleteData, getStoreData, updateData, initDB } from '../db'; - -export const useFetchZones = () => { - const [error, setError] = useState(null); - const [zones, setZones] = useState([]); - - let origin = process.env.REACT_APP_ORIGIN; - - useEffect(() => { - setError(null); - let newUpdate = new Date().toISOString() - - getStoreData(Stores.Flight) - .then((data) => { - console.log(data) - if (data && data.length > 0) { - setZones(data) - } else { - fetchZones(origin, null) - .then((data) => { - localStorage.setItem('lastUpdated', newUpdate) - let toAdd: Flight[] = [] - data.map((u) => { - if (u.status != 'Deleted') { - addData(Stores.Flight, u) - toAdd.push(u) - } - }) - setZones(toAdd); - }) - .catch((error) => {}); - } - }) - - }, [origin]); - - useEffect(() => { - const intervalId = setInterval(() => { - let lastUpdate = localStorage.getItem('lastUpdated') - let newUpdate = new Date().toISOString() - - fetchZones(origin, lastUpdate) - .then((data) => { - localStorage.setItem('lastUpdated', newUpdate) - let toAdd: Flight[] = [] - let toRemove: Flight[] = [] - - zones.forEach((c, i) => { - let index = data.findIndex(x => x.id === c.id) - if (index >= 0) { - console.log(data[index].status) - if (data[index].status == 'Deleted') { - console.log("sacamos") - toRemove.push(data[index]) - deleteData(Stores.Flight, c.id) - } else { - toAdd.push(data[index]); - updateData(Stores.Flight, c.id, data[index]) - } - } else { - if (c.status == 'Deleted') { - toRemove.push(c); - } else { - toAdd.push(c); - } - } - }); - - console.log(toAdd) - console.log(toRemove) - let filtered = data.filter(o => !toAdd.some(b => { return o.id === b.id}) && !toRemove.some(b => { return o.id === b.id})) - const newArray = toAdd.concat(filtered); - filtered.forEach(c => { - addData(Stores.Flight, c) - }) - - setZones(newArray); - }) - .catch((error) => {}); - }, 5000) - - return () => clearInterval(intervalId); - }, [origin, zones]) - - return { zones, error }; -}; diff --git a/screen-domain/src/hooks/useIsConnected.tsx b/screen-domain/src/hooks/useIsConnected.tsx index 3ec39fc..d08d64a 100644 --- a/screen-domain/src/hooks/useIsConnected.tsx +++ b/screen-domain/src/hooks/useIsConnected.tsx @@ -3,17 +3,21 @@ import { useState } from "react"; import { ping } from "../Api"; export const useIsConnected = () => { - const [connected, setConnected] = useState(false); + const [connected, setConnected] = useState(true); - useEffect(() => { - ping() + useEffect(() => { + const interval = setInterval(() => { + ping() .then(() => { setConnected(true); }) .catch(() => { setConnected(false); }); - }, []); + }, 5000); + + return () => clearInterval(interval); + }, []); return (
diff --git a/screen-domain/test.sh b/screen-domain/test.sh index c20a79c..24ce9ab 100644 --- a/screen-domain/test.sh +++ b/screen-domain/test.sh @@ -1,8 +1,3 @@ #!/bin/bash -curl -X DELETE api:5000/ping -curl -X POST api:5000/ping - - -# npm test -echo "NPM TEST" +npm run test