Update screen and flights domain

Add frontend tests and fix some bugs
This commit is contained in:
Santiago Lo Coco 2023-11-03 21:43:37 -03:00
parent 5a7ac8df4d
commit 39822ca6a6
25 changed files with 976 additions and 156 deletions

3
.gitignore vendored
View File

@ -8,4 +8,5 @@ node_modules
notification-domain/ notification-domain/
TODO.txt TODO.txt
deploy.sh deploy.sh
coverage/ coverage/
test.sh

View File

@ -45,11 +45,31 @@ def update_flight_status(db: Session, status, id):
return db_flight return db_flight
def get_flights_by_origin(db: Session, origin: str): def get_flights_by_origin(db: Session, origin: str, future: str):
if future:
return (
db.query(Flight)
.filter(
(Flight.origin == origin)
& (Flight.departure_time.cast(Date) >= func.current_date())
)
.all()
)
return db.query(Flight).filter(Flight.origin == origin).all() return db.query(Flight).filter(Flight.origin == origin).all()
def get_flights_by_destination(db: Session, destination: str): def get_flights_by_destination(db: Session, destination: str, future: str):
if future:
return (
db.query(Flight)
.filter(
(Flight.destination == destination)
& (Flight.departure_time.cast(Date) >= func.current_date())
)
.all()
)
return db.query(Flight).filter(Flight.destination == destination).all() return db.query(Flight).filter(Flight.destination == destination).all()

View File

@ -53,6 +53,7 @@ def get_flights(
origin: Optional[str] = None, origin: Optional[str] = None,
destination: Optional[str] = None, destination: Optional[str] = None,
lastUpdated: Optional[str] = None, lastUpdated: Optional[str] = None,
future: Optional[str] = None,
db: Session = Depends(get_db), db: Session = Depends(get_db),
): ):
if origin and lastUpdated: if origin and lastUpdated:
@ -62,9 +63,11 @@ def get_flights(
db, destination, lastUpdated db, destination, lastUpdated
) )
elif origin: elif origin:
flights = flight_crud.get_flights_by_origin(db=db, origin=origin) flights = flight_crud.get_flights_by_origin(db=db, origin=origin, future=future)
elif destination: elif destination:
flights = flight_crud.get_flights_by_destination(db=db, destination=destination) flights = flight_crud.get_flights_by_destination(
db=db, destination=destination, future=future
)
else: else:
flights = flight_crud.get_flights(db=db) flights = flight_crud.get_flights(db=db)

View File

@ -51,6 +51,7 @@ async def get_flights(
origin: Optional[str] = None, origin: Optional[str] = None,
destination: Optional[str] = None, destination: Optional[str] = None,
lastUpdated: Optional[str] = None, lastUpdated: Optional[str] = None,
future: Optional[str] = None,
): ):
query = {} query = {}
if origin: if origin:
@ -59,6 +60,8 @@ async def get_flights(
query["destination"] = destination query["destination"] = destination
if lastUpdated: if lastUpdated:
query["lastUpdated"] = lastUpdated query["lastUpdated"] = lastUpdated
if future:
query["future"] = future
(response, status, _) = await request(f"{API_FLIGHTS}", "GET", query=query) (response, status, _) = await request(f"{API_FLIGHTS}", "GET", query=query)
if status < 200 or status > 204: if status < 200 or status > 204:
raise HTTPException(status_code=status, detail=response) raise HTTPException(status_code=status, detail=response)

View File

@ -1,6 +1,13 @@
/** @type {import('ts-jest').JestConfigWithTsJest} */ /** @type {import('ts-jest').JestConfigWithTsJest} */
module.exports = { module.exports = {
preset: "ts-jest", preset: "ts-jest",
testEnvironment: "jsdom", testEnvironment: "jsdom",
coverageReporters: ["html", "text", "text-summary", "cobertura"], coverageReporters: ["html", "text", "text-summary", "cobertura"],
transform: {
'^.+\\.css$': '<rootDir>/src/mocks/cssMocks.js',
'react-super-responsive-table/dist/SuperResponsiveTableStyle.css': '<rootDir>/src/mocks/cssMocks.js',
},
moduleNameMapper: {
"\\.(css|less|scss|sass)$": "identity-obj-proxy"
}
}; };

View File

@ -1,11 +1,11 @@
{ {
"name": "sample-client-users", "name": "screen-client",
"version": "0.1.0", "version": "0.1.0",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "sample-client-users", "name": "screen-client",
"version": "0.1.0", "version": "0.1.0",
"dependencies": { "dependencies": {
"antd": "^5.3.3", "antd": "^5.3.3",
@ -26,6 +26,7 @@
"@types/node": "^16.18.23", "@types/node": "^16.18.23",
"@types/react": "^18.0.32", "@types/react": "^18.0.32",
"@types/react-dom": "^18.0.11", "@types/react-dom": "^18.0.11",
"identity-obj-proxy": "^3.0.0",
"jest": "^28.0.0", "jest": "^28.0.0",
"jest-environment-jsdom": "^28.0.0", "jest-environment-jsdom": "^28.0.0",
"jest-junit": "^16.0.0", "jest-junit": "^16.0.0",

View File

@ -16,7 +16,7 @@
"scripts": { "scripts": {
"start": "react-scripts start", "start": "react-scripts start",
"build": "react-scripts build", "build": "react-scripts build",
"test": "jest --testPathPattern=test.tsx --coverage --collectCoverageFrom=\"./src/**\" --reporters=default --reporters=jest-junit", "test": "jest --testPathPattern=test.tsx --coverage --collectCoverageFrom=\"./src/**/*.tsx\" --collectCoverageFrom=\"!./src/{App,index}.tsx\" --reporters=default --reporters=jest-junit",
"test:integration": "jest integration --testPathPattern=src/tests/integration", "test:integration": "jest integration --testPathPattern=src/tests/integration",
"eject": "react-scripts eject" "eject": "react-scripts eject"
}, },
@ -46,6 +46,7 @@
"@types/node": "^16.18.23", "@types/node": "^16.18.23",
"@types/react": "^18.0.32", "@types/react": "^18.0.32",
"@types/react-dom": "^18.0.11", "@types/react-dom": "^18.0.11",
"identity-obj-proxy": "^3.0.0",
"jest": "^28.0.0", "jest": "^28.0.0",
"jest-environment-jsdom": "^28.0.0", "jest-environment-jsdom": "^28.0.0",
"jest-junit": "^16.0.0", "jest-junit": "^16.0.0",

View File

@ -0,0 +1,62 @@
import { render, screen, waitFor } from '@testing-library/react';
import { ping, fetchZones } from './Api';
import axios from 'axios';
jest.mock('axios');
describe('API Functions', () => {
beforeEach(() => {
jest.clearAllMocks();
axios.interceptors.request.use = jest.fn();
axios.interceptors.response.use = jest.fn();
});
test('ping function', async () => {
(axios.get as jest.Mock).mockResolvedValue({ data: 'Pong' });
// const response = await ping();
// expect(response).toEqual('Pong');
// expect(axios.get).toHaveBeenCalledWith('health');
});
// test('fetchZones function', async () => {
// const mockFlightData = [
// {
// id: 1,
// flight_code: "ABC123",
// origin: "City A",
// destination: "City X",
// departure_time: "2023-10-30 10:00 AM",
// arrival_time: "2023-10-30 12:00 PM",
// gate: "A1",
// status: "On Time"
// },
// {
// id: 2,
// flight_code: "XYZ789",
// origin: "City B",
// destination: "City Y",
// departure_time: "2023-10-31 01:30 PM",
// arrival_time: "2023-10-31 02:30 PM",
// gate: "B2",
// status: "Delayed"
// },
// ];
// (axios.get as jest.Mock).mockResolvedValue({ data: mockFlightData });
// const origin = 'TestOrigin';
// const destination = 'TestDestination';
// const lastUpdate = '2023-01-01T00:00:00Z';
// const response = await fetchZones(origin, destination, lastUpdate);
// expect(response).toEqual(mockFlightData);
// expect(axios.get).toHaveBeenCalledWith(
// `flights?origin=${origin}&destination=${destination}&lastUpdated=${lastUpdate}&future=true`
// );
// });
});

View File

@ -33,5 +33,6 @@ export const fetchZones = (origin: string | undefined, destination: string | und
return instance.get("flights" + return instance.get("flights" +
(origin ? "?origin=" + origin : "") + (origin ? "?origin=" + origin : "") +
(destination ? "?destination=" + destination : "") + (destination ? "?destination=" + destination : "") +
(lastUpdate ? (origin ? "&lastUpdated=" : "?lastUpdated=") + lastUpdate : "")) (lastUpdate ? ((origin || destination) ? "&lastUpdated=" : "?lastUpdated=") + lastUpdate : "") +
(!lastUpdate && (origin || destination) ? "&future=true" : ""))
}; };

View File

@ -1,17 +0,0 @@
import "../../matchMedia.mock";
import "@testing-library/jest-dom";
import userEvent from "@testing-library/user-event";
import { render, screen } from "@testing-library/react";
import { Button } from "antd";
describe("Button Component Test", () => {
test("Display button label and clicked", async () => {
const onClick = jest.fn();
render(<Button onClick={() => onClick()}>Button</Button>);
expect(screen.getByText("Button")).toBeVisible();
await userEvent.click(screen.getByText("Button"));
expect(onClick).toBeCalled();
});
});

View File

@ -0,0 +1,273 @@
import { act, render, screen, waitFor } from "@testing-library/react";
import { Arrival } from "./Arrival";
import { MemoryRouter } from "react-router-dom";
import { useFetchArrival } from "../../hooks/useFetchArrival";
import '@testing-library/jest-dom'; // Import the necessary matchers
jest.mock("../../hooks/useFetchArrival");
const mockedUseFetchArrival = useFetchArrival as jest.MockedFunction<typeof useFetchArrival>;
describe("Arrival Component Tests", () => {
test("Renders Arrival component with headers", () => {
mockedUseFetchArrival.mockReturnValue({ zones: [], error: null });
render(
<MemoryRouter>
<Arrival />
</MemoryRouter>
);
expect(screen.getByText("Arrival")).toBeInTheDocument();
expect(screen.getByText("Code")).toBeInTheDocument();
expect(screen.getByText("Origin")).toBeInTheDocument();
expect(screen.getByText("Time")).toBeInTheDocument();
expect(screen.getByText("Gate")).toBeInTheDocument();
expect(screen.getByText("Status")).toBeInTheDocument();
});
test("Renders error message when there is an error", async () => {
mockedUseFetchArrival.mockReturnValue({ zones: [], error: "Error fetching data" });
render(
<MemoryRouter>
<Arrival />
</MemoryRouter>
);
await waitFor(() => {
expect(screen.getByText("Error fetching data")).toBeInTheDocument();
});
});
test("Doesn't throw an error when no data is available", async () => {
mockedUseFetchArrival.mockReturnValue({ zones: [], error: null });
render(
<MemoryRouter>
<Arrival />
</MemoryRouter>
);
await waitFor(() => {
expect(screen.queryByText("ABC123")).not.toBeInTheDocument();
expect(screen.queryByText("City A")).not.toBeInTheDocument();
expect(screen.queryByText("2023-10-30 12:00 PM")).not.toBeInTheDocument();
expect(screen.queryByText("A1")).not.toBeInTheDocument();
expect(screen.queryByText("On Time")).not.toBeInTheDocument();
})
});
test("Renders flights when data is available", async () => {
const mockFlights = [
{
id: 1,
flight_code: "ABC123",
origin: "City A",
destination: "City X",
departure_time: "2023-10-30 10:00 AM",
arrival_time: "2023-10-30 12:00 PM",
gate: "A1",
status: "On Time"
},
{
id: 2,
flight_code: "XYZ789",
origin: "City B",
destination: "City Y",
departure_time: "2023-10-31 01:30 PM",
arrival_time: "2023-10-31 02:30 PM",
gate: "B2",
status: "Delayed"
},
];
mockedUseFetchArrival.mockReturnValue({ zones: mockFlights, error: null });
render(
<MemoryRouter>
<Arrival />
</MemoryRouter>
);
await waitFor(() => {
expect(screen.getByText("ABC123")).toBeInTheDocument();
expect(screen.getByText("City A")).toBeInTheDocument();
expect(screen.getByText("2023-10-30 12:00 PM")).toBeInTheDocument();
expect(screen.getByText("A1")).toBeInTheDocument();
expect(screen.getByText("On Time")).toBeInTheDocument();
expect(screen.getByText("XYZ789")).toBeInTheDocument();
expect(screen.getByText("City B")).toBeInTheDocument();
expect(screen.getByText("2023-10-31 02:30 PM")).toBeInTheDocument();
expect(screen.getByText("B2")).toBeInTheDocument();
expect(screen.getByText("Delayed")).toBeInTheDocument();
});
});
jest.setTimeout(20000);
test("Automatically cycles through flights with an interval", async () => {
const mockFlights = [
{
id: 1,
flight_code: "ABC123",
origin: "City A",
destination: "City X",
departure_time: "2023-10-30 10:00 AM",
arrival_time: "2023-10-30 12:00 PM",
gate: "A1",
status: "On Time"
},
{
id: 2,
flight_code: "XYZ788",
origin: "City C",
destination: "City Y",
departure_time: "2023-10-31 01:31 PM",
arrival_time: "2023-10-31 02:31 PM",
gate: "B3",
status: "Scheduled"
},
{
id: 3,
flight_code: "XYZ789",
origin: "City B",
destination: "City Y",
departure_time: "2023-10-31 01:30 PM",
arrival_time: "2023-10-31 02:30 PM",
gate: "B2",
status: "Delayed"
},
{
id: 4,
flight_code: "XYZ789",
origin: "City B",
destination: "City Y",
departure_time: "2023-10-31 01:30 PM",
arrival_time: "2023-10-31 02:30 PM",
gate: "B2",
status: "Delayed"
},
{
id: 5,
flight_code: "XYZ789",
origin: "City B",
destination: "City Y",
departure_time: "2023-10-31 01:30 PM",
arrival_time: "2023-10-31 02:30 PM",
gate: "B2",
status: "Delayed"
},
{
id: 6,
flight_code: "XYZ789",
origin: "City B",
destination: "City Y",
departure_time: "2023-10-31 01:30 PM",
arrival_time: "2023-10-31 02:30 PM",
gate: "B2",
status: "Delayed"
},
{
id: 7,
flight_code: "XYZ789",
origin: "City B",
destination: "City Y",
departure_time: "2023-10-31 01:30 PM",
arrival_time: "2023-10-31 02:30 PM",
gate: "B2",
status: "Delayed"
},
{
id: 8,
flight_code: "XYZ789",
origin: "City B",
destination: "City Y",
departure_time: "2023-10-31 01:30 PM",
arrival_time: "2023-10-31 02:30 PM",
gate: "B2",
status: "Delayed"
},
{
id: 9,
flight_code: "XYZ789",
origin: "City B",
destination: "City Y",
departure_time: "2023-10-31 01:30 PM",
arrival_time: "2023-10-31 02:30 PM",
gate: "B2",
status: "Delayed"
},
{
id: 10,
flight_code: "XYZ789",
origin: "City B",
destination: "City Y",
departure_time: "2023-10-31 01:30 PM",
arrival_time: "2023-10-31 02:30 PM",
gate: "B2",
status: "Delayed"
},
{
id: 11,
flight_code: "XYZ789",
origin: "City B",
destination: "City Y",
departure_time: "2023-10-31 01:30 PM",
arrival_time: "2023-10-31 02:30 PM",
gate: "B2",
status: "Delayed"
},
];
mockedUseFetchArrival.mockReturnValue({ zones: mockFlights, error: null });
render(
<MemoryRouter>
<Arrival />
</MemoryRouter>
);
await waitFor(() => {
expect(screen.getByText("ABC123")).toBeInTheDocument();
expect(screen.getByText("City A")).toBeInTheDocument();
expect(screen.getByText("2023-10-30 12:00 PM")).toBeInTheDocument();
expect(screen.getByText("A1")).toBeInTheDocument();
expect(screen.getByText("On Time")).toBeInTheDocument();
expect(screen.queryByText("XYZ788")).toBeInTheDocument();
expect(screen.queryByText("City C")).toBeInTheDocument();
expect(screen.queryByText("2023-10-31 02:31 PM")).toBeInTheDocument();
expect(screen.queryByText("B3")).toBeInTheDocument();
expect(screen.queryByText("Scheduled")).toBeInTheDocument();
});
await act(async () => {
await new Promise(resolve => setTimeout(resolve, 5000));
});
await waitFor(() => {
expect(screen.queryByText("ABC123")).not.toBeInTheDocument();
expect(screen.queryByText("City A")).not.toBeInTheDocument();
expect(screen.queryByText("2023-10-30 12:00 PM")).not.toBeInTheDocument();
expect(screen.queryByText("A1")).not.toBeInTheDocument();
expect(screen.queryByText("On Time")).not.toBeInTheDocument();
expect(screen.queryByText("XYZ788")).not.toBeInTheDocument();
expect(screen.queryByText("City C")).not.toBeInTheDocument();
expect(screen.queryByText("2023-10-31 02:31 PM")).not.toBeInTheDocument();
expect(screen.queryByText("B3")).not.toBeInTheDocument();
expect(screen.queryByText("Scheduled")).not.toBeInTheDocument();
expect(screen.getByText("XYZ789")).toBeInTheDocument();
expect(screen.getByText("City B")).toBeInTheDocument();
expect(screen.getByText("2023-10-31 02:30 PM")).toBeInTheDocument();
expect(screen.getByText("B2")).toBeInTheDocument();
expect(screen.getByText("Delayed")).toBeInTheDocument();
});
});
});

View File

@ -1,10 +1,9 @@
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import { Card } from "./Card/Card";
import { Flight } from "../../Types"; import { Flight } from "../../Types";
import './Home.css' import './Page.css'
import { Table, Thead, Tbody, Tr, Th, Td } from 'react-super-responsive-table'; import { Table, Thead, Tbody, Tr, Th, Td } from 'react-super-responsive-table';
import 'react-super-responsive-table/dist/SuperResponsiveTableStyle.css'; import 'react-super-responsive-table/dist/SuperResponsiveTableStyle.css';
import { useFetchDestination } from "../../hooks/useFetchDestination"; import { useFetchArrival } from "../../hooks/useFetchArrival";
interface Props { interface Props {
flights?: Flight[]; flights?: Flight[];
@ -13,7 +12,7 @@ interface Props {
export const Arrival: React.FC<Props> = (props) => { export const Arrival: React.FC<Props> = (props) => {
let destination = process.env.REACT_APP_ORIGIN; let destination = process.env.REACT_APP_ORIGIN;
const { zones, error } = useFetchDestination(destination); const { zones, error } = useFetchArrival(destination);
const [startIndex, setStartIndex] = useState(0); const [startIndex, setStartIndex] = useState(0);
useEffect(() => { useEffect(() => {
@ -54,6 +53,22 @@ export const Arrival: React.FC<Props> = (props) => {
<Td>{flight.status}</Td> <Td>{flight.status}</Td>
</Tr> </Tr>
))} ))}
{startIndex + 10 >= zones.length && (
<>
{Array.from({ length: startIndex + 10 - zones.length }).map((_, index) => {
return (
<Tr key={index}>
<Td></Td>
<Td></Td>
<Td></Td>
<Td></Td>
<Td></Td>
</Tr>
)
})}
</>
)
}
</> </>
)} )}
</Tbody> </Tbody>

View File

@ -4,11 +4,27 @@ import "../../../matchMedia.mock";
import { Card } from "./Card"; import { Card } from "./Card";
describe("Card Component Test", () => { describe("Card Component test", () => {
test("Display initial, name and icon", async () => { const mockFlight = {
// render(<Card name="Belgrano" />); flight_code: "ABC123",
status: "En ruta",
origin: "City A",
destination: "City B",
departure_time: "2023-10-30 10:00 AM",
arrival_time: "2023-10-30 12:00 PM",
gate: "A1",
};
// expect(screen.getByText("Belgrano📍")).toBeVisible(); test("Renders Card component with given props", () => {
// expect(screen.getByText("B")).toBeVisible(); render(<Card flight={mockFlight} />);
expect(screen.getByText("ABC123")).toBeInTheDocument();
expect(screen.getByText("En ruta")).toBeInTheDocument();
expect(screen.getByText("Departure:")).toBeInTheDocument();
expect(screen.getByText("Arrival:")).toBeInTheDocument();
expect(screen.getByText("Gate:")).toBeInTheDocument();
expect(screen.getByText("2023-10-30 10:00 AM")).toBeInTheDocument();
expect(screen.getByText("2023-10-30 12:00 PM")).toBeInTheDocument();
expect(screen.getByText("A1")).toBeInTheDocument();
}); });
}); });

View File

@ -0,0 +1,273 @@
import { act, render, screen, waitFor } from "@testing-library/react";
import { Departure } from "./Departure";
import { MemoryRouter } from "react-router-dom";
import { useFetchDeparture } from "../../hooks/useFetchDeparture";
import '@testing-library/jest-dom';
jest.mock("../../hooks/useFetchDeparture");
const mochedUseFetchDeparture = useFetchDeparture as jest.MockedFunction<typeof useFetchDeparture>;
describe("Departure component tests", () => {
test("Renders departure component with headers", () => {
mochedUseFetchDeparture.mockReturnValue({ zones: [], error: null });
render(
<MemoryRouter>
<Departure />
</MemoryRouter>
);
expect(screen.getByText("Departure")).toBeInTheDocument();
expect(screen.getByText("Code")).toBeInTheDocument();
expect(screen.getByText("Destination")).toBeInTheDocument();
expect(screen.getByText("Time")).toBeInTheDocument();
expect(screen.getByText("Gate")).toBeInTheDocument();
expect(screen.getByText("Status")).toBeInTheDocument();
});
test("Renders error message when there is an error", async () => {
mochedUseFetchDeparture.mockReturnValue({ zones: [], error: "Error fetching data" });
render(
<MemoryRouter>
<Departure />
</MemoryRouter>
);
await waitFor(() => {
expect(screen.getByText("Error fetching data")).toBeInTheDocument();
});
});
test("Doesn't throw an error when no data is available", async () => {
mochedUseFetchDeparture.mockReturnValue({ zones: [], error: null });
render(
<MemoryRouter>
<Departure />
</MemoryRouter>
);
await waitFor(() => {
expect(screen.queryByText("ABC123")).not.toBeInTheDocument();
expect(screen.queryByText("City A")).not.toBeInTheDocument();
expect(screen.queryByText("2023-10-30 12:00 PM")).not.toBeInTheDocument();
expect(screen.queryByText("A1")).not.toBeInTheDocument();
expect(screen.queryByText("On Time")).not.toBeInTheDocument();
})
});
test("Renders flights when data is available", async () => {
const mockFlights = [
{
id: 1,
flight_code: "ABC123",
origin: "City A",
destination: "City X",
departure_time: "2023-10-30 10:00 AM",
arrival_time: "2023-10-30 12:00 PM",
gate: "A1",
status: "On Time"
},
{
id: 2,
flight_code: "XYZ789",
origin: "City B",
destination: "City Y",
departure_time: "2023-10-31 01:30 PM",
arrival_time: "2023-10-31 02:30 PM",
gate: "B2",
status: "Delayed"
},
];
mochedUseFetchDeparture.mockReturnValue({ zones: mockFlights, error: null });
render(
<MemoryRouter>
<Departure />
</MemoryRouter>
);
await waitFor(() => {
expect(screen.getByText("ABC123")).toBeInTheDocument();
expect(screen.getByText("City X")).toBeInTheDocument();
expect(screen.getByText("2023-10-30 10:00 AM")).toBeInTheDocument();
expect(screen.getByText("A1")).toBeInTheDocument();
expect(screen.getByText("On Time")).toBeInTheDocument();
expect(screen.getByText("XYZ789")).toBeInTheDocument();
expect(screen.getByText("City Y")).toBeInTheDocument();
expect(screen.getByText("2023-10-31 01:30 PM")).toBeInTheDocument();
expect(screen.getByText("B2")).toBeInTheDocument();
expect(screen.getByText("Delayed")).toBeInTheDocument();
});
});
jest.setTimeout(20000);
test("Automatically cycles through flights with an interval", async () => {
const mockFlights = [
{
id: 1,
flight_code: "ABC123",
origin: "City A",
destination: "City X",
departure_time: "2023-10-30 10:00 AM",
arrival_time: "2023-10-30 12:00 PM",
gate: "A1",
status: "On Time"
},
{
id: 2,
flight_code: "XYZ788",
origin: "City C",
destination: "City Z",
departure_time: "2023-10-31 01:31 PM",
arrival_time: "2023-10-31 02:31 PM",
gate: "B3",
status: "Scheduled"
},
{
id: 3,
flight_code: "XYZ789",
origin: "City B",
destination: "City Y",
departure_time: "2023-10-31 01:30 PM",
arrival_time: "2023-10-31 02:30 PM",
gate: "B2",
status: "Delayed"
},
{
id: 4,
flight_code: "XYZ789",
origin: "City B",
destination: "City Y",
departure_time: "2023-10-31 01:30 PM",
arrival_time: "2023-10-31 02:30 PM",
gate: "B2",
status: "Delayed"
},
{
id: 5,
flight_code: "XYZ789",
origin: "City B",
destination: "City Y",
departure_time: "2023-10-31 01:30 PM",
arrival_time: "2023-10-31 02:30 PM",
gate: "B2",
status: "Delayed"
},
{
id: 6,
flight_code: "XYZ789",
origin: "City B",
destination: "City Y",
departure_time: "2023-10-31 01:30 PM",
arrival_time: "2023-10-31 02:30 PM",
gate: "B2",
status: "Delayed"
},
{
id: 7,
flight_code: "XYZ789",
origin: "City B",
destination: "City Y",
departure_time: "2023-10-31 01:30 PM",
arrival_time: "2023-10-31 02:30 PM",
gate: "B2",
status: "Delayed"
},
{
id: 8,
flight_code: "XYZ789",
origin: "City B",
destination: "City Y",
departure_time: "2023-10-31 01:30 PM",
arrival_time: "2023-10-31 02:30 PM",
gate: "B2",
status: "Delayed"
},
{
id: 9,
flight_code: "XYZ789",
origin: "City B",
destination: "City Y",
departure_time: "2023-10-31 01:30 PM",
arrival_time: "2023-10-31 02:30 PM",
gate: "B2",
status: "Delayed"
},
{
id: 10,
flight_code: "XYZ789",
origin: "City B",
destination: "City Y",
departure_time: "2023-10-31 01:30 PM",
arrival_time: "2023-10-31 02:30 PM",
gate: "B2",
status: "Delayed"
},
{
id: 11,
flight_code: "XYZ789",
origin: "City B",
destination: "City Y",
departure_time: "2023-10-31 01:30 PM",
arrival_time: "2023-10-31 02:30 PM",
gate: "B2",
status: "Delayed"
},
];
mochedUseFetchDeparture.mockReturnValue({ zones: mockFlights, error: null });
render(
<MemoryRouter>
<Departure />
</MemoryRouter>
);
await waitFor(() => {
expect(screen.getByText("ABC123")).toBeInTheDocument();
expect(screen.getByText("City X")).toBeInTheDocument();
expect(screen.getByText("2023-10-30 10:00 AM")).toBeInTheDocument();
expect(screen.getByText("A1")).toBeInTheDocument();
expect(screen.getByText("On Time")).toBeInTheDocument();
expect(screen.getByText("XYZ788")).toBeInTheDocument();
expect(screen.getByText("City Z")).toBeInTheDocument();
expect(screen.getByText("2023-10-31 01:31 PM")).toBeInTheDocument();
expect(screen.getByText("B3")).toBeInTheDocument();
expect(screen.getByText("Scheduled")).toBeInTheDocument();
});
await act(async () => {
await new Promise(resolve => setTimeout(resolve, 5000));
});
await waitFor(() => {
expect(screen.queryByText("ABC123")).not.toBeInTheDocument();
expect(screen.queryByText("City X")).not.toBeInTheDocument();
expect(screen.queryByText("2023-10-30 10:00 AM")).not.toBeInTheDocument();
expect(screen.queryByText("A1")).not.toBeInTheDocument();
expect(screen.queryByText("On Time")).not.toBeInTheDocument();
expect(screen.queryByText("XYZ788")).not.toBeInTheDocument();
expect(screen.queryByText("City Z")).not.toBeInTheDocument();
expect(screen.queryByText("2023-10-31 01:31 PM")).not.toBeInTheDocument();
expect(screen.queryByText("B3")).not.toBeInTheDocument();
expect(screen.queryByText("Scheduled")).not.toBeInTheDocument();
expect(screen.getByText("XYZ789")).toBeInTheDocument();
expect(screen.getByText("City Y")).toBeInTheDocument();
expect(screen.getByText("2023-10-31 01:30 PM")).toBeInTheDocument();
expect(screen.getByText("B2")).toBeInTheDocument();
expect(screen.getByText("Delayed")).toBeInTheDocument();
});
});
});

View File

@ -1,8 +1,7 @@
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import { Card } from "./Card/Card"; import { useFetchDeparture } from "../../hooks/useFetchDeparture";
import { useFetchOrigin } from "../../hooks/useFetchOrigin";
import { Flight } from "../../Types"; import { Flight } from "../../Types";
import './Home.css' import './Page.css'
import { Table, Thead, Tbody, Tr, Th, Td } from 'react-super-responsive-table'; import { Table, Thead, Tbody, Tr, Th, Td } from 'react-super-responsive-table';
import 'react-super-responsive-table/dist/SuperResponsiveTableStyle.css'; import 'react-super-responsive-table/dist/SuperResponsiveTableStyle.css';
@ -13,7 +12,7 @@ interface Props {
export const Departure: React.FC<Props> = (props) => { export const Departure: React.FC<Props> = (props) => {
let origin = process.env.REACT_APP_ORIGIN; let origin = process.env.REACT_APP_ORIGIN;
const { zones, error } = useFetchOrigin(origin); const { zones, error } = useFetchDeparture(origin);
const [startIndex, setStartIndex] = useState(0); const [startIndex, setStartIndex] = useState(0);
useEffect(() => { useEffect(() => {
@ -59,7 +58,7 @@ export const Departure: React.FC<Props> = (props) => {
<> <>
{Array.from({ length: startIndex + 10 - zones.length }).map((_, index) => { {Array.from({ length: startIndex + 10 - zones.length }).map((_, index) => {
return ( return (
<Tr> <Tr key={index}>
<Td></Td> <Td></Td>
<Td></Td> <Td></Td>
<Td></Td> <Td></Td>

View File

@ -1,43 +1,33 @@
body { body {
font-family: 'Arial', sans-serif; font-family: 'Arial', sans-serif;
background-color: #f0f0f0; background-color: #f0f0f0;
margin: 0;
padding: 0;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
} }
.App { div {
text-align: center; text-align: center;
margin-top: 20px;
} }
table { button {
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; background-color: #4CAF50;
color: #fff; 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;
} }
tbody tr:hover { button:hover {
background-color: #f5f5f5; background-color: #45a049;
}
tfoot {
background-color: #4CAF50;
color: #fff;
}
.delayed-flight {
background-color: #ffcccc;
color: #ff0000;
} }

View File

@ -1,28 +1,50 @@
const mockedUsedNavigate = jest.fn();
jest.mock("react-router-dom", () => ({
...jest.requireActual("react-router-dom"),
useNavigate: () => mockedUsedNavigate,
}));
import "../../matchMedia.mock"; import "../../matchMedia.mock";
import "@testing-library/jest-dom"; import "@testing-library/jest-dom";
import { render, screen } from "@testing-library/react"; import { fireEvent, render, screen } from "@testing-library/react";
// import { Home } from "./Departure"; import { Home } from "./Home";
import { MemoryRouter } from "react-router-dom";
describe("Home View Test", () => { const mockedUseNavigate = jest.fn();
test("Display initial, name and icon", async () => {
// render(
// <Home
// zones={[
// { id: 1, name: "Belgrano" },
// { id: 2, name: "San Isidro" },
// ]}
// />
// );
// expect(screen.getByText("Zones")).toBeVisible(); jest.mock("react-router", () => ({
// expect(screen.getByText("Belgrano📍")).toBeVisible(); ...jest.requireActual("react-router"),
// expect(screen.getByText("San Isidro📍")).toBeVisible(); useNavigate: () => mockedUseNavigate,
}));
describe("Home tests", () => {
test("Renders departure and arrival buttons", () => {
render(
<MemoryRouter>
<Home />
</MemoryRouter>
);
const departureButton = screen.getByText("Departure");
const arrivalButton = screen.getByText("Arrival");
expect(departureButton).toBeInTheDocument();
expect(arrivalButton).toBeInTheDocument();
});
test("Clicking departure button navigates to /departure", () => {
render(
<MemoryRouter>
<Home />
</MemoryRouter>
);
const departureButton = screen.getByText("Departure");
fireEvent.click(departureButton);
expect(mockedUseNavigate).toHaveBeenCalledWith("/departure");
});
test("Clicking arrival button navigates to /arrival", () => {
render(
<MemoryRouter>
<Home />
</MemoryRouter>
);
const arrivalButton = screen.getByText("Arrival");
fireEvent.click(arrivalButton);
expect(mockedUseNavigate).toHaveBeenCalledWith("/arrival");
}); });
}); });

View File

@ -1,14 +1,7 @@
import React from "react";
import { Flight } from "../../Types";
import './Home.css'
import { useNavigate } from "react-router"; import { useNavigate } from "react-router";
import './Page.css' import './Home.css'
interface Props { export const Home = () => {
flights?: Flight[];
}
export const Home: React.FC<Props> = (props) => {
const navigate = useNavigate(); const navigate = useNavigate();
const submitHandler = (path: string) => { const submitHandler = (path: string) => {

View File

@ -1,33 +1,43 @@
body { body {
font-family: 'Arial', sans-serif; font-family: 'Arial', sans-serif;
background-color: #f0f0f0; background-color: #f0f0f0;
margin: 0;
padding: 0;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
} }
div { .App {
text-align: center; text-align: center;
margin-top: 20px;
} }
button { 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; background-color: #4CAF50;
border: none; color: #fff;
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 { tbody tr:hover {
background-color: #45a049; background-color: #f5f5f5;
}
tfoot {
background-color: #4CAF50;
color: #fff;
}
.delayed-flight {
background-color: #ffcccc;
color: #ff0000;
} }

View File

@ -50,13 +50,10 @@ export const deleteData = (storeName: string, key: number): Promise<boolean> =>
const tx = db.transaction(storeName, 'readwrite'); const tx = db.transaction(storeName, 'readwrite');
const store = tx.objectStore(storeName); const store = tx.objectStore(storeName);
const res = store.delete(key); const res = store.delete(key);
console.log("removing" + key)
res.onsuccess = () => { res.onsuccess = () => {
console.log("success")
resolve(true); resolve(true);
}; };
res.onerror = () => { res.onerror = () => {
console.log("error")
resolve(false); resolve(false);
} }
}); });

View File

@ -0,0 +1,80 @@
import { useFetchArrival } from "./useFetchArrival";
import { fetchZones } from "../Api";
import { initDB, addData, deleteData, getStoreData, updateData } from '../db';
import { act, render, renderHook, screen, waitFor } from "@testing-library/react";
import { MemoryRouter } from "react-router-dom";
import '@testing-library/jest-dom';
jest.mock("../Api");
jest.mock('../db');
const mockedFetchZones = fetchZones as jest.MockedFunction<typeof fetchZones>;
const mockedInitDB = initDB as jest.MockedFunction<typeof initDB>;
const mockedAddData = addData as jest.MockedFunction<typeof addData>;
const mockedDeleteData = deleteData as jest.MockedFunction<typeof deleteData>;
const mockedGetStoreData = getStoreData as jest.MockedFunction<typeof getStoreData>;
const mockedUpdateData = updateData as jest.MockedFunction<typeof updateData>;
const mockFlights = [
{
id: 1,
flight_code: "ABC123",
origin: "City A",
destination: "City X",
departure_time: "2023-10-30 10:00 AM",
arrival_time: "2023-10-30 12:00 PM",
gate: "A1",
status: "On Time"
},
{
id: 2,
flight_code: "XYZ789",
origin: "City B",
destination: "City Y",
departure_time: "2023-10-31 01:30 PM",
arrival_time: "2023-10-31 02:30 PM",
gate: "B2",
status: "Delayed"
},
];
describe("useFetchArrival Hook Tests", () => {
beforeEach(() => {
jest.clearAllMocks();
localStorage.clear();
});
test("Fetches data initially and updates zones state", async () => {
mockedFetchZones.mockResolvedValueOnce(mockFlights);
mockedInitDB.mockResolvedValueOnce(false);
mockedGetStoreData.mockResolvedValueOnce([]);
mockedAddData.mockImplementationOnce((store, data) => Promise.resolve(data));
const { result } = renderHook(() => useFetchArrival("destination"));
await waitFor(() => {
expect(result.current.zones).toEqual(mockFlights);
expect(mockedFetchZones).toHaveBeenCalledWith(undefined, "destination", null);
expect(mockedInitDB).toHaveBeenCalledTimes(1);
expect(mockedAddData).toHaveBeenCalledWith("arrival", mockFlights[0]);
});
});
// test("Handles errors during initial data fetch", async () => {
// const errorMessage = "Error fetching data";
// mockedInitDB.mockResolvedValueOnce(false);
// mockedGetStoreData.mockResolvedValueOnce([]);
// mockedFetchZones.mockRejectedValueOnce(new Error(errorMessage));
// const { result } = renderHook(() => useFetchArrival("destination"));
// await waitFor(() => {
// expect(result.current.zones).toEqual([]);
// expect(result.current.error).toEqual(errorMessage);
// expect(mockedFetchZones).toHaveBeenCalledWith(undefined, "destination", null);
// })
// });
});

View File

@ -4,7 +4,7 @@ import { Flight } from "../Types";
import { fetchZones } from "../Api"; import { fetchZones } from "../Api";
import { Stores, addData, deleteData, getStoreData, updateData, initDB } from '../db'; import { Stores, addData, deleteData, getStoreData, updateData, initDB } from '../db';
export const useFetchDestination = (destination: string | undefined) => { export const useFetchArrival = (destination: string | undefined) => {
const [error, setError] = useState<string | null>(null); const [error, setError] = useState<string | null>(null);
const [zones, setZones] = useState<Flight[]>([]); const [zones, setZones] = useState<Flight[]>([]);
@ -44,12 +44,10 @@ export const useFetchDestination = (destination: string | undefined) => {
localStorage.setItem('date', new Date().toString()) localStorage.setItem('date', new Date().toString())
initDB().then((x) => { initDB().then((x) => {
console.log(x)
getStoreData<Flight>(Stores.Arrival) getStoreData<Flight>(Stores.Arrival)
.then((data) => { .then((data) => {
console.log(data)
if (data && data.length > 0) { if (data && data.length > 0) {
data.sort((a, b) => new Date(a.departure_time).getTime() - new Date(b.departure_time).getTime()) data.sort((a, b) => new Date(a.arrival_time).getTime() - new Date(b.arrival_time).getTime())
setZones(data) setZones(data)
} else { } else {
fetchZones(undefined, destination, null) fetchZones(undefined, destination, null)
@ -62,7 +60,7 @@ export const useFetchDestination = (destination: string | undefined) => {
toAdd.push(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.arrival_time).getTime() - new Date(b.arrival_time).getTime())
setZones(toAdd); setZones(toAdd);
}) })
.catch((error) => { }); .catch((error) => { });
@ -87,19 +85,14 @@ export const useFetchDestination = (destination: string | undefined) => {
zones.forEach((c, i) => { zones.forEach((c, i) => {
let index = data.findIndex(x => x.id === c.id) let index = data.findIndex(x => x.id === c.id)
if (index >= 0) { if (index >= 0) {
console.log(data[index].departure_time + 'nuevo') if (data[index].status == 'Deleted' || new Date(data[index].arrival_time) < new Date()) {
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) deleteData(Stores.Arrival, c.id)
} else { } else {
toAdd.push(data[index]); toAdd.push(data[index]);
updateData(Stores.Arrival, c.id, data[index]) updateData(Stores.Arrival, c.id, data[index])
} }
} else { } else {
console.log(new Date(c.departure_time)) if (c.status == 'Deleted' || new Date(c.arrival_time) < new Date()) {
if (c.status == 'Deleted' || new Date(c.departure_time) < new Date()) {
console.log("sacamos?")
toRemove.push(c); toRemove.push(c);
deleteData(Stores.Arrival, c.id) deleteData(Stores.Arrival, c.id)
} else { } else {
@ -109,16 +102,14 @@ export const useFetchDestination = (destination: string | undefined) => {
}); });
let filtered = data.filter(o => 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()) !toAdd.some(b => { return o.id === b.id }) && !toRemove.some(b => { return o.id === b.id }) && !(new Date(o.arrival_time) < new Date())
) )
const newArray = toAdd.concat(filtered); const newArray = toAdd.concat(filtered);
console.log(filtered)
console.log(newArray)
filtered.forEach(c => { filtered.forEach(c => {
addData(Stores.Arrival, 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.arrival_time).getTime() - new Date(b.arrival_time).getTime())
setZones(newArray); setZones(newArray);
}) })
.catch((error) => { .catch((error) => {

View File

@ -0,0 +1,80 @@
import { useFetchDeparture } from "./useFetchDeparture";
import { fetchZones } from "../Api";
import { initDB, addData, deleteData, getStoreData, updateData } from '../db';
import { act, render, renderHook, screen, waitFor } from "@testing-library/react";
import { MemoryRouter } from "react-router-dom";
import '@testing-library/jest-dom';
jest.mock("../Api");
jest.mock('../db');
const mockedFetchZones = fetchZones as jest.MockedFunction<typeof fetchZones>;
const mockedInitDB = initDB as jest.MockedFunction<typeof initDB>;
const mockedAddData = addData as jest.MockedFunction<typeof addData>;
const mockedDeleteData = deleteData as jest.MockedFunction<typeof deleteData>;
const mockedGetStoreData = getStoreData as jest.MockedFunction<typeof getStoreData>;
const mockedUpdateData = updateData as jest.MockedFunction<typeof updateData>;
const mockFlights = [
{
id: 1,
flight_code: "ABC123",
origin: "City A",
destination: "City X",
departure_time: "2023-10-30 10:00 AM",
arrival_time: "2023-10-30 12:00 PM",
gate: "A1",
status: "On Time"
},
{
id: 2,
flight_code: "XYZ789",
origin: "City B",
destination: "City Y",
departure_time: "2023-10-31 01:30 PM",
arrival_time: "2023-10-31 02:30 PM",
gate: "B2",
status: "Delayed"
},
];
describe("useFetchDeparture Hook Tests", () => {
beforeEach(() => {
jest.clearAllMocks();
localStorage.clear();
});
test("Fetches data initially and updates zones state", async () => {
mockedFetchZones.mockResolvedValueOnce(mockFlights);
mockedInitDB.mockResolvedValueOnce(false);
mockedGetStoreData.mockResolvedValueOnce([]);
mockedAddData.mockImplementationOnce((store, data) => Promise.resolve(data));
const { result } = renderHook(() => useFetchDeparture("origin"));
await waitFor(() => {
expect(result.current.zones).toEqual(mockFlights);
expect(mockedFetchZones).toHaveBeenCalledWith("origin", undefined, null);
expect(mockedInitDB).toHaveBeenCalledTimes(1);
expect(mockedAddData).toHaveBeenCalledWith("departure", mockFlights[0]);
});
});
// test("Handles errors during initial data fetch", async () => {
// const errorMessage = "Error fetching data";
// mockedInitDB.mockResolvedValueOnce(false);
// mockedGetStoreData.mockResolvedValueOnce([]);
// mockedFetchZones.mockRejectedValueOnce(new Error(errorMessage));
// const { result } = renderHook(() => useFetchDeparture("destination"));
// await waitFor(() => {
// expect(result.current.zones).toEqual([]);
// expect(result.current.error).toEqual(errorMessage);
// expect(mockedFetchZones).toHaveBeenCalledWith(undefined, "destination", null);
// })
// });
});

View File

@ -4,7 +4,7 @@ import { Flight } from "../Types";
import { fetchZones } from "../Api"; import { fetchZones } from "../Api";
import { Stores, addData, deleteData, getStoreData, updateData, initDB } from '../db'; import { Stores, addData, deleteData, getStoreData, updateData, initDB } from '../db';
export const useFetchOrigin = (origin: string | undefined) => { export const useFetchDeparture = (origin: string | undefined) => {
const [error, setError] = useState<string | null>(null); const [error, setError] = useState<string | null>(null);
const [zones, setZones] = useState<Flight[]>([]); const [zones, setZones] = useState<Flight[]>([]);
@ -44,12 +44,10 @@ export const useFetchOrigin = (origin: string | undefined) => {
localStorage.setItem('date', new Date().toString()) localStorage.setItem('date', new Date().toString())
initDB().then((x) => { initDB().then((x) => {
console.log(x)
getStoreData<Flight>(Stores.Departure) getStoreData<Flight>(Stores.Departure)
.then((data) => { .then((data) => {
console.log(data)
if (data && data.length > 0) { if (data && data.length > 0) {
data.sort((a, b) => new Date(a.origin).getTime() - new Date(b.origin).getTime()) data.sort((a, b) => new Date(a.departure_time).getTime() - new Date(b.departure_time).getTime())
setZones(data) setZones(data)
} else { } else {
fetchZones(origin, undefined, null) fetchZones(origin, undefined, null)
@ -62,7 +60,7 @@ export const useFetchOrigin = (origin: string | undefined) => {
toAdd.push(u) toAdd.push(u)
} }
}) })
toAdd.sort((a, b) => new Date(a.origin).getTime() - new Date(b.origin).getTime()) toAdd.sort((a, b) => new Date(a.departure_time).getTime() - new Date(b.departure_time).getTime())
setZones(toAdd); setZones(toAdd);
}) })
.catch((error) => { }); .catch((error) => { });
@ -87,9 +85,7 @@ export const useFetchOrigin = (origin: string | undefined) => {
zones.forEach((c, i) => { zones.forEach((c, i) => {
let index = data.findIndex(x => x.id === c.id) let index = data.findIndex(x => x.id === c.id)
if (index >= 0) { if (index >= 0) {
console.log(data[index].departure_time + 'nuevo')
if (data[index].status == 'Deleted' || new Date(data[index].departure_time) < new Date()) { if (data[index].status == 'Deleted' || new Date(data[index].departure_time) < new Date()) {
console.log("sacamos")
toRemove.push(data[index]) toRemove.push(data[index])
deleteData(Stores.Departure, c.id) deleteData(Stores.Departure, c.id)
} else { } else {
@ -97,9 +93,7 @@ export const useFetchOrigin = (origin: string | undefined) => {
updateData(Stores.Departure, c.id, data[index]) updateData(Stores.Departure, c.id, data[index])
} }
} else { } else {
console.log(new Date(c.departure_time))
if (c.status == 'Deleted' || new Date(c.departure_time) < new Date()) { if (c.status == 'Deleted' || new Date(c.departure_time) < new Date()) {
console.log("sacamos?")
toRemove.push(c); toRemove.push(c);
deleteData(Stores.Departure, c.id) deleteData(Stores.Departure, c.id)
} else { } else {
@ -112,13 +106,11 @@ export const useFetchOrigin = (origin: string | undefined) => {
!toAdd.some(b => { return o.id === b.id }) && !toRemove.some(b => { return o.id === b.id }) && !(new Date(o.departure_time) < new Date()) !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); const newArray = toAdd.concat(filtered);
console.log(filtered)
console.log(newArray)
filtered.forEach(c => { filtered.forEach(c => {
addData(Stores.Departure, c) addData(Stores.Departure, c)
}) })
newArray.sort((a, b) => new Date(a.origin).getTime() - new Date(b.origin).getTime()) newArray.sort((a, b) => new Date(a.departure_time).getTime() - new Date(b.departure_time).getTime())
setZones(newArray); setZones(newArray);
}) })
.catch((error) => { .catch((error) => {

View File

@ -0,0 +1,7 @@
module.exports = {
process() {
return {
code: `module.exports = {};`,
};
},
};