-
Notifications
You must be signed in to change notification settings - Fork 0
/
Upcoming.tsx
143 lines (133 loc) · 4.22 KB
/
Upcoming.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
import {
Collapse,
IconButton,
Paper,
Table,
TableBody,
TableCell,
TableContainer,
TableHead,
TableRow,
} from '@material-ui/core';
import { KeyboardArrowDown, KeyboardArrowUp } from '@material-ui/icons';
import './Upcoming.css';
import React from 'react';
import SpacexLaunchInfo from '../SpaceX/SpacexLaunchInfo';
export interface LaunchItem {
/** Unique name for this launch */
name: string;
/** UTC date string when the launch is expected to occur */
date: string;
rocket: string;
launchpad: string;
location: string;
capsule?: string;
description?: string;
crew?: string[];
}
interface LaunchTableProps {
/**
* The list of launches to be displayed in the table
*/
items: LaunchItem[];
}
/** Formats the date to the current locale */
function formatDate(dateUtc: string): string {
const date = new Date(dateUtc);
return date.toLocaleString();
}
function hasExpandableContent(item: LaunchItem): boolean {
return (
(item?.crew !== undefined && item?.crew?.length > 0)
|| (item?.description !== undefined && item?.description?.length > 0)
);
}
/**
* React fragment specifically for the table rows so state can be maintained for detail expansion
* @param props
*/
function Row(props: { row: LaunchItem }) {
const { row } = props;
// Maintain the state for each row to know if it is expanded or not
const [open, setOpen] = React.useState(false);
const isExpandable = hasExpandableContent(row);
// Create a cell that modifies the state of the row based on if it's open or closed
const expansionCell = (
<TableCell>
<IconButton
aria-label="expand row"
size="small"
onClick={() => setOpen(!open)}
>
{open ? <KeyboardArrowUp /> : <KeyboardArrowDown />}
</IconButton>
</TableCell>
);
const expansionRow = (
// Set the class based on if you can open the row or not
<TableRow
className={`${
!open ? 'upcoming-launch-row' : 'upcoming-launch-row-expanded'
}`}
>
{/* Set the column span to 7 because there are 7 headers for the table */}
{/* If the span is not the same number of headers then weird width issues occur during expansion/collapse */}
{/* Remove the padding so it doesnt show a gap between rows */}
<TableCell style={{ paddingBottom: 0, paddingTop: 0 }} colSpan={7}>
<Collapse in={open} timeout="auto" unmountOnExit>
{isExpandable ? (
<SpacexLaunchInfo details={row.description} crewIds={row.crew} />
) : undefined}
</Collapse>
</TableCell>
</TableRow>
);
// Returns around fragment to prevent nested indentation when mapping the list during table creation
return (
<>
<TableRow className="upcoming-launch-row">
{
// Only display the expansion cell if there are children otherwise return an empty cell
isExpandable ? expansionCell : <TableCell />
}
<TableCell>{row.name}</TableCell>
<TableCell align="left">{formatDate(row.date)}</TableCell>
<TableCell align="left">{row.rocket}</TableCell>
<TableCell align="left">{row.launchpad}</TableCell>
<TableCell align="left">{row.location}</TableCell>
<TableCell align="left">{row.capsule}</TableCell>
</TableRow>
{isExpandable ? expansionRow : undefined}
</>
);
}
/**
* Creates a table that shows a list of rocket launches
* @param props
*/
const LaunchTable: React.FC<LaunchTableProps> = ({
items,
}: LaunchTableProps) => (
<TableContainer component={Paper}>
<Table className="upcoming-launch-table" aria-label="table">
<TableHead>
<TableRow className="upcoming-launch-header">
<TableCell />
{/* Created an empty cell to accomodate detail expansion, pushing name to the right */}
<TableCell>Name</TableCell>
<TableCell>Date</TableCell>
<TableCell>Rocket</TableCell>
<TableCell>Launchpad</TableCell>
<TableCell>Location</TableCell>
<TableCell>Capsule</TableCell>
</TableRow>
</TableHead>
<TableBody>
{items.map((row) => (
<Row key={row.name} row={row} />
))}
</TableBody>
</Table>
</TableContainer>
);
export default LaunchTable;