From 0ddd46643b63859fabd577ff3b36ee8bc511704c Mon Sep 17 00:00:00 2001 From: DrMint Date: Fri, 9 Dec 2022 23:03:09 +0100 Subject: [PATCH] Moved assert helpers into their own folder + activated some tsconfig strict options --- src/components/AppLayout.tsx | 4 +- .../Chronicles/ChroniclePreview.tsx | 2 +- src/components/Chronicles/ChroniclesList.tsx | 2 +- src/components/Cli/Terminal.tsx | 2 +- src/components/Inputs/Button.tsx | 2 +- src/components/Inputs/ButtonGroup.tsx | 2 +- src/components/Inputs/Link.tsx | 2 +- src/components/Inputs/OrderableList.tsx | 16 +- src/components/Inputs/TextInput.tsx | 2 +- src/components/Inputs/WithLabel.tsx | 2 +- src/components/LightBox.tsx | 2 +- src/components/Markdown/Markdawn.tsx | 18 +- src/components/PanelComponents/NavOption.tsx | 2 +- .../PanelComponents/PanelHeader.tsx | 2 +- .../PanelComponents/ReturnButton.tsx | 4 +- src/components/Panels/MainPanel.tsx | 2 +- src/components/Panels/SettingsPopup.tsx | 14 +- src/components/PostPage.tsx | 3 +- src/components/PreviewLine.tsx | 2 +- src/components/RecorderChip.tsx | 2 +- src/components/SmartList.tsx | 18 +- src/components/ThumbnailHeader.tsx | 2 +- src/contexts/LightBoxProvider.tsx | 2 +- src/contexts/settings.ts | 2 +- src/contexts/webkitFixes.ts | 2 +- src/graphql/getPostStaticProps.ts | 4 +- src/helpers/asserts.ts | 79 +++++++++ src/helpers/component.tsx | 2 +- src/helpers/date.ts | 2 +- src/helpers/description.ts | 2 +- src/helpers/formatters.ts | 4 +- src/helpers/img.ts | 12 +- src/helpers/libraryItem.ts | 2 +- src/helpers/locales.ts | 2 +- src/helpers/openGraph.ts | 2 +- src/helpers/others.ts | 48 +----- src/helpers/terminal.ts | 2 +- src/hooks/useFullscreen.ts | 2 +- src/hooks/useIntersectionList.ts | 12 +- src/hooks/useOnResize.ts | 11 +- src/hooks/useScrollIntoView.ts | 2 +- src/hooks/useSmartLanguage.ts | 2 +- src/pages/api/revalidate.ts | 17 +- src/pages/archives/videos/c/[uid].tsx | 4 +- src/pages/archives/videos/index.tsx | 2 +- src/pages/archives/videos/v/[uid].tsx | 2 +- src/pages/chronicles/[slug]/index.tsx | 4 +- src/pages/chronicles/index.tsx | 2 +- src/pages/contents/[slug].tsx | 7 +- src/pages/contents/all.tsx | 8 +- src/pages/contents/folder/[slug].tsx | 2 +- src/pages/dev/checkup/contents.tsx | 5 +- src/pages/dev/checkup/libraryitems.tsx | 5 +- src/pages/dev/showcase/design-system.tsx | 7 +- src/pages/dev/transcript.tsx | 2 +- src/pages/library/[slug]/index.tsx | 4 +- src/pages/library/[slug]/reader.tsx | 154 ++++++++---------- src/pages/library/index.tsx | 16 +- src/pages/news/[slug].tsx | 2 +- src/pages/news/index.tsx | 2 +- src/pages/wiki/[slug]/index.tsx | 2 +- src/pages/wiki/chronology.tsx | 12 +- src/pages/wiki/index.tsx | 8 +- src/types/SelectiveNonNullable.ts | 39 ----- tsconfig.json | 7 +- 65 files changed, 314 insertions(+), 302 deletions(-) create mode 100644 src/helpers/asserts.ts delete mode 100644 src/types/SelectiveNonNullable.ts diff --git a/src/components/AppLayout.tsx b/src/components/AppLayout.tsx index df788cf..2a2a1b8 100644 --- a/src/components/AppLayout.tsx +++ b/src/components/AppLayout.tsx @@ -3,7 +3,7 @@ import { useSwipeable } from "react-swipeable"; import { layout } from "../../design.config"; import { Ico, Icon } from "./Ico"; import { MainPanel } from "./Panels/MainPanel"; -import { isDefined, isUndefined } from "helpers/others"; +import { isDefined, isUndefined } from "helpers/asserts"; import { cIf, cJoin } from "helpers/className"; import { OpenGraph, TITLE_PREFIX, TITLE_SEPARATOR } from "helpers/openGraph"; import { Ids } from "types/ids"; @@ -239,7 +239,7 @@ const ContentPlaceholder = ({ message, icon }: ContentPlaceholderProps): JSX.Ele className="grid grid-flow-col place-items-center gap-9 rounded-2xl border-2 border-dotted border-dark p-8 text-dark opacity-40"> {isDefined(icon) && } -

{message}

+

