Fixed airport responses
This commit is contained in:
@@ -22,7 +22,7 @@ pub struct Airport {
|
|||||||
pub iata_code: String,
|
pub iata_code: String,
|
||||||
pub local_code: String,
|
pub local_code: String,
|
||||||
pub point: Point,
|
pub point: Point,
|
||||||
pub tower: Option<bool>,
|
pub has_tower: Option<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Into<QueryAirport> for Airport {
|
impl Into<QueryAirport> for Airport {
|
||||||
|
|||||||
@@ -106,10 +106,17 @@ async fn get_all(req: HttpRequest) -> HttpResponse {
|
|||||||
let pages = ((total as f64) / (if limit <= 0 { 1 } else { limit} as f64)).ceil() as i64;
|
let pages = ((total as f64) / (if limit <= 0 { 1 } else { limit} as f64)).ceil() as i64;
|
||||||
|
|
||||||
match web::block(move || QueryAirport::get_all(&filters, limit, page)).await.unwrap() {
|
match web::block(move || QueryAirport::get_all(&filters, limit, page)).await.unwrap() {
|
||||||
Ok(a) => HttpResponse::Ok().json(Response {
|
Ok(a) => {
|
||||||
data: a,
|
// Convert Vec<QueryAirport> to Vec<Airport>
|
||||||
meta: Some(Metadata { page, limit, pages, total })
|
let mut airports: Vec<Airport> = vec![];
|
||||||
}),
|
for airport in a {
|
||||||
|
airports.push(airport.into());
|
||||||
|
}
|
||||||
|
HttpResponse::Ok().json(Response {
|
||||||
|
data: airports,
|
||||||
|
meta: Some(Metadata { page, limit, pages, total })
|
||||||
|
})
|
||||||
|
},
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
error!("{}", err);
|
error!("{}", err);
|
||||||
err.to_http_response()
|
err.to_http_response()
|
||||||
@@ -120,10 +127,13 @@ async fn get_all(req: HttpRequest) -> HttpResponse {
|
|||||||
#[get("/{icao}")]
|
#[get("/{icao}")]
|
||||||
async fn get(icao: web::Path<String>) -> HttpResponse {
|
async fn get(icao: web::Path<String>) -> HttpResponse {
|
||||||
match QueryAirport::find(icao.into_inner()) {
|
match QueryAirport::find(icao.into_inner()) {
|
||||||
Ok(a) => HttpResponse::Ok().json(Response {
|
Ok(a) => {
|
||||||
data: a,
|
let airport: Airport = a.into();
|
||||||
meta: Some(Metadata { page: 1, limit: 1, pages: 1, total: 1 })
|
HttpResponse::Ok().json(Response {
|
||||||
}),
|
data: airport,
|
||||||
|
meta: Some(Metadata { page: 1, limit: 1, pages: 1, total: 1 })
|
||||||
|
})
|
||||||
|
},
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
error!("{}", err);
|
error!("{}", err);
|
||||||
err.to_http_response()
|
err.to_http_response()
|
||||||
@@ -139,7 +149,10 @@ async fn create(airport: web::Json<Airport>, auth: JwtAuth) -> HttpResponse {
|
|||||||
};
|
};
|
||||||
let query_airport: QueryAirport = airport.into_inner().into();
|
let query_airport: QueryAirport = airport.into_inner().into();
|
||||||
match QueryAirport::insert(query_airport) {
|
match QueryAirport::insert(query_airport) {
|
||||||
Ok(a) => HttpResponse::Created().json(a),
|
Ok(a) => {
|
||||||
|
let airport: Airport = a.into();
|
||||||
|
HttpResponse::Ok().json(airport)
|
||||||
|
},
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
error!("{}", err);
|
error!("{}", err);
|
||||||
err.to_http_response()
|
err.to_http_response()
|
||||||
@@ -155,7 +168,10 @@ async fn update(icao: web::Path<String>, airport: web::Json<Airport>, auth: JwtA
|
|||||||
};
|
};
|
||||||
let query_airport: QueryAirport = airport.into_inner().into();
|
let query_airport: QueryAirport = airport.into_inner().into();
|
||||||
match QueryAirport::update(icao.into_inner(), query_airport) {
|
match QueryAirport::update(icao.into_inner(), query_airport) {
|
||||||
Ok(a) => HttpResponse::Ok().json(a),
|
Ok(a) => {
|
||||||
|
let airport: Airport = a.into();
|
||||||
|
HttpResponse::Ok().json(airport)
|
||||||
|
},
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
error!("{}", err);
|
error!("{}", err);
|
||||||
err.to_http_response()
|
err.to_http_response()
|
||||||
|
|||||||
@@ -8,10 +8,15 @@ use serde::{Deserialize, Serialize};
|
|||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
pub struct QualityControlFlags {
|
pub struct QualityControlFlags {
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub auto: Option<bool>,
|
pub auto: Option<bool>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub auto_station_without_precipication: Option<bool>,
|
pub auto_station_without_precipication: Option<bool>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub auto_station_with_precipication: Option<bool>,
|
pub auto_station_with_precipication: Option<bool>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub maintenance_indicator_on: Option<bool>,
|
pub maintenance_indicator_on: Option<bool>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub corrected: Option<bool>
|
pub corrected: Option<bool>
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -30,6 +35,7 @@ impl Default for QualityControlFlags {
|
|||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
pub struct SkyCondition {
|
pub struct SkyCondition {
|
||||||
pub sky_cover: String,
|
pub sky_cover: String,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub cloud_base_ft_agl: Option<i32>
|
pub cloud_base_ft_agl: Option<i32>
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,8 +51,11 @@ impl Default for SkyCondition {
|
|||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
pub struct RunwayVisualRange {
|
pub struct RunwayVisualRange {
|
||||||
pub runway: String,
|
pub runway: String,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub visibility_ft: Option<String>,
|
pub visibility_ft: Option<String>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub variable_visibility_high_ft: Option<String>,
|
pub variable_visibility_high_ft: Option<String>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub variable_visibility_low_ft: Option<String>
|
pub variable_visibility_low_ft: Option<String>
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,23 +84,36 @@ pub struct Metar {
|
|||||||
pub raw_text: String,
|
pub raw_text: String,
|
||||||
pub station_id: String,
|
pub station_id: String,
|
||||||
pub observation_time: chrono::NaiveDateTime,
|
pub observation_time: chrono::NaiveDateTime,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub temp_c: Option<f64>,
|
pub temp_c: Option<f64>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub dewpoint_c: Option<f64>,
|
pub dewpoint_c: Option<f64>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub wind_dir_degrees: Option<String>,
|
pub wind_dir_degrees: Option<String>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub wind_speed_kt: Option<i32>,
|
pub wind_speed_kt: Option<i32>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub wind_gust_kt: Option<i32>,
|
pub wind_gust_kt: Option<i32>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub variable_wind_dir_degrees: Option<String>,
|
pub variable_wind_dir_degrees: Option<String>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub visibility_statute_mi: Option<String>,
|
pub visibility_statute_mi: Option<String>,
|
||||||
pub runway_visual_range: Vec<RunwayVisualRange>,
|
pub runway_visual_range: Vec<RunwayVisualRange>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub altim_in_hg: Option<f64>,
|
pub altim_in_hg: Option<f64>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub sea_level_pressure_mb: Option<f64>,
|
pub sea_level_pressure_mb: Option<f64>,
|
||||||
pub quality_control_flags: QualityControlFlags,
|
pub quality_control_flags: QualityControlFlags,
|
||||||
pub weather_phenomena: Vec<String>,
|
pub weather_phenomena: Vec<String>,
|
||||||
pub sky_condition: Vec<SkyCondition>,
|
pub sky_condition: Vec<SkyCondition>,
|
||||||
pub flight_category: FlightCategory,
|
pub flight_category: FlightCategory,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub three_hr_pressure_tendency_mb: Option<f64>,
|
pub three_hr_pressure_tendency_mb: Option<f64>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub max_t_c: Option<f64>,
|
pub max_t_c: Option<f64>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub min_t_c: Option<f64>,
|
pub min_t_c: Option<f64>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub precip_in: Option<f64>,
|
pub precip_in: Option<f64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ export interface Metar {
|
|||||||
sky_condition: SkyCondition[];
|
sky_condition: SkyCondition[];
|
||||||
flight_category: 'VFR' | 'MVFR' | 'LIFR' | 'IFR' | 'UNKN';
|
flight_category: 'VFR' | 'MVFR' | 'LIFR' | 'IFR' | 'UNKN';
|
||||||
three_hr_pressure_tendency_mb: number;
|
three_hr_pressure_tendency_mb: number;
|
||||||
maxT_c: number;
|
max_t_c: number;
|
||||||
minT_c: number;
|
min_t_c: number;
|
||||||
precip_in: number;
|
precip_in: number;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ export default function MapTiles() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function metarIcon(airport: Airport) {
|
function metarIcon(airport: Airport) {
|
||||||
function innerIcon({ tag, color, size = 'sm' }: { tag: string; color: string; size?: string }) {
|
function innerIcon({ tag, color, size = 'xs' }: { tag: string; color: string; size?: string }) {
|
||||||
return new DivIcon({
|
return new DivIcon({
|
||||||
html: ReactDOMServer.renderToString(
|
html: ReactDOMServer.renderToString(
|
||||||
<MantineProvider>
|
<MantineProvider>
|
||||||
|
|||||||
@@ -48,7 +48,13 @@ export default function MetarModal({ airport, isOpen, onClose }: MetarModalProps
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal opened={isOpen} onClose={onClose} withCloseButton={false} size={'50%'} className='modal'>
|
<Modal
|
||||||
|
opened={isOpen}
|
||||||
|
onClose={onClose}
|
||||||
|
withCloseButton={false}
|
||||||
|
size={'50%'}
|
||||||
|
className='modal'
|
||||||
|
>
|
||||||
<span className='title'>
|
<span className='title'>
|
||||||
<Link href={`/airport/${airport.icao}`}>
|
<Link href={`/airport/${airport.icao}`}>
|
||||||
{airport.icao} {airport.full_name}
|
{airport.icao} {airport.full_name}
|
||||||
@@ -163,13 +169,14 @@ function MetarInfo({ metar }: { metar: Metar }) {
|
|||||||
</Grid>
|
</Grid>
|
||||||
</Grid.Col>
|
</Grid.Col>
|
||||||
<Grid.Col className='gutter-row' span={12}>
|
<Grid.Col className='gutter-row' span={12}>
|
||||||
<Grid style={{ paddingTop: '1em', paddingBottom: '1em' }} gutter={48}>
|
<Grid gutter={18}>
|
||||||
{metar.weather_phenomena &&
|
<Grid.Col className='gutter-row' span={12}>
|
||||||
metar.weather_phenomena.map((wx) => (
|
<Card shadow='sm' padding='sm' radius='md' style={{ textAlign: 'center' }}>
|
||||||
<Grid.Col span={1}>
|
<Card.Section>
|
||||||
<MetarIcon wx={wx} />
|
|
||||||
</Grid.Col>
|
</Card.Section>
|
||||||
))}
|
</Card>
|
||||||
|
</Grid.Col>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid.Col>
|
</Grid.Col>
|
||||||
</Grid.Col>
|
</Grid.Col>
|
||||||
|
|||||||
@@ -15,4 +15,4 @@
|
|||||||
|
|
||||||
.modal .star {
|
.modal .star {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user