feat: implement BoardFlightBody with detailed flight information
This commit is contained in:
@@ -2,25 +2,112 @@
|
||||
padding: 16px;
|
||||
background: #fafafa;
|
||||
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 {
|
||||
margin-bottom: 16px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
.board-flight-body__section-title {
|
||||
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 {
|
||||
margin: 0 0 8px 0;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 0;
|
||||
color: #666;
|
||||
font-size: 14px;
|
||||
@media (max-width: 480px) {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
.board-flight-body__info-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
padding: 8px;
|
||||
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 { Button } from 'primereact/button'
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import './board-flight-body.scss'
|
||||
|
||||
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 }) => {
|
||||
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 (
|
||||
<div className="board-flight-body" data-testid={`flight-body-${flight.id}`}>
|
||||
<div className="board-flight-body__section">
|
||||
<h3>Departure</h3>
|
||||
<p>{flight.departure.airport} - {flight.departure.city}</p>
|
||||
<div className="board-flight-body__content">
|
||||
{/* Departure Section */}
|
||||
<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 className="board-flight-body__section">
|
||||
<h3>Arrival</h3>
|
||||
<p>{flight.arrival.airport} - {flight.arrival.city}</p>
|
||||
|
||||
{/* Action Buttons */}
|
||||
<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>
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user