{message}

); diff --git a/src/components/Chronicles/ChroniclePreview.tsx b/src/components/Chronicles/ChroniclePreview.tsx index 320b4f6..f718b55 100644 --- a/src/components/Chronicles/ChroniclePreview.tsx +++ b/src/components/Chronicles/ChroniclePreview.tsx @@ -3,7 +3,7 @@ import { DatePickerFragment } from "graphql/generated"; import { TranslatedProps } from "types/TranslatedProps"; import { useSmartLanguage } from "hooks/useSmartLanguage"; import { DownPressable } from "components/Containers/DownPressable"; -import { isDefined } from "helpers/others"; +import { isDefined } from "helpers/asserts"; import { cIf, cJoin } from "helpers/className"; /* diff --git a/src/components/Chronicles/ChroniclesList.tsx b/src/components/Chronicles/ChroniclesList.tsx index eb6a64c..b39faab 100644 --- a/src/components/Chronicles/ChroniclesList.tsx +++ b/src/components/Chronicles/ChroniclesList.tsx @@ -2,7 +2,7 @@ import { useCallback } from "react"; import { useBoolean } from "usehooks-ts"; import { TranslatedChroniclePreview } from "./ChroniclePreview"; import { GetChroniclesChaptersQuery } from "graphql/generated"; -import { filterHasAttributes } from "helpers/others"; +import { filterHasAttributes } from "helpers/asserts"; import { prettyInlineTitle, prettySlug, sJoin } from "helpers/formatters"; import { Ico, Icon } from "components/Ico"; import { compareDate } from "helpers/date"; diff --git a/src/components/Cli/Terminal.tsx b/src/components/Cli/Terminal.tsx index c28dda7..5a91c09 100644 --- a/src/components/Cli/Terminal.tsx +++ b/src/components/Cli/Terminal.tsx @@ -1,7 +1,7 @@ import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { useRouter } from "next/router"; import { cJoin, cIf } from "helpers/className"; -import { isDefined, isDefinedAndNotEmpty } from "helpers/others"; +import { isDefined, isDefinedAndNotEmpty } from "helpers/asserts"; import { atoms } from "contexts/atoms"; import { useAtomSetter, useAtomPair } from "helpers/atoms"; diff --git a/src/components/Inputs/Button.tsx b/src/components/Inputs/Button.tsx index 078bbfa..6d3186e 100644 --- a/src/components/Inputs/Button.tsx +++ b/src/components/Inputs/Button.tsx @@ -2,7 +2,7 @@ import { MouseEventHandler, useCallback } from "react"; import { Link } from "./Link"; import { Ico, Icon } from "components/Ico"; import { cIf, cJoin } from "helpers/className"; -import { isDefined, isDefinedAndNotEmpty } from "helpers/others"; +import { isDefined, isDefinedAndNotEmpty } from "helpers/asserts"; import { TranslatedProps } from "types/TranslatedProps"; import { useSmartLanguage } from "hooks/useSmartLanguage"; diff --git a/src/components/Inputs/ButtonGroup.tsx b/src/components/Inputs/ButtonGroup.tsx index 9c27981..bd9566f 100644 --- a/src/components/Inputs/ButtonGroup.tsx +++ b/src/components/Inputs/ButtonGroup.tsx @@ -2,7 +2,7 @@ import { Button } from "./Button"; import { ToolTip } from "components/ToolTip"; import { cJoin } from "helpers/className"; import { ConditionalWrapper, Wrapper } from "helpers/component"; -import { isDefinedAndNotEmpty } from "helpers/others"; +import { isDefinedAndNotEmpty } from "helpers/asserts"; /* * ╭─────────────╮ diff --git a/src/components/Inputs/Link.tsx b/src/components/Inputs/Link.tsx index da27dae..92faa4a 100644 --- a/src/components/Inputs/Link.tsx +++ b/src/components/Inputs/Link.tsx @@ -1,7 +1,7 @@ import React, { MouseEventHandler } from "react"; import NextLink from "next/link"; import { ConditionalWrapper, Wrapper } from "helpers/component"; -import { isDefinedAndNotEmpty } from "helpers/others"; +import { isDefinedAndNotEmpty } from "helpers/asserts"; import { cIf, cJoin } from "helpers/className"; interface Props { diff --git a/src/components/Inputs/OrderableList.tsx b/src/components/Inputs/OrderableList.tsx index 937bae0..fbcf738 100644 --- a/src/components/Inputs/OrderableList.tsx +++ b/src/components/Inputs/OrderableList.tsx @@ -1,6 +1,7 @@ import { Fragment, useCallback } from "react"; import { Ico, Icon } from "components/Ico"; -import { arrayMove, isDefinedAndNotEmpty } from "helpers/others"; +import { arrayMove } from "helpers/others"; +import { isDefinedAndNotEmpty } from "helpers/asserts"; /* * ╭─────────────╮ @@ -16,6 +17,14 @@ interface Props { // ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ +interface InsertedLabelProps { + label?: string; +} + +const InsertedLabel = ({ label }: InsertedLabelProps) => ( + <>{isDefinedAndNotEmpty(label) &&

{label}

} +); + export const OrderableList = ({ onChange, items, insertLabels }: Props): JSX.Element => { const updateOrder = useCallback( (sourceIndex: number, targetIndex: number) => { @@ -29,9 +38,8 @@ export const OrderableList = ({ onChange, items, insertLabels }: Props): JSX.Ele
{items.map((item, index) => ( - {insertLabels && isDefinedAndNotEmpty(insertLabels[index]?.name) && ( -

{insertLabels[index].name}

- )} + +
{ const source = event.target as HTMLElement; diff --git a/src/components/Inputs/TextInput.tsx b/src/components/Inputs/TextInput.tsx index b1a153a..abadefd 100644 --- a/src/components/Inputs/TextInput.tsx +++ b/src/components/Inputs/TextInput.tsx @@ -1,6 +1,6 @@ import { Ico, Icon } from "components/Ico"; import { cIf, cJoin } from "helpers/className"; -import { isDefinedAndNotEmpty } from "helpers/others"; +import { isDefinedAndNotEmpty } from "helpers/asserts"; /* * ╭─────────────╮ diff --git a/src/components/Inputs/WithLabel.tsx b/src/components/Inputs/WithLabel.tsx index b91cb67..dea2069 100644 --- a/src/components/Inputs/WithLabel.tsx +++ b/src/components/Inputs/WithLabel.tsx @@ -1,5 +1,5 @@ import { cIf, cJoin } from "helpers/className"; -import { isDefinedAndNotEmpty } from "helpers/others"; +import { isDefinedAndNotEmpty } from "helpers/asserts"; /* * ╭─────────────╮ diff --git a/src/components/LightBox.tsx b/src/components/LightBox.tsx index bd121f4..a105a19 100644 --- a/src/components/LightBox.tsx +++ b/src/components/LightBox.tsx @@ -9,7 +9,7 @@ import { useFullscreen } from "hooks/useFullscreen"; import { Ids } from "types/ids"; import { UploadImageFragment } from "graphql/generated"; import { ImageQuality } from "helpers/img"; -import { isDefined } from "helpers/others"; +import { isDefined } from "helpers/asserts"; import { useAtomGetter } from "helpers/atoms"; import { atoms } from "contexts/atoms"; diff --git a/src/components/Markdown/Markdawn.tsx b/src/components/Markdown/Markdawn.tsx index 8a86e54..5e176a0 100644 --- a/src/components/Markdown/Markdawn.tsx +++ b/src/components/Markdown/Markdawn.tsx @@ -7,7 +7,7 @@ import { InsetBox } from "components/Containers/InsetBox"; import { cIf, cJoin } from "helpers/className"; import { slugify } from "helpers/formatters"; import { getAssetURL, ImageQuality } from "helpers/img"; -import { isDefined, isDefinedAndNotEmpty, isUndefined } from "helpers/others"; +import { isDefined, isDefinedAndNotEmpty, isUndefined } from "helpers/asserts"; import { AnchorShare } from "components/AnchorShare"; import { useIntersectionList } from "hooks/useIntersectionList"; import { Ico, Icon } from "components/Ico"; @@ -459,7 +459,7 @@ const getTocFromMarkdawn = (text: string, title?: string): TocInterface => { h5 = -1; scenebreak = 0; } else if (h2 >= 0 && line.startsWith('
{ h5 = -1; scenebreak = 0; } else if (h3 >= 0 && line.startsWith('
{ h5 = -1; scenebreak = 0; } else if (h4 >= 0 && line.startsWith('
{ h5++; scenebreak = 0; } else if (h5 >= 0 && line.startsWith('
{ }; if (h5 >= 0) { - toc.children[h2].children[h3].children[h4].children[h5].children.push(child); + toc.children[h2]?.children[h3]?.children[h4]?.children[h5]?.children.push(child); } else if (h4 >= 0) { - toc.children[h2].children[h3].children[h4].children.push(child); + toc.children[h2]?.children[h3]?.children[h4]?.children.push(child); } else if (h3 >= 0) { - toc.children[h2].children[h3].children.push(child); + toc.children[h2]?.children[h3]?.children.push(child); } else if (h2 >= 0) { - toc.children[h2].children.push(child); + toc.children[h2]?.children.push(child); } else { toc.children.push(child); } diff --git a/src/components/PanelComponents/NavOption.tsx b/src/components/PanelComponents/NavOption.tsx index d343120..6319765 100644 --- a/src/components/PanelComponents/NavOption.tsx +++ b/src/components/PanelComponents/NavOption.tsx @@ -3,7 +3,7 @@ import { MouseEventHandler, useCallback } from "react"; import { Ico, Icon } from "components/Ico"; import { ToolTip } from "components/ToolTip"; import { cIf, cJoin } from "helpers/className"; -import { isDefinedAndNotEmpty } from "helpers/others"; +import { isDefinedAndNotEmpty } from "helpers/asserts"; import { TranslatedProps } from "types/TranslatedProps"; import { useSmartLanguage } from "hooks/useSmartLanguage"; import { DownPressable } from "components/Containers/DownPressable"; diff --git a/src/components/PanelComponents/PanelHeader.tsx b/src/components/PanelComponents/PanelHeader.tsx index a134207..039d6b2 100644 --- a/src/components/PanelComponents/PanelHeader.tsx +++ b/src/components/PanelComponents/PanelHeader.tsx @@ -1,5 +1,5 @@ import { Ico, Icon } from "components/Ico"; -import { isDefinedAndNotEmpty } from "helpers/others"; +import { isDefinedAndNotEmpty } from "helpers/asserts"; /* * ╭─────────────╮ diff --git a/src/components/PanelComponents/ReturnButton.tsx b/src/components/PanelComponents/ReturnButton.tsx index f499a65..3edd732 100644 --- a/src/components/PanelComponents/ReturnButton.tsx +++ b/src/components/PanelComponents/ReturnButton.tsx @@ -3,7 +3,7 @@ import { Icon } from "components/Ico"; import { Button } from "components/Inputs/Button"; import { TranslatedProps } from "types/TranslatedProps"; import { useSmartLanguage } from "hooks/useSmartLanguage"; -import { isDefined } from "helpers/others"; +import { isUndefined } from "helpers/asserts"; import { atoms } from "contexts/atoms"; import { useAtomGetter } from "helpers/atoms"; @@ -30,7 +30,7 @@ export const ReturnButton = ({ href, title, displayOnlyOn, className }: Props): <> {((is3ColumnsLayout && displayOnlyOn === "3ColumnsLayout") || (!is3ColumnsLayout && displayOnlyOn === "1ColumnLayout") || - !isDefined(displayOnlyOn)) && ( + isUndefined(displayOnlyOn)) && (
diff --git a/src/components/Panels/MainPanel.tsx b/src/components/Panels/MainPanel.tsx index 0d69f96..48accf6 100644 --- a/src/components/Panels/MainPanel.tsx +++ b/src/components/Panels/MainPanel.tsx @@ -4,7 +4,7 @@ import { NavOption } from "components/PanelComponents/NavOption"; import { ToolTip } from "components/ToolTip"; import { Icon } from "components/Ico"; import { cIf, cJoin } from "helpers/className"; -import { isDefinedAndNotEmpty } from "helpers/others"; +import { isDefinedAndNotEmpty } from "helpers/asserts"; import { Link } from "components/Inputs/Link"; import { sendAnalytics } from "helpers/analytics"; import { ColoredSvg } from "components/ColoredSvg"; diff --git a/src/components/Panels/SettingsPopup.tsx b/src/components/Panels/SettingsPopup.tsx index 79a1c0c..9f6cdef 100644 --- a/src/components/Panels/SettingsPopup.tsx +++ b/src/components/Panels/SettingsPopup.tsx @@ -10,7 +10,7 @@ import { Popup } from "components/Containers/Popup"; import { sendAnalytics } from "helpers/analytics"; import { cJoin, cIf } from "helpers/className"; import { prettyLanguage } from "helpers/formatters"; -import { filterHasAttributes, isDefined } from "helpers/others"; +import { filterHasAttributes, isDefined } from "helpers/asserts"; import { atoms } from "contexts/atoms"; import { useAtomGetter, useAtomPair } from "helpers/atoms"; import { ThemeMode } from "contexts/settings"; @@ -39,15 +39,10 @@ export const SettingsPopup = (): JSX.Element => { ); const [currencySelect, setCurrencySelect] = useState(-1); - useEffect(() => { if (isDefined(currency)) setCurrencySelect(currencyOptions.indexOf(currency)); }, [currency, currencyOptions]); - useEffect(() => { - if (currencySelect >= 0) setCurrency(currencyOptions[currencySelect]); - }, [currencyOptions, currencySelect, setCurrency]); - return ( { options={currencyOptions} value={currencySelect} onChange={(newCurrency) => { - setCurrencySelect(newCurrency); - sendAnalytics("Settings", `Change currency (${currencyOptions[newCurrency]})}`); + const newCurrencyName = currencyOptions[newCurrency]; + if (isDefined(newCurrencyName)) { + setCurrency(newCurrencyName); + sendAnalytics("Settings", `Change currency (${currencyOptions[newCurrency]})}`); + } }} className="w-28" /> diff --git a/src/components/PostPage.tsx b/src/components/PostPage.tsx index 20dffda..9bd3688 100644 --- a/src/components/PostPage.tsx +++ b/src/components/PostPage.tsx @@ -11,7 +11,8 @@ import { ThumbnailHeader } from "./ThumbnailHeader"; import { ToolTip } from "./ToolTip"; import { useSmartLanguage } from "hooks/useSmartLanguage"; import { PostWithTranslations } from "types/types"; -import { filterHasAttributes, getStatusDescription } from "helpers/others"; +import { getStatusDescription } from "helpers/others"; +import { filterHasAttributes } from "helpers/asserts"; import { prettySlug } from "helpers/formatters"; import { atoms } from "contexts/atoms"; import { useAtomGetter } from "helpers/atoms"; diff --git a/src/components/PreviewLine.tsx b/src/components/PreviewLine.tsx index 313f82e..dcc3fd5 100644 --- a/src/components/PreviewLine.tsx +++ b/src/components/PreviewLine.tsx @@ -7,7 +7,7 @@ import { ImageQuality } from "helpers/img"; import { TranslatedProps } from "types/TranslatedProps"; import { useSmartLanguage } from "hooks/useSmartLanguage"; import { cIf, cJoin } from "helpers/className"; -import { isDefined } from "helpers/others"; +import { isDefined } from "helpers/asserts"; /* * ╭─────────────╮ diff --git a/src/components/RecorderChip.tsx b/src/components/RecorderChip.tsx index 6101eac..ec4a452 100644 --- a/src/components/RecorderChip.tsx +++ b/src/components/RecorderChip.tsx @@ -5,7 +5,7 @@ import { ToolTip } from "./ToolTip"; import { Chip } from "components/Chip"; import { RecorderChipFragment } from "graphql/generated"; import { ImageQuality } from "helpers/img"; -import { filterHasAttributes } from "helpers/others"; +import { filterHasAttributes } from "helpers/asserts"; import { atoms } from "contexts/atoms"; import { useAtomGetter } from "helpers/atoms"; diff --git a/src/components/SmartList.tsx b/src/components/SmartList.tsx index 21b2db0..356ad8d 100644 --- a/src/components/SmartList.tsx +++ b/src/components/SmartList.tsx @@ -5,7 +5,7 @@ import { Chip } from "./Chip"; import { PageSelector } from "./Inputs/PageSelector"; import { Ico, Icon } from "./Ico"; import { cJoin } from "helpers/className"; -import { isDefined, isDefinedAndNotEmpty } from "helpers/others"; +import { isDefined, isDefinedAndNotEmpty } from "helpers/asserts"; import { useScrollTopOnChange } from "hooks/useScrollTopOnChange"; import { Ids } from "types/ids"; import { atoms } from "contexts/atoms"; @@ -95,17 +95,17 @@ export const SmartList = ({ const memo: Group[] = []; sortedItem.forEach((item) => { - groupingFunction(item).forEach((category) => { - const index = memo.findIndex((group) => group.name === category); - if (index === -1) { + groupingFunction(item).forEach((groupName) => { + const group = memo.find((elem) => elem.name === groupName); + if (isDefined(group)) { + group.items.push(item); + group.totalCount += groupCountingFunction(item); + } else { memo.push({ - name: category, + name: groupName, items: [item], totalCount: groupCountingFunction(item), }); - } else { - memo[index].items.push(item); - memo[index].totalCount += groupCountingFunction(item); } }); }); @@ -170,7 +170,7 @@ export const SmartList = ({ )}
- {pages[page]?.length > 0 ? ( + {(pages[page]?.length ?? 0) > 0 ? ( pages[page]?.map( (group) => group.items.length > 0 && ( diff --git a/src/components/ThumbnailHeader.tsx b/src/components/ThumbnailHeader.tsx index 993f148..7bbed9e 100644 --- a/src/components/ThumbnailHeader.tsx +++ b/src/components/ThumbnailHeader.tsx @@ -5,7 +5,7 @@ import { Markdawn } from "components/Markdown/Markdawn"; import { GetContentTextQuery, UploadImageFragment } from "graphql/generated"; import { prettyInlineTitle, prettySlug, slugify } from "helpers/formatters"; import { ImageQuality } from "helpers/img"; -import { filterHasAttributes } from "helpers/others"; +import { filterHasAttributes } from "helpers/asserts"; import { useAtomGetter } from "helpers/atoms"; import { atoms } from "contexts/atoms"; diff --git a/src/contexts/LightBoxProvider.tsx b/src/contexts/LightBoxProvider.tsx index ca36116..1a09ea5 100644 --- a/src/contexts/LightBoxProvider.tsx +++ b/src/contexts/LightBoxProvider.tsx @@ -3,7 +3,7 @@ import { useEffectOnce } from "usehooks-ts"; import { atom } from "jotai"; import { UploadImageFragment } from "graphql/generated"; import { LightBox } from "components/LightBox"; -import { filterDefined } from "helpers/others"; +import { filterDefined } from "helpers/asserts"; import { atomPairing, useAtomSetter } from "helpers/atoms"; const lightBoxAtom = atomPairing( diff --git a/src/contexts/settings.ts b/src/contexts/settings.ts index d505a29..101d11e 100644 --- a/src/contexts/settings.ts +++ b/src/contexts/settings.ts @@ -4,7 +4,7 @@ import { atom } from "jotai"; import { atomWithStorage } from "jotai/utils"; import { atomPairing, useAtomGetter, useAtomPair } from "helpers/atoms"; import { getDefaultPreferredLanguages } from "helpers/locales"; -import { isDefined, isDefinedAndNotEmpty } from "helpers/others"; +import { isDefined, isDefinedAndNotEmpty } from "helpers/asserts"; import { usePrefersDarkMode } from "hooks/useMediaQuery"; export enum ThemeMode { diff --git a/src/contexts/webkitFixes.ts b/src/contexts/webkitFixes.ts index fdaae91..77e1cdf 100644 --- a/src/contexts/webkitFixes.ts +++ b/src/contexts/webkitFixes.ts @@ -1,5 +1,5 @@ import { useLayoutEffect } from "react"; -import { isDefined } from "helpers/others"; +import { isDefined } from "helpers/asserts"; import { useIsWebkit } from "hooks/useIsWebkit"; export const useWebkitFixes = (): void => { diff --git a/src/graphql/getPostStaticProps.ts b/src/graphql/getPostStaticProps.ts index acfd8ad..26b6118 100644 --- a/src/graphql/getPostStaticProps.ts +++ b/src/graphql/getPostStaticProps.ts @@ -5,7 +5,7 @@ import { PostWithTranslations } from "types/types"; import { getOpenGraph } from "helpers/openGraph"; import { prettyDate, prettySlug } from "helpers/formatters"; import { getDefaultPreferredLanguages, staticSmartLanguage } from "helpers/locales"; -import { filterHasAttributes, isDefined } from "helpers/others"; +import { filterHasAttributes, isDefined } from "helpers/asserts"; import { getDescription } from "helpers/description"; import { AppLayoutRequired } from "components/AppLayout"; @@ -25,7 +25,7 @@ export const getPostStaticProps = if ( post.posts?.data && post.posts.data.length > 0 && - post.posts.data[0].attributes?.translations && + post.posts.data[0]?.attributes?.translations && isDefined(context.locale) && isDefined(context.locales) ) { diff --git a/src/helpers/asserts.ts b/src/helpers/asserts.ts new file mode 100644 index 0000000..96673bd --- /dev/null +++ b/src/helpers/asserts.ts @@ -0,0 +1,79 @@ +type JoinDot = `${K}${"" extends K ? "" : "."}${P}`; + +type PathDot = T extends object + ? { + [K in keyof T]: K extends string ? JoinDot | PathDot> : never; + }[keyof T] + : Acc; + +type PathHead = T extends [infer head] + ? head + : // eslint-disable-next-line @typescript-eslint/no-unused-vars + T extends [infer head, ...infer rest] + ? head + : ""; + +// eslint-disable-next-line @typescript-eslint/no-unused-vars +type PathRest = T extends [infer head, ...infer rest] + ? rest extends [] + ? never + : rest + : never; + +type PathLast = T["length"] extends 1 ? true : false; + +type Recursive = PathHead extends keyof T + ? Omit> & { + [P in PathHead]-?: PathLast extends true + ? NonNullable + : Recursive, PathRest>; + } + : T; + +type Split = Str extends `${infer Head}.${infer Rest}` + ? Split + : Str extends `${infer Last}` + ? [...Acc, Last] + : never; + +export type SelectiveNonNullable> = Recursive, Split

>; + +export const isDefined = (t: T): t is NonNullable => t !== null && t !== undefined; + +export const isUndefined = (t: T | null | undefined): t is null | undefined => !isDefined(t); + +export const isDefinedAndNotEmpty = (string: string | null | undefined): string is string => + isDefined(string) && string.length > 0; + +export const filterDefined = (t: T[] | null | undefined): NonNullable[] => + isUndefined(t) ? [] : (t.filter((item) => isDefined(item)) as NonNullable[]); + +export const filterHasAttributes = >( + t: T[] | null | undefined, + paths: readonly P[] +): SelectiveNonNullable[] => + isDefined(t) + ? (t.filter((item) => hasAttributes(item, paths)) as unknown as SelectiveNonNullable< + T, + typeof paths[number] + >[]) + : []; + +const hasAttributes = (item: T, paths: readonly PathDot[]): boolean => + isDefined(item) && paths.every((path) => hasAttribute(item, path)); + +const hasAttribute = (item: T, path: string): boolean => { + if (isDefined(item)) { + const [head, ...rest] = path.split("."); + if (isDefined(head) && Object.keys(item).includes(head)) { + const attribute = head as keyof T; + if (isDefined(item[attribute])) { + if (rest.length > 0) { + return hasAttribute(item[attribute], rest.join(".")); + } + return true; + } + } + } + return false; +}; diff --git a/src/helpers/component.tsx b/src/helpers/component.tsx index c887de1..d96aa40 100644 --- a/src/helpers/component.tsx +++ b/src/helpers/component.tsx @@ -1,4 +1,4 @@ -import { isDefined } from "./others"; +import { isDefined } from "./asserts"; export interface Wrapper { children: React.ReactNode; diff --git a/src/helpers/date.ts b/src/helpers/date.ts index 06b0e05..08f1396 100644 --- a/src/helpers/date.ts +++ b/src/helpers/date.ts @@ -1,4 +1,4 @@ -import { isUndefined } from "./others"; +import { isUndefined } from "./asserts"; import { DatePickerFragment } from "graphql/generated"; export const compareDate = ( diff --git a/src/helpers/description.ts b/src/helpers/description.ts index 299fa3b..cd3347b 100644 --- a/src/helpers/description.ts +++ b/src/helpers/description.ts @@ -1,4 +1,4 @@ -import { filterDefined, isDefined, isDefinedAndNotEmpty } from "./others"; +import { filterDefined, isDefined, isDefinedAndNotEmpty } from "./asserts"; export const getDescription = ( description: string | null | undefined, diff --git a/src/helpers/formatters.ts b/src/helpers/formatters.ts index 3997f96..82cf34b 100644 --- a/src/helpers/formatters.ts +++ b/src/helpers/formatters.ts @@ -1,5 +1,5 @@ import { convertPrice } from "./numbers"; -import { isDefinedAndNotEmpty, isUndefined } from "./others"; +import { isDefinedAndNotEmpty, isUndefined } from "./asserts"; import { datePickerToDate } from "./date"; import { Currencies, Languages, Langui } from "./localData"; import { DatePickerFragment, PricePickerFragment } from "graphql/generated"; @@ -180,7 +180,7 @@ export const prettyItemSubType = ( case "ComponentMetadataGame": return metadata.platforms?.data && metadata.platforms.data.length > 0 && - metadata.platforms.data[0].attributes + metadata.platforms.data[0]?.attributes ? metadata.platforms.data[0].attributes.short : ""; case "ComponentMetadataGroup": { diff --git a/src/helpers/img.ts b/src/helpers/img.ts index ae027d4..87dd917 100644 --- a/src/helpers/img.ts +++ b/src/helpers/img.ts @@ -27,13 +27,11 @@ const imageQualityProperties: Record = { }; export const getAssetFilename = (path: string): string => { - let result = path.split("/"); - result = result[result.length - 1].split("."); - result = result - .splice(0, result.length - 1) - .join(".") - .split("_"); - return result[0]; + // /uploads/329_7f41d09a98.webp -> 329_7f41d09a98.webp + let result = path.substring(path.lastIndexOf("/") + 1); + // 329_7f41d09a98.webp -> 329 + result = result.substring(0, result.indexOf("_")); + return result; }; export const getAssetURL = (url: string, quality: ImageQuality): string => { diff --git a/src/helpers/libraryItem.ts b/src/helpers/libraryItem.ts index cd74944..fb7e11b 100644 --- a/src/helpers/libraryItem.ts +++ b/src/helpers/libraryItem.ts @@ -1,4 +1,4 @@ -import { isDefined } from "./others"; +import { isDefined } from "./asserts"; export const isUntangibleGroupItem = ( metadata: diff --git a/src/helpers/locales.ts b/src/helpers/locales.ts index 3e63270..4d5a59c 100644 --- a/src/helpers/locales.ts +++ b/src/helpers/locales.ts @@ -1,4 +1,4 @@ -import { isDefined } from "./others"; +import { isDefined } from "./asserts"; export const getDefaultPreferredLanguages = (routerLocal: string, locales: string[]): string[] => { let defaultPreferredLanguages: string[] = []; diff --git a/src/helpers/openGraph.ts b/src/helpers/openGraph.ts index b4063f7..c50197b 100644 --- a/src/helpers/openGraph.ts +++ b/src/helpers/openGraph.ts @@ -1,5 +1,5 @@ import { OgImage, getImgSizesByQuality, ImageQuality, getAssetURL } from "./img"; -import { isDefinedAndNotEmpty } from "./others"; +import { isDefinedAndNotEmpty } from "./asserts"; import { Langui } from "./localData"; import { UploadImageFragment } from "graphql/generated"; diff --git a/src/helpers/others.ts b/src/helpers/others.ts index e45f4c7..0d3c4a8 100644 --- a/src/helpers/others.ts +++ b/src/helpers/others.ts @@ -1,5 +1,5 @@ -import { PathDot, SelectiveNonNullable } from "../types/SelectiveNonNullable"; import { Langui } from "./localData"; +import { isDefined } from "./asserts"; import { Enum_Componentsetstextset_Status, GetLibraryItemQuery, @@ -45,47 +45,6 @@ export const getStatusDescription = (status: string, langui: Langui): string | n } }; -export const isDefined = (t: T): t is NonNullable => t !== null && t !== undefined; - -export const isUndefined = (t: T | null | undefined): t is null | undefined => - t === null || t === undefined; - -export const isDefinedAndNotEmpty = (string: string | null | undefined): string is string => - isDefined(string) && string.length > 0; - -export const filterDefined = (t: T[] | null | undefined): NonNullable[] => - isUndefined(t) ? [] : (t.filter((item) => isDefined(item)) as NonNullable[]); - -export const filterHasAttributes = >( - t: T[] | null | undefined, - paths: readonly P[] -): SelectiveNonNullable[] => - isDefined(t) - ? (t.filter((item) => hasAttributes(item, paths)) as unknown as SelectiveNonNullable< - T, - typeof paths[number] - >[]) - : []; - -const hasAttributes = (item: T, paths: readonly PathDot[]): boolean => - isDefined(item) && paths.every((path) => hasAttribute(item, path)); - -const hasAttribute = (item: T, path: string): boolean => { - if (isDefined(item)) { - const [head, ...rest] = path.split("."); - if (Object.keys(item).includes(head)) { - const attribute = head as keyof T; - if (isDefined(item[attribute])) { - if (rest.length > 0) { - return hasAttribute(item[attribute], rest.join(".")); - } - return true; - } - } - } - return false; -}; - export const iterateMap = ( map: Map, callbackfn: (key: K, value: V, index: number) => U, @@ -99,7 +58,10 @@ export const iterateMap = ( }; export const arrayMove = (arr: T[], sourceIndex: number, targetIndex: number): T[] => { - arr.splice(targetIndex, 0, arr.splice(sourceIndex, 1)[0]); + const sourceItem = arr.splice(sourceIndex, 1)[0]; + if (isDefined(sourceItem)) { + arr.splice(targetIndex, 0, sourceItem); + } return arr; }; diff --git a/src/helpers/terminal.ts b/src/helpers/terminal.ts index 04937c7..05e327f 100644 --- a/src/helpers/terminal.ts +++ b/src/helpers/terminal.ts @@ -1,4 +1,4 @@ -import { isDefinedAndNotEmpty } from "./others"; +import { isDefinedAndNotEmpty } from "./asserts"; export const prettyTerminalUnderlinedTitle = (string: string | null | undefined): string => isDefinedAndNotEmpty(string) diff --git a/src/hooks/useFullscreen.ts b/src/hooks/useFullscreen.ts index a9fd4a0..72543ee 100644 --- a/src/hooks/useFullscreen.ts +++ b/src/hooks/useFullscreen.ts @@ -1,6 +1,6 @@ import { useCallback, useEffect, useState } from "react"; import { useIsClient } from "usehooks-ts"; -import { isDefined } from "helpers/others"; +import { isDefined } from "helpers/asserts"; export const useFullscreen = ( id: string diff --git a/src/hooks/useIntersectionList.ts b/src/hooks/useIntersectionList.ts index 04e44a4..4a02425 100644 --- a/src/hooks/useIntersectionList.ts +++ b/src/hooks/useIntersectionList.ts @@ -2,7 +2,7 @@ import { useCallback, useEffect, useState } from "react"; import { throttle } from "throttle-debounce"; import { useIsClient } from "usehooks-ts"; import { useOnScroll } from "./useOnScroll"; -import { isDefined } from "helpers/others"; +import { isDefined, isUndefined } from "helpers/asserts"; import { Ids } from "types/ids"; export const useIntersectionList = (ids: string[]): number => { @@ -16,21 +16,21 @@ export const useIntersectionList = (ids: string[]): number => { (scroll: number) => { console.log("useIntersectionList"); - if (!isDefined(contentPanel)) { + if (isUndefined(contentPanel)) { setCurrentIntersection(-1); return; } - for (let idIndex = 0; idIndex < ids.length; idIndex++) { - const elem = document.getElementById(ids[ids.length - 1 - idIndex]); + for (const [index, id] of [...ids].reverse().entries()) { + const elem = document.getElementById(id); const halfScreenOffset = window.screen.height / 2; if (isDefined(elem) && scroll > elem.offsetTop - halfScreenOffset) { - setCurrentIntersection(ids.length - 1 - idIndex); + const unreversedIndex = ids.length - 1 - index; + setCurrentIntersection(unreversedIndex); return; } } - setCurrentIntersection(-1); }, [ids, contentPanel] ); diff --git a/src/hooks/useOnResize.ts b/src/hooks/useOnResize.ts index ccfae39..678737d 100644 --- a/src/hooks/useOnResize.ts +++ b/src/hooks/useOnResize.ts @@ -1,6 +1,6 @@ import { useEffect } from "react"; import { useIsClient } from "usehooks-ts"; -import { isDefined } from "helpers/others"; +import { isDefined } from "helpers/asserts"; export const useOnResize = ( id: string, @@ -11,9 +11,12 @@ export const useOnResize = ( useEffect(() => { console.log("[useOnResize]", id); const elem = isClient ? document.querySelector(`#${id}`) : null; - const ro = new ResizeObserver((resizeObserverEntry) => - onResize(resizeObserverEntry[0].contentRect.width, resizeObserverEntry[0].contentRect.height) - ); + const ro = new ResizeObserver((resizeObserverEntry) => { + const entry = resizeObserverEntry[0]; + if (isDefined(entry)) { + onResize(entry.contentRect.width, entry.contentRect.height); + } + }); if (isDefined(elem)) { ro.observe(elem); } diff --git a/src/hooks/useScrollIntoView.ts b/src/hooks/useScrollIntoView.ts index 5b44dc3..cc7631f 100644 --- a/src/hooks/useScrollIntoView.ts +++ b/src/hooks/useScrollIntoView.ts @@ -1,7 +1,7 @@ import { useRouter } from "next/router"; import { useEffect, useState } from "react"; import { useCounter } from "usehooks-ts"; -import { isDefined } from "helpers/others"; +import { isDefined } from "helpers/asserts"; const NUM_RETRIES = 10; diff --git a/src/hooks/useSmartLanguage.ts b/src/hooks/useSmartLanguage.ts index 2e65aa5..1fd1106 100644 --- a/src/hooks/useSmartLanguage.ts +++ b/src/hooks/useSmartLanguage.ts @@ -1,7 +1,7 @@ import { useRouter } from "next/router"; import { useEffect, useMemo, useState } from "react"; import { LanguageSwitcher } from "components/Inputs/LanguageSwitcher"; -import { filterDefined, isDefined } from "helpers/others"; +import { filterDefined, isDefined } from "helpers/asserts"; import { getPreferredLanguage } from "helpers/locales"; import { atoms } from "contexts/atoms"; import { useAtomGetter } from "helpers/atoms"; diff --git a/src/pages/api/revalidate.ts b/src/pages/api/revalidate.ts index dd49406..2d2a502 100644 --- a/src/pages/api/revalidate.ts +++ b/src/pages/api/revalidate.ts @@ -1,6 +1,7 @@ import type { NextApiRequest, NextApiResponse } from "next"; import { i18n } from "../../../next.config"; -import { cartesianProduct, filterHasAttributes, isDefined } from "helpers/others"; +import { cartesianProduct } from "helpers/others"; +import { filterHasAttributes, isDefined } from "helpers/asserts"; import { fetchLocalData } from "graphql/fetchLocalData"; import { getReadySdk } from "graphql/sdk"; @@ -183,7 +184,7 @@ const Revalidate = async ( language_code: "en", slug: body.entry.slug, }); - filterHasAttributes(libraryItem.libraryItems?.data[0].attributes?.subitem_of?.data, [ + filterHasAttributes(libraryItem.libraryItems?.data[0]?.attributes?.subitem_of?.data, [ "attributes.slug", ] as const).forEach((parentItem) => paths.push(`/library/${parentItem.attributes.slug}`)); } @@ -202,12 +203,12 @@ const Revalidate = async ( slug: body.entry.slug, }); - const folderSlug = content.contents?.data[0].attributes?.folder?.data?.attributes?.slug; + const folderSlug = content.contents?.data[0]?.attributes?.folder?.data?.attributes?.slug; if (folderSlug) { paths.push(`/contents/folder/${folderSlug}`); } - filterHasAttributes(content.contents?.data[0].attributes?.ranged_contents?.data, [ + filterHasAttributes(content.contents?.data[0]?.attributes?.ranged_contents?.data, [ "attributes.library_item.data.attributes.slug", ] as const).forEach((ranged_content) => { const parentSlug = ranged_content.attributes.library_item.data.attributes.slug; @@ -260,16 +261,16 @@ const Revalidate = async ( slug: body.entry.slug, }); const parentSlug = - folder.contentsFolders?.data[0].attributes?.parent_folder?.data?.attributes?.slug; + folder.contentsFolders?.data[0]?.attributes?.parent_folder?.data?.attributes?.slug; if (parentSlug) { paths.push(`/contents/folder/${parentSlug}`); } - filterHasAttributes(folder.contentsFolders?.data[0].attributes?.subfolders?.data, [ + filterHasAttributes(folder.contentsFolders?.data[0]?.attributes?.subfolders?.data, [ "attributes.slug", ] as const).forEach((subfolder) => paths.push(`/contents/folder/${subfolder.attributes.slug}`) ); - filterHasAttributes(folder.contentsFolders?.data[0].attributes?.contents?.data, [ + filterHasAttributes(folder.contentsFolders?.data[0]?.attributes?.contents?.data, [ "attributes.slug", ] as const).forEach((content) => paths.push(`/contents/${content.attributes.slug}`)); } @@ -308,7 +309,7 @@ const Revalidate = async ( paths.push(`/archives/videos`); paths.push(`/archives/videos/v/${body.entry.uid}`); const video = await sdk.getVideo({ uid: body.entry.uid }); - const channelUid = video.videos?.data[0].attributes?.channel?.data?.attributes?.uid; + const channelUid = video.videos?.data[0]?.attributes?.channel?.data?.attributes?.uid; if (isDefined(channelUid)) { paths.push(`/archives/videos/c/${channelUid}`); } diff --git a/src/pages/archives/videos/c/[uid].tsx b/src/pages/archives/videos/c/[uid].tsx index 4fe2507..75b7798 100644 --- a/src/pages/archives/videos/c/[uid].tsx +++ b/src/pages/archives/videos/c/[uid].tsx @@ -14,7 +14,7 @@ import { getVideoThumbnailURL } from "helpers/videos"; import { Icon } from "components/Ico"; import { useDeviceSupportsHover } from "hooks/useMediaQuery"; import { WithLabel } from "components/Inputs/WithLabel"; -import { filterHasAttributes, isDefined } from "helpers/others"; +import { filterHasAttributes, isDefined } from "helpers/asserts"; import { getOpenGraph } from "helpers/openGraph"; import { compareDate } from "helpers/date"; import { HorizontalLine } from "components/HorizontalLine"; @@ -136,7 +136,7 @@ export const getStaticProps: GetStaticProps = async (context) => { const channel = await sdk.getVideoChannel({ channel: context.params && isDefined(context.params.uid) ? context.params.uid.toString() : "", }); - if (!channel.videoChannels?.data[0].attributes) return { notFound: true }; + if (!channel.videoChannels?.data[0]?.attributes) return { notFound: true }; channel.videoChannels.data[0].attributes.videos?.data .sort((a, b) => compareDate(a.attributes?.published_date, b.attributes?.published_date)) diff --git a/src/pages/archives/videos/index.tsx b/src/pages/archives/videos/index.tsx index 1f5fee0..51d9d2e 100644 --- a/src/pages/archives/videos/index.tsx +++ b/src/pages/archives/videos/index.tsx @@ -14,7 +14,7 @@ import { SubPanel } from "components/Containers/SubPanel"; import { PreviewCard } from "components/PreviewCard"; import { GetVideosPreviewQuery } from "graphql/generated"; import { getReadySdk } from "graphql/sdk"; -import { filterHasAttributes } from "helpers/others"; +import { filterHasAttributes } from "helpers/asserts"; import { getVideoThumbnailURL } from "helpers/videos"; import { useDeviceSupportsHover } from "hooks/useMediaQuery"; import { getOpenGraph } from "helpers/openGraph"; diff --git a/src/pages/archives/videos/v/[uid].tsx b/src/pages/archives/videos/v/[uid].tsx index 3537ebc..6e448a0 100644 --- a/src/pages/archives/videos/v/[uid].tsx +++ b/src/pages/archives/videos/v/[uid].tsx @@ -12,7 +12,7 @@ import { SubPanel } from "components/Containers/SubPanel"; import { GetVideoQuery } from "graphql/generated"; import { getReadySdk } from "graphql/sdk"; import { prettyDate, prettyShortenNumber } from "helpers/formatters"; -import { filterHasAttributes, isDefined } from "helpers/others"; +import { filterHasAttributes, isDefined } from "helpers/asserts"; import { getVideoFile } from "helpers/videos"; import { getOpenGraph } from "helpers/openGraph"; import { getLangui } from "graphql/fetchLocalData"; diff --git a/src/pages/chronicles/[slug]/index.tsx b/src/pages/chronicles/[slug]/index.tsx index f57cd89..bc8c842 100644 --- a/src/pages/chronicles/[slug]/index.tsx +++ b/src/pages/chronicles/[slug]/index.tsx @@ -1,7 +1,7 @@ import { GetStaticProps, GetStaticPaths, GetStaticPathsResult } from "next"; -import { useCallback, useMemo } from "react"; +import { useCallback } from "react"; import { getReadySdk } from "graphql/sdk"; -import { isDefined, filterHasAttributes } from "helpers/others"; +import { isDefined, filterHasAttributes } from "helpers/asserts"; import { ChronicleWithTranslations } from "types/types"; import { AppLayout, AppLayoutRequired } from "components/AppLayout"; import { useSmartLanguage } from "hooks/useSmartLanguage"; diff --git a/src/pages/chronicles/index.tsx b/src/pages/chronicles/index.tsx index 52ff422..5a437fe 100644 --- a/src/pages/chronicles/index.tsx +++ b/src/pages/chronicles/index.tsx @@ -5,7 +5,7 @@ import { SubPanel } from "components/Containers/SubPanel"; import { Icon } from "components/Ico"; import { getReadySdk } from "graphql/sdk"; import { GetChroniclesChaptersQuery } from "graphql/generated"; -import { filterHasAttributes } from "helpers/others"; +import { filterHasAttributes } from "helpers/asserts"; import { prettySlug } from "helpers/formatters"; import { getOpenGraph } from "helpers/openGraph"; import { TranslatedChroniclesList } from "components/Chronicles/ChroniclesList"; diff --git a/src/pages/contents/[slug].tsx b/src/pages/contents/[slug].tsx index b79bdab..317cc07 100644 --- a/src/pages/contents/[slug].tsx +++ b/src/pages/contents/[slug].tsx @@ -21,7 +21,8 @@ import { prettySlug, } from "helpers/formatters"; import { isUntangibleGroupItem } from "helpers/libraryItem"; -import { filterHasAttributes, getStatusDescription, isDefinedAndNotEmpty } from "helpers/others"; +import { getStatusDescription } from "helpers/others"; +import { filterHasAttributes, isDefinedAndNotEmpty } from "helpers/asserts"; import { ContentWithTranslations } from "types/types"; import { useScrollTopOnChange } from "hooks/useScrollTopOnChange"; import { useSmartLanguage } from "hooks/useSmartLanguage"; @@ -466,7 +467,7 @@ type FolderContents = NonNullable< const getPreviousContent = (contents: FolderContents, currentSlug: string) => { for (let index = 0; index < contents.length; index++) { const content = contents[index]; - if (content.attributes?.slug === currentSlug && index > 0) { + if (content?.attributes?.slug === currentSlug && index > 0) { return contents[index - 1]; } } @@ -478,7 +479,7 @@ const getPreviousContent = (contents: FolderContents, currentSlug: string) => { const getNextContent = (contents: FolderContents, currentSlug: string) => { for (let index = 0; index < contents.length; index++) { const content = contents[index]; - if (content.attributes?.slug === currentSlug && index < contents.length - 1) { + if (content?.attributes?.slug === currentSlug && index < contents.length - 1) { return contents[index + 1]; } } diff --git a/src/pages/contents/all.tsx b/src/pages/contents/all.tsx index 057cebd..78bcfe0 100644 --- a/src/pages/contents/all.tsx +++ b/src/pages/contents/all.tsx @@ -15,10 +15,14 @@ import { WithLabel } from "components/Inputs/WithLabel"; import { Button } from "components/Inputs/Button"; import { useDeviceSupportsHover } from "hooks/useMediaQuery"; import { Icon } from "components/Ico"; -import { filterDefined, filterHasAttributes, isDefinedAndNotEmpty } from "helpers/others"; +import { + filterDefined, + filterHasAttributes, + isDefinedAndNotEmpty, + SelectiveNonNullable, +} from "helpers/asserts"; import { GetContentsQuery } from "graphql/generated"; import { SmartList } from "components/SmartList"; -import { SelectiveNonNullable } from "types/SelectiveNonNullable"; import { getOpenGraph } from "helpers/openGraph"; import { HorizontalLine } from "components/HorizontalLine"; import { TranslatedPreviewCard } from "components/PreviewCard"; diff --git a/src/pages/contents/folder/[slug].tsx b/src/pages/contents/folder/[slug].tsx index 5974f34..c15459f 100644 --- a/src/pages/contents/folder/[slug].tsx +++ b/src/pages/contents/folder/[slug].tsx @@ -4,7 +4,7 @@ import { AppLayout, AppLayoutRequired } from "components/AppLayout"; import { ContentPanel, ContentPanelWidthSizes } from "components/Containers/ContentPanel"; import { getOpenGraph } from "helpers/openGraph"; import { getReadySdk } from "graphql/sdk"; -import { filterHasAttributes } from "helpers/others"; +import { filterHasAttributes } from "helpers/asserts"; import { GetContentsFolderQuery } from "graphql/generated"; import { getDefaultPreferredLanguages, staticSmartLanguage } from "helpers/locales"; import { prettySlug } from "helpers/formatters"; diff --git a/src/pages/dev/checkup/contents.tsx b/src/pages/dev/checkup/contents.tsx index 30df295..b8deb85 100644 --- a/src/pages/dev/checkup/contents.tsx +++ b/src/pages/dev/checkup/contents.tsx @@ -6,7 +6,7 @@ import { ContentPanel, ContentPanelWidthSizes } from "components/Containers/Cont import { ToolTip } from "components/ToolTip"; import { DevGetContentsQuery } from "graphql/generated"; import { getReadySdk } from "graphql/sdk"; -import { filterDefined, filterHasAttributes } from "helpers/others"; +import { filterDefined, filterHasAttributes } from "helpers/asserts"; import { Report, Severity } from "types/Report"; import { getOpenGraph } from "helpers/openGraph"; import { getLangui } from "graphql/fetchLocalData"; @@ -61,7 +61,8 @@ const CheckupContents = ({ contents, ...otherProps }: Props): JSX.Element => { ? "bg-[#fff344] !opacity-100" : "" } - text={Severity[line.severity]} + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + text={Severity[line.severity] ?? "Unknown"} />

{line.description}

diff --git a/src/pages/dev/checkup/libraryitems.tsx b/src/pages/dev/checkup/libraryitems.tsx index d43315f..0efd694 100644 --- a/src/pages/dev/checkup/libraryitems.tsx +++ b/src/pages/dev/checkup/libraryitems.tsx @@ -47,7 +47,7 @@ const CheckupLibraryItems = ({ libraryItems, ...otherProps }: Props): JSX.Elemen
+ grid-cols-[2em,3em,2fr,1fr,0.5fr,0.5fr,2fr] items-center justify-items-start gap-2">