Skip to content

Commit 2d500a8

Browse files
committed
Manual clean-up
1 parent 74b8add commit 2d500a8

File tree

3 files changed

+51
-100
lines changed

3 files changed

+51
-100
lines changed

src/app/pages/errata-summary/errata-summary.tsx

Lines changed: 6 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,23 @@
11
import React, {useState} from 'react';
22
import Hero from './hero/hero';
33
import {RadioPanel} from '~/components/radio-panel/radio-panel';
4-
import Table from './table/table';
4+
import Table, {RawErrataItem} from './table/table';
55
import LoaderPage from '~/components/jsx-helpers/loader-page';
66
import './errata-summary.scss';
77

8-
type RadioItem = {
9-
value: string;
10-
html: string;
11-
};
12-
13-
type ErrataData = {
14-
id: string;
15-
created: string;
16-
resource: string;
17-
resourceOther?: string;
18-
errorType: string;
19-
errorTypeOther?: string;
20-
location: string;
21-
additionalLocationInformation?: string;
22-
detail: string;
23-
modified: string;
24-
};
25-
268
type ErrataSummaryProps = {
27-
data: ErrataData[];
9+
data: RawErrataItem[];
2810
book: string;
2911
};
3012

31-
const radioItems: RadioItem[] = [
13+
const radioItems = [
3214
{value: '', html: 'View All'},
3315
{value: 'in-review', html: 'In Review'},
3416
{value: 'reviewed', html: 'Reviewed'},
3517
{value: 'corrected', html: 'Corrected'}
3618
];
3719

38-
function ErrataSummary({data, book}: ErrataSummaryProps): React.ReactElement {
20+
function ErrataSummary({data, book}: ErrataSummaryProps) {
3921
const initialValue: string = window.location.hash.replace('#', '');
4022
const [selectedFilter, setselectedFilter] = useState<string>(initialValue);
4123
const onChange = React.useCallback(
@@ -70,7 +52,7 @@ function ErrataSummary({data, book}: ErrataSummaryProps): React.ReactElement {
7052
);
7153
}
7254

73-
export default function ErrataSummaryLoader(): React.ReactElement {
55+
export default function ErrataSummaryLoader() {
7456
const book: string | null = new window.URLSearchParams(window.location.search).get('book');
7557
const slug: string = `errata/?book_title=${book}` +
7658
'&is_assessment_errata__not=Yes&archived=False&status__not=New' +
@@ -81,4 +63,4 @@ export default function ErrataSummaryLoader(): React.ReactElement {
8163
<LoaderPage slug={slug} Child={ErrataSummary} props={{book: book || ''}} />
8264
</main>
8365
);
84-
}
66+
}

src/app/pages/errata-summary/hero/hero.tsx

Lines changed: 21 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -8,49 +8,31 @@ import useRouterContext from '~/components/shell/router-context';
88
import cn from 'classnames';
99
import './hero.scss';
1010

11-
interface BookEntry {
12-
title: string;
13-
meta: {
14-
slug: string;
15-
};
16-
}
17-
18-
interface HeroData {
11+
type HeroData = {
1912
aboutHeader: string;
2013
aboutText: string;
2114
aboutPopup: string;
2215
}
2316

24-
interface HeroProps {
17+
type HeroProps = {
2518
book: string;
2619
}
2720

28-
interface HeroContentProps {
21+
type HeroContentProps = {
2922
data: HeroData;
3023
}
3124

32-
interface PopTipProps {
25+
type PopTipProps = {
3326
html: string;
3427
isOpen: boolean;
3528
}
3629

37-
interface PopTipState {
38-
isOpen: boolean;
39-
activate: () => void;
40-
deactivate: () => void;
41-
}
42-
43-
interface PopTipStyleResult {
44-
ref: React.RefObject<HTMLDivElement>;
45-
style: { left: number | string };
46-
}
47-
4830
function useBookInfo(book: string): [string, string] {
4931
const [info, setInfo] = useState<[string, string]>(['', '']);
5032
const {fail} = useRouterContext();
5133

5234
useEffect(() => {
53-
bookPromise.then((bookList: BookEntry[]) => {
35+
bookPromise.then((bookList) => {
5436
const entry = bookList.find(({title}) => title === book);
5537

5638
if (entry) {
@@ -71,27 +53,28 @@ const middle: string = '-135';
7153
const margin: number = 3;
7254

7355
function shiftIntoView(
74-
ref: React.RefObject<HTMLDivElement>,
75-
leftOffset: number | string,
56+
ref: React.RefObject<HTMLDivElement>,
57+
leftOffset: number | string,
7658
setLeftOffset: (value: number | string) => void
77-
): void {
78-
if (!ref.current) return;
79-
59+
) {
60+
if (!ref.current) {return;}
61+
8062
const {left, right} = ref.current.getBoundingClientRect();
8163
const pageElement = ref.current.closest('.page');
82-
if (!pageElement) return;
83-
64+
65+
if (!pageElement) {return;}
66+
8467
const {right: pageRight} = pageElement.getBoundingClientRect();
8568
const overRight = right - pageRight + margin;
8669
const overLeft = margin - left;
87-
const leftOffsetNum = typeof leftOffset === 'string' ? parseInt(leftOffset) : leftOffset;
88-
const rightWants = Math.min(parseInt(middle), leftOffsetNum - overRight);
70+
const leftOffsetNum = typeof leftOffset === 'string' ? parseInt(leftOffset, 10) : leftOffset;
71+
const rightWants = Math.min(parseInt(middle, 10), leftOffsetNum - overRight);
8972
const leftWants = Math.max(rightWants, leftOffsetNum + overLeft);
9073

9174
setLeftOffset(leftWants);
9275
}
9376

94-
function usePopTipStyle(isOpen: boolean): PopTipStyleResult {
77+
function usePopTipStyle(isOpen: boolean) {
9578
const ref = React.useRef<HTMLDivElement>(null);
9679
const [leftOffset, setLeftOffset] = React.useState<number | string>(middle);
9780

@@ -103,7 +86,7 @@ function usePopTipStyle(isOpen: boolean): PopTipStyleResult {
10386
return {ref, style: {left: leftOffset}};
10487
}
10588

106-
function PopTip({html, isOpen}: PopTipProps): React.ReactElement {
89+
function PopTip({html, isOpen}: PopTipProps) {
10790
const {ref, style} = usePopTipStyle(isOpen);
10891

10992
return (
@@ -118,7 +101,7 @@ function PopTip({html, isOpen}: PopTipProps): React.ReactElement {
118101
);
119102
}
120103

121-
function usePopTipState(): PopTipState {
104+
function usePopTipState() {
122105
const [isOpen, setIsOpen] = React.useState<boolean>(false);
123106

124107
return {
@@ -128,7 +111,7 @@ function usePopTipState(): PopTipState {
128111
};
129112
}
130113

131-
function HeroContent({data}: HeroContentProps): React.ReactElement {
114+
function HeroContent({data}: HeroContentProps) {
132115
const {isOpen, activate, deactivate} = usePopTipState();
133116

134117
return (
@@ -151,7 +134,7 @@ function HeroContent({data}: HeroContentProps): React.ReactElement {
151134
);
152135
}
153136

154-
export default function Hero({book}: HeroProps): React.ReactElement | null {
137+
export default function Hero({book}: HeroProps) {
155138
const [slug, title] = useBookInfo(book);
156139

157140
if (!slug) {
@@ -165,4 +148,4 @@ export default function Hero({book}: HeroProps): React.ReactElement | null {
165148
</div>
166149
</div>
167150
);
168-
}
151+
}

src/app/pages/errata-summary/table/table.tsx

Lines changed: 24 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,9 @@
11
import React, {useState} from 'react';
22
import {treatSpaceOrEnterAsClick} from '~/helpers/events';
3-
import {getDisplayStatus} from '~/helpers/errata';
3+
import {getDisplayStatus, Errata} from '~/helpers/errata';
44
import './table.scss';
55

6-
type ColumnSpec = {
7-
label: string;
8-
id: string;
9-
sortFn?: string;
10-
cssClass: string;
11-
};
12-
13-
type RawErrataItem = {
6+
export type RawErrataItem = Errata & {
147
id: string;
158
created: string;
169
resource: string;
@@ -35,14 +28,7 @@ type ProcessedErrataItem = {
3528
modified: string;
3629
};
3730

38-
type SortController = {
39-
sortFn: string;
40-
sortKey: string;
41-
sortDir: number;
42-
setSortFn: (fn: string) => void;
43-
setSortKey: (key: string) => void;
44-
setSortDir: (dir: number) => void;
45-
};
31+
type SortController = ReturnType<typeof useSortController>;
4632

4733
type DesktopHeaderColumnProps = {
4834
colSpec: ColumnSpec;
@@ -85,12 +71,9 @@ type TableProps = {
8571
filter: string;
8672
};
8773

88-
type SortFn = (
89-
a: string | number | null | ProcessedErrataItem,
90-
b: string | number | null | ProcessedErrataItem
91-
) => number;
74+
type ColumnSpec = typeof columnSpecs[number];
9275

93-
const columnSpecs: ColumnSpec[] = [
76+
const columnSpecs = [
9477
{
9578
label: 'Date Submitted',
9679
id: 'date',
@@ -131,7 +114,7 @@ const columnSpecs: ColumnSpec[] = [
131114
sortFn: 'sortDecision',
132115
cssClass: 'mid'
133116
}
134-
];
117+
] as const;
135118

136119
const statusSortOrder: {[key: string]: number} = {
137120
'Co': 1,
@@ -141,7 +124,7 @@ const statusSortOrder: {[key: string]: number} = {
141124
'In': 5
142125
};
143126

144-
const sortFunctions: {[key: string]: SortFn} = {
127+
const sortFunctions = {
145128
sortDate: (a: string, b: string): number => new Date(a).getTime() - new Date(b).getTime(),
146129
sort: (a: string | null, b: string | null): number => {
147130
const as = a === null ? '' : a;
@@ -166,21 +149,22 @@ const sortFunctions: {[key: string]: SortFn} = {
166149

167150
function DesktopHeaderColumn({colSpec, sortController}: DesktopHeaderColumnProps): React.ReactElement {
168151
const {sortKey, sortDir, setSortFn, setSortDir, setSortKey} = sortController;
152+
const sortable = 'sortFn' in colSpec;
169153
const onClick = (): void => {
170154
if (sortKey === colSpec.id) {
171155
setSortDir(-sortDir);
172156
} else {
173-
if (colSpec.sortFn) {
157+
if (sortable) {
174158
setSortFn(colSpec.sortFn);
175159
}
176160
setSortKey(colSpec.id);
177161
setSortDir(1);
178162
}
179163
};
180-
const sortAttributes = colSpec.sortFn ? {
164+
const sortAttributes = sortable ? {
181165
role: 'button', tabIndex: 0, onClick, onKeyDown: treatSpaceOrEnterAsClick
182166
} : {};
183-
const sortIndicator = colSpec.sortFn ?
167+
const sortIndicator = sortable ?
184168
<span className={`will-sort sortdir${colSpec.sortFn === 'sort' ? 1 : -1}`} /> :
185169
null;
186170

@@ -204,7 +188,7 @@ function DesktopHeaderRow({sortController}: DesktopHeaderRowProps): React.ReactE
204188
return (
205189
<tr>
206190
{
207-
columnSpecs.map((colSpec: ColumnSpec) =>
191+
columnSpecs.map((colSpec) =>
208192
<DesktopHeaderColumn key={colSpec.id} colSpec={colSpec} sortController={sortController} />
209193
)
210194
}
@@ -224,7 +208,7 @@ function DesktopDataColumn({colSpec, entry}: DesktopDataColumnProps): React.Reac
224208
<React.Fragment>
225209
{entry[colSpec.id as keyof ProcessedErrataItem]}{' '}
226210
{
227-
colSpec.id === 'displayStatus' &&
211+
colSpec.id === 'displayStatus' &&
228212
entry[colSpec.id as keyof ProcessedErrataItem] === 'No Correction' &&
229213
<a href={`/errata/${entry.id}`}>Details</a>
230214
}
@@ -238,16 +222,16 @@ function DesktopDataColumn({colSpec, entry}: DesktopDataColumnProps): React.Reac
238222
function DesktopDataRow({entry}: DesktopDataRowProps): React.ReactElement {
239223
return (
240224
<tr>
241-
{columnSpecs.map((colSpec: ColumnSpec) =>
225+
{columnSpecs.map((colSpec) =>
242226
<DesktopDataColumn key={colSpec.id} colSpec={colSpec} entry={entry} />
243227
)}
244228
</tr>
245229
);
246230
}
247231

248-
function useSortController(): SortController {
249-
const [sortFn, setSortFn] = useState<string>('sortDate');
250-
const [sortKey, setSortKey] = useState<string>('date');
232+
function useSortController() {
233+
const [sortFn, setSortFn] = useState<keyof typeof sortFunctions>('sortDate');
234+
const [sortKey, setSortKey] = useState<keyof ProcessedErrataItem>('date');
251235
const [sortDir, setSortDir] = useState<number>(-1);
252236

253237
return {sortFn, sortKey, sortDir, setSortFn, setSortKey, setSortDir};
@@ -257,9 +241,11 @@ function DesktopTable({data}: DesktopTableProps): React.ReactElement {
257241
const sortController = useSortController();
258242
const {sortFn, sortKey, sortDir} = sortController;
259243

260-
const sortedData = [...data];
261-
sortedData.sort((a: ProcessedErrataItem, b: ProcessedErrataItem) =>
262-
sortFunctions[sortFn](a[sortKey as keyof ProcessedErrataItem], b[sortKey as keyof ProcessedErrataItem])
244+
const sortedData = [...data] as Array<string & ProcessedErrataItem>;
245+
246+
sortedData.sort((a, b) =>
247+
// @ts-expect-error sortKey and sortFn are guaranteed compatible
248+
sortFunctions[sortFn](a[sortKey], b[sortKey])
263249
);
264250
if (sortDir < 0) {
265251
sortedData.reverse();
@@ -301,7 +287,7 @@ function MobileTable({entry}: MobileTableProps): React.ReactElement {
301287
<table className="body-block summary-table-mobile">
302288
<tbody>
303289
{
304-
columnSpecs.map((colSpec: ColumnSpec) =>
290+
columnSpecs.map((colSpec) =>
305291
<MobileRow
306292
key={colSpec.label}
307293
entry={entry}
@@ -371,4 +357,4 @@ export default function Table({data, filter}: TableProps): React.ReactElement {
371357
<DesktopTable data={filteredDetails} />
372358
</div>
373359
);
374-
}
360+
}

0 commit comments

Comments
 (0)