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

Develop코드적용 #56

Merged
merged 14 commits into from
Oct 27, 2024
Merged
5 changes: 4 additions & 1 deletion .eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,7 @@ module.exports = {
semi: ['error', 'never'],
// '@typescript-eslint/semi': ['error', 'never'],
},
}
overrides: {
files: ['*.ts', '*.tsx'], // .ts와 .tsx 파일에 린트 적용
},
}
24 changes: 24 additions & 0 deletions .pnp.cjs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file not shown.
9 changes: 9 additions & 0 deletions global.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
declare module '*.jpg' {
const value: string;
export default value;
}

declare module '*.png' {
const value: string;
export default value;
}
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-error-boundary": "^4.0.13",
"react-flagkit": "^2.0.4",
"react-map-gl": "^7.1.7",
"react-router-dom": "^6.26.1"
},
Expand Down
52 changes: 30 additions & 22 deletions src/api/airports.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { useSuspenseQuery } from '@tanstack/react-query'
import { countryNameToCode } from '../countryNameToCode'

export type AirportList = Awaited<ReturnType<typeof fetchAirports>>
export type Airport = AirportList[number]
Expand All @@ -14,45 +15,48 @@ const fetchAirports = async () => {

const parseCSV = (data: string) => {
/*
ID: The unique identifier of the airport.
Airport Name: The name of the airport.
City: The city where the airport is located.
Country: The country where the airport is located.
IATA Code: The IATA airport code.
ICAO Code: The ICAO airport code.
Latitude: The latitude of the airport.
Longitude: The longitude of the airport.
Altitude: The altitude of the airport.
Timezone: The timezone in which the airport is located.
DST: Daylight saving time information.
Tz Database Timezone: The timezone database name.
Type: The type of location (e.g., "airport").
Source: The source of the data.
ID: The unique identifier of the airport.
Airport Name: The name of the airport.
City: The city where the airport is located.
Country: The country where the airport is located.
IATA Code: The IATA airport code.
ICAO Code: The ICAO airport code.
Latitude: The latitude of the airport.
Longitude: The longitude of the airport.
Altitude: The altitude of the airport.
Timezone: The timezone in which the airport is located.
DST: Daylight saving time information.
Tz Database Timezone: The timezone database name.
Type: The type of location (e.g., "airport").
Source: The source of the data.
*/
return data
.trim()
.split('\n')
.map((line) => {
const parts = line.split(',')
.map((record) => {
const parts = record.split(',')

return {
id: parts[0],
name: parts[1].replace(/"/g, ''), // Remove quotes from the airport name
city: parts[2].replace(/"/g, ''), // City name
country: parts[3].replace(/"/g, ''), // Country name
flag: countryNameToCode[parts[3].replace(/"/g, '')], // Country Code for Flag
iata: parts[4].replace(/"/g, ''), // IATA code
icao: parts[5].replace(/"/g, ''), // ICAO code
latitude: parseFloat(parts[6]), // Latitude
longitude: parseFloat(parts[7]), // Longitude
altitude: parseInt(parts[8]), // Altitude
timezone: parts[9], // Timezone
dst: parts[10], // DST information
tzDatabaseTimezone: parts[11], // Tz database timezone
type: parts[12], // Type (e.g., airport)
source: parts[13], // Source (e.g., OurAirports)
timezone: parts[9].replace(/"/g, ''), // Timezone
dst: parts[10].replace(/"/g, ''), // DST information
tzDatabaseTimezone: parts[11].replace(/"/g, ''), // Tz database timezone
type: parts[12].replace(/"/g, ''), // Type (e.g., airport)
source: parts[13].replace(/"/g, ''), // Source (e.g., OurAirports)
}
})
.filter(airport => airport.type === "airport" && airport.source === "OurAirports")
}

return parseCSV(textData)
}

Expand All @@ -65,6 +69,10 @@ export const useAirports = () => {
queryKey: ['airports'],
queryFn: fetchAirports,
})

const nations = new Set<string>()
airports.map(airport => {
nations.add(airport.country)
})
console.log([...nations], airports)
return { airports, isLoading, error }
}
15 changes: 7 additions & 8 deletions src/api/flight.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,19 +34,18 @@ export type Aircraft = {
origin_country: string
time_position: number
last_contact: number
longitude: number | null
latitude: number | null
baro_altitude: number | null
longitude: null | number
latitude: null | number
baro_altitude: null | number
on_ground: boolean
velocity: number | null
true_track: number | null
vertical_rate: number | null
geo_altitude: number | null
velocity: null | number
true_track: null | number
vertical_rate: null | number
geo_altitude: null | number
}

export type AircraftStatus = Aircraft | false


export const getAllActiveFlights = async (): Promise<Aircraft[]> => {
const response = await fetch(`https://opensky-network.org/api/states/all`)
const data = await response.json()
Expand Down
113 changes: 113 additions & 0 deletions src/components/AirportComboBox/AirportComboBox.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import { styled } from '@stitches/react'
import React, { useEffect, useState } from 'react'
import FlagIcon from 'react-flagkit';
import { AirportList } from '../../api/airports';

const ComboBoxContainer = styled('div', {
display: 'flex',
flexDirection: 'column',
minWidth: '250px',
padding: '8px',
border: '1px solid #CCC',
borderRadius: '8px',
backgroundColor: '#EFEFEF', //'$background',
})
const Input = styled('input', {
padding: '8px',
borderRadius: '4px',
border: '1px solid #CCC',
marginBottom: '8px',
// position: 'absolute',
})
const Dropdown = styled('ul', {
listStyle: 'none',
padding: '0',
margin: '0',
border: '1px solid #CCC',
borderRadius: '4px',
backgroundColor: '#FFF',
maxHeight: '150px',
maxWidth: '350px',
overflowY: 'auto',
})
const Option = styled('li', {
display: 'flex',
justifyContent: 'flex-start',
alignItems: 'center',
textAlign: 'left',
width: 'max-content',
padding: '8px',
overflow: 'hidden',
cursor: 'pointer',

'&:hover': {
backgroundColor: '#DDD',
},

'p': {
fontWeight: 'bold',
fontSize: '.8rem',
margin: '0',
padding: '0',
}
})

const ComboBox = ({ airports, onSelectAirport, blacklist }: any) => {
const [searchTerm, setSearchTerm] = useState<string>('')
const [filteredAirports, setFilteredAirports] = useState<AirportList>([])

const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const value = e.target.value
setSearchTerm(value)
}

useEffect(() => {

if (searchTerm === '' || searchTerm.length < 2) {
setFilteredAirports([])
return
}

const filtered = airports.filter(
(airport: any) =>
airport.city.replaceAll(' ', '').toLowerCase().indexOf(searchTerm.toLocaleLowerCase()) > -1
|| airport.country.replaceAll(' ', '').toLowerCase().indexOf(searchTerm.toLocaleLowerCase()) > -1
)
setFilteredAirports(filtered)
}, [searchTerm])

const handleOptionClick = (airport: any) => {
onSelectAirport(airport)
setSearchTerm(airport.name)
setFilteredAirports([])
}


return (
<ComboBoxContainer>
<Input
onChange={handleInputChange}
placeholder="공항을 검색해주세요."
type="text"
value={searchTerm}
/>
{filteredAirports.length > 0 && (
<Dropdown>
{filteredAirports
.filter((airport: any) => airport.id !== blacklist?.id)
.map((airport: any) => (
<Option
key={airport.id}
onClick={() => handleOptionClick(airport)}
>
{airport.flag === '-' ? '🌏' : <FlagIcon alt={airport.country} country={airport.flag} />}
&nbsp;<p>{airport.city}</p>&nbsp;{airport.name}
</Option>
))}
</Dropdown>
)}
</ComboBoxContainer>
)
}

export default ComboBox
16 changes: 8 additions & 8 deletions src/components/Button/VSKyButton.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from "react";
import { styled } from "@stitches/react";
import { styled } from '@stitches/react'
import React from 'react'

const Button = styled('button', {
backgroundColor: '#18B2FF', // todo - blue로 정의하고 바꾸기
Expand All @@ -13,15 +13,15 @@ const Button = styled('button', {
'&:hover': {
backgroundColor: 'darkblue', // todo - hex변경하기
},
});
})

type ButtonProps = {
children: React.ReactNode;
onClick?: () => void;
};
children: React.ReactNode
onClick?: () => void
}

function VSkyButton({ children, onClick }: ButtonProps) {
return <Button onClick={onClick}>{children}</Button>;
return <Button onClick={onClick}>{children}</Button>
}

export default VSkyButton;
export default VSkyButton
Loading
Loading