feat: implement BoardFlightBody with detailed flight information
This commit is contained in:
@@ -2,25 +2,112 @@
|
|||||||
padding: 16px;
|
padding: 16px;
|
||||||
background: #fafafa;
|
background: #fafafa;
|
||||||
border-top: 1px solid #e0e0e0;
|
border-top: 1px solid #e0e0e0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.board-flight-body__content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.board-flight-body__section {
|
.board-flight-body__section {
|
||||||
margin-bottom: 16px;
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
&:last-child {
|
.board-flight-body__section-title {
|
||||||
margin-bottom: 0;
|
margin: 0;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #666;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.board-flight-body__info-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
|
||||||
|
gap: 12px;
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
}
|
}
|
||||||
|
|
||||||
h3 {
|
@media (max-width: 480px) {
|
||||||
margin: 0 0 8px 0;
|
grid-template-columns: 1fr;
|
||||||
font-size: 14px;
|
}
|
||||||
font-weight: 600;
|
}
|
||||||
color: #333;
|
|
||||||
}
|
.board-flight-body__info-item {
|
||||||
|
display: flex;
|
||||||
p {
|
flex-direction: column;
|
||||||
margin: 0;
|
gap: 4px;
|
||||||
color: #666;
|
padding: 8px;
|
||||||
font-size: 14px;
|
background: white;
|
||||||
|
border-radius: 4px;
|
||||||
|
border: 1px solid #e0e0e0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.board-flight-body__label {
|
||||||
|
font-size: 11px;
|
||||||
|
color: #999;
|
||||||
|
text-transform: uppercase;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.board-flight-body__value {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #333;
|
||||||
|
font-weight: 500;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.board-flight-body__city {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #999;
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
|
||||||
|
.board-flight-body__actual {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #f57c00;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.board-flight-body__codesharing-list {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.board-flight-body__codeshare-badge {
|
||||||
|
padding: 4px 10px;
|
||||||
|
background: #e3f2fd;
|
||||||
|
color: #1565c0;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.board-flight-body__actions {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
justify-content: flex-end;
|
||||||
|
padding-top: 8px;
|
||||||
|
border-top: 1px solid #e0e0e0;
|
||||||
|
|
||||||
|
:global {
|
||||||
|
.p-button {
|
||||||
|
&.p-button-sm {
|
||||||
|
padding: 6px 12px;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,20 +1,186 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
import { Button } from 'primereact/button'
|
||||||
|
import { useNavigate } from 'react-router-dom'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
import './board-flight-body.scss'
|
import './board-flight-body.scss'
|
||||||
|
|
||||||
export interface BoardFlightBodyProps {
|
export interface BoardFlightBodyProps {
|
||||||
flight: any
|
flight: {
|
||||||
|
id: string
|
||||||
|
flightNumber: string
|
||||||
|
departure: {
|
||||||
|
airport: string
|
||||||
|
city: string
|
||||||
|
scheduled: string
|
||||||
|
actual?: string
|
||||||
|
terminal?: string
|
||||||
|
gate?: string
|
||||||
|
}
|
||||||
|
arrival: {
|
||||||
|
airport: string
|
||||||
|
city: string
|
||||||
|
scheduled: string
|
||||||
|
actual?: string
|
||||||
|
terminal?: string
|
||||||
|
gate?: string
|
||||||
|
}
|
||||||
|
boarding?: {
|
||||||
|
time: string
|
||||||
|
gate: string
|
||||||
|
}
|
||||||
|
deboarding?: {
|
||||||
|
time: string
|
||||||
|
gate: string
|
||||||
|
}
|
||||||
|
codesharing?: string[]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const BoardFlightBody: React.FC<BoardFlightBodyProps> = ({ flight }) => {
|
export const BoardFlightBody: React.FC<BoardFlightBodyProps> = ({ flight }) => {
|
||||||
|
const navigate = useNavigate()
|
||||||
|
const { t } = useTranslation()
|
||||||
|
|
||||||
|
const handleViewDetails = () => {
|
||||||
|
// Navigate to full flight details page
|
||||||
|
const params = btoa(JSON.stringify({ id: flight.id, flightNumber: flight.flightNumber }))
|
||||||
|
navigate(`/onlineboard/${params}`)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="board-flight-body" data-testid={`flight-body-${flight.id}`}>
|
<div className="board-flight-body" data-testid={`flight-body-${flight.id}`}>
|
||||||
<div className="board-flight-body__section">
|
<div className="board-flight-body__content">
|
||||||
<h3>Departure</h3>
|
{/* Departure Section */}
|
||||||
<p>{flight.departure.airport} - {flight.departure.city}</p>
|
<div className="board-flight-body__section">
|
||||||
|
<h4 className="board-flight-body__section-title">{t('SHARED.DEPARTURE')}</h4>
|
||||||
|
<div className="board-flight-body__info-grid">
|
||||||
|
<div className="board-flight-body__info-item">
|
||||||
|
<span className="board-flight-body__label">{t('SHARED.AIRPORT')}</span>
|
||||||
|
<span className="board-flight-body__value">
|
||||||
|
{flight.departure.airport}
|
||||||
|
<span className="board-flight-body__city">{flight.departure.city}</span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className="board-flight-body__info-item">
|
||||||
|
<span className="board-flight-body__label">{t('SHARED.TIME')}</span>
|
||||||
|
<span className="board-flight-body__value">
|
||||||
|
{flight.departure.scheduled}
|
||||||
|
{flight.departure.actual && (
|
||||||
|
<span className="board-flight-body__actual">{flight.departure.actual}</span>
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
{flight.departure.terminal && (
|
||||||
|
<div className="board-flight-body__info-item">
|
||||||
|
<span className="board-flight-body__label">{t('SHARED.TERMINAL')}</span>
|
||||||
|
<span className="board-flight-body__value">{flight.departure.terminal}</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{flight.departure.gate && (
|
||||||
|
<div className="board-flight-body__info-item">
|
||||||
|
<span className="board-flight-body__label">{t('SHARED.GATE')}</span>
|
||||||
|
<span className="board-flight-body__value">{flight.departure.gate}</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Boarding Section */}
|
||||||
|
{flight.boarding && (
|
||||||
|
<div className="board-flight-body__section">
|
||||||
|
<h4 className="board-flight-body__section-title">{t('BOARD.BOARDING')}</h4>
|
||||||
|
<div className="board-flight-body__info-grid">
|
||||||
|
<div className="board-flight-body__info-item">
|
||||||
|
<span className="board-flight-body__label">{t('SHARED.TIME')}</span>
|
||||||
|
<span className="board-flight-body__value">{flight.boarding.time}</span>
|
||||||
|
</div>
|
||||||
|
{flight.boarding.gate && (
|
||||||
|
<div className="board-flight-body__info-item">
|
||||||
|
<span className="board-flight-body__label">{t('SHARED.GATE')}</span>
|
||||||
|
<span className="board-flight-body__value">{flight.boarding.gate}</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Arrival Section */}
|
||||||
|
<div className="board-flight-body__section">
|
||||||
|
<h4 className="board-flight-body__section-title">{t('SHARED.ARRIVAL')}</h4>
|
||||||
|
<div className="board-flight-body__info-grid">
|
||||||
|
<div className="board-flight-body__info-item">
|
||||||
|
<span className="board-flight-body__label">{t('SHARED.AIRPORT')}</span>
|
||||||
|
<span className="board-flight-body__value">
|
||||||
|
{flight.arrival.airport}
|
||||||
|
<span className="board-flight-body__city">{flight.arrival.city}</span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className="board-flight-body__info-item">
|
||||||
|
<span className="board-flight-body__label">{t('SHARED.TIME')}</span>
|
||||||
|
<span className="board-flight-body__value">
|
||||||
|
{flight.arrival.scheduled}
|
||||||
|
{flight.arrival.actual && (
|
||||||
|
<span className="board-flight-body__actual">{flight.arrival.actual}</span>
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
{flight.arrival.terminal && (
|
||||||
|
<div className="board-flight-body__info-item">
|
||||||
|
<span className="board-flight-body__label">{t('SHARED.TERMINAL')}</span>
|
||||||
|
<span className="board-flight-body__value">{flight.arrival.terminal}</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{flight.arrival.gate && (
|
||||||
|
<div className="board-flight-body__info-item">
|
||||||
|
<span className="board-flight-body__label">{t('SHARED.GATE')}</span>
|
||||||
|
<span className="board-flight-body__value">{flight.arrival.gate}</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Deboarding Section */}
|
||||||
|
{flight.deboarding && (
|
||||||
|
<div className="board-flight-body__section">
|
||||||
|
<h4 className="board-flight-body__section-title">{t('BOARD.DEBOARDING')}</h4>
|
||||||
|
<div className="board-flight-body__info-grid">
|
||||||
|
<div className="board-flight-body__info-item">
|
||||||
|
<span className="board-flight-body__label">{t('SHARED.TIME')}</span>
|
||||||
|
<span className="board-flight-body__value">{flight.deboarding.time}</span>
|
||||||
|
</div>
|
||||||
|
{flight.deboarding.gate && (
|
||||||
|
<div className="board-flight-body__info-item">
|
||||||
|
<span className="board-flight-body__label">{t('SHARED.GATE')}</span>
|
||||||
|
<span className="board-flight-body__value">{flight.deboarding.gate}</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Codesharing Section */}
|
||||||
|
{flight.codesharing && flight.codesharing.length > 0 && (
|
||||||
|
<div className="board-flight-body__section">
|
||||||
|
<h4 className="board-flight-body__section-title">{t('BOARD.CODESHARING')}</h4>
|
||||||
|
<div className="board-flight-body__codesharing-list">
|
||||||
|
{flight.codesharing.map((code, idx) => (
|
||||||
|
<span key={idx} className="board-flight-body__codeshare-badge">
|
||||||
|
{code}
|
||||||
|
</span>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="board-flight-body__section">
|
|
||||||
<h3>Arrival</h3>
|
{/* Action Buttons */}
|
||||||
<p>{flight.arrival.airport} - {flight.arrival.city}</p>
|
<div className="board-flight-body__actions">
|
||||||
|
<Button
|
||||||
|
label={t('BOARD.VIEW_DETAILS')}
|
||||||
|
icon="pi pi-arrow-right"
|
||||||
|
onClick={handleViewDetails}
|
||||||
|
className="p-button-sm"
|
||||||
|
data-testid={`flight-details-button-${flight.id}`}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user