diff --git a/src/features/migration/components/MIgrationEntryGroup.tsx b/src/features/migration/components/MIgrationEntryGroup.tsx
index e17c151f..0bd4857e 100644
--- a/src/features/migration/components/MIgrationEntryGroup.tsx
+++ b/src/features/migration/components/MIgrationEntryGroup.tsx
@@ -11,58 +11,60 @@ import type { ButtonProps } from '@mui/material/Button';
import Button from '@mui/material/Button';
import Collapse from '@mui/material/Collapse';
import Stack from '@mui/material/Stack';
-import {} from 'react';
+import { memo } from 'react';
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
import ExpandLessIcon from '@mui/icons-material/ExpandLess';
import { MigrationEntry } from '@/features/migration/components/migration-entry/MigrationEntry.tsx';
import { MigrationManager } from '@/features/migration/MigrationManager.ts';
-export const MigrationEntryGroup = ({
- status,
- title,
- entries,
- color,
- isMigrating = false,
-}: {
- status: MigrationEntryStatus;
- title: string;
- entries: TMigrationEntry[];
- color: ButtonProps['color'];
- isMigrating?: boolean;
-}) => {
- const isExpanded = MigrationManager.useGroupExpandState(status);
+export const MigrationEntryGroup = memo(
+ ({
+ status,
+ title,
+ entries,
+ color,
+ isMigrating = false,
+ }: {
+ status: MigrationEntryStatus;
+ title: string;
+ entries: TMigrationEntry[];
+ color: ButtonProps['color'];
+ isMigrating?: boolean;
+ }) => {
+ const isExpanded = MigrationManager.useGroupExpandState(status);
- if (!entries.length) {
- return null;
- }
+ if (!entries.length) {
+ return null;
+ }
- return (
-
-
-
-
- {entries.map((entry) => (
-
- ))}
-
-
-
- );
-};
+ return (
+
+
+
+
+ {entries.map((entry) => (
+
+ ))}
+
+
+
+ );
+ },
+);
diff --git a/src/features/migration/components/MigrationCard.tsx b/src/features/migration/components/MigrationCard.tsx
index 64f7cfd6..5e80471b 100644
--- a/src/features/migration/components/MigrationCard.tsx
+++ b/src/features/migration/components/MigrationCard.tsx
@@ -21,8 +21,9 @@ import { Sources } from '@/features/source/services/Sources';
import type { TMigratableSource } from '@/features/migration/Migration.types.ts';
import { ReactRouter } from '@/lib/react-router/ReactRouter.ts';
import { AppRoutes } from '@/base/AppRoute.constants.ts';
+import { memo } from 'react';
-export const MigrationCard = (source: TMigratableSource) => {
+export const MigrationCard = memo((source: TMigratableSource) => {
const { id, name, lang, iconUrl, mangaCount } = source;
const { t } = useLingui();
@@ -66,4 +67,4 @@ export const MigrationCard = (source: TMigratableSource) => {
);
-};
+});
diff --git a/src/features/migration/components/MigrationSourceList.tsx b/src/features/migration/components/MigrationSourceList.tsx
index 1e9347dc..cbc5e83f 100644
--- a/src/features/migration/components/MigrationSourceList.tsx
+++ b/src/features/migration/components/MigrationSourceList.tsx
@@ -6,7 +6,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
-import { useCallback, useMemo, useState } from 'react';
+import { memo, useCallback, useMemo, useState } from 'react';
import Box from '@mui/material/Box';
import Card from '@mui/material/Card';
import Chip from '@mui/material/Chip';
@@ -36,55 +36,57 @@ import { languageCodeToName } from '@/base/utils/Languages.ts';
import { DEFAULT_FULL_FAB_HEIGHT } from '@/base/components/buttons/StyledFab.tsx';
import Stack from '@mui/material/Stack';
-const SourceCard = ({
- source,
- onToggle,
- isCurrentSource,
- isSelected,
- isDragging,
-}: {
- source: SourceItem;
- onToggle: (id: SourceIdInfo['id']) => void;
- isCurrentSource: boolean;
- isSelected: boolean;
- isDragging?: boolean;
-}) => {
- const { t } = useLingui();
+const SourceCard = memo(
+ ({
+ source,
+ onToggle,
+ isCurrentSource,
+ isSelected,
+ isDragging,
+ }: {
+ source: SourceItem;
+ onToggle: (id: SourceIdInfo['id']) => void;
+ isCurrentSource: boolean;
+ isSelected: boolean;
+ isDragging?: boolean;
+ }) => {
+ const { t } = useLingui();
- return (
-
-
- onToggle(source.id)}>
-
-
-
-
-
- {source.name}
-
- {languageCodeToName(source.lang)}
-
-
-
- {isCurrentSource && (
-
- )}
- {isSelected && (
-
-
+ return (
+
+
+ onToggle(source.id)}>
+
+
+
+
+
+ {source.name}
+
+ {languageCodeToName(source.lang)}
- )}
-
-
-
-
-
- );
-};
+
+
+ {isCurrentSource && (
+
+ )}
+ {isSelected && (
+
+
+
+ )}
+
+
+
+
+
+ );
+ },
+);
export const MigrationSourceList = ({
sources,
diff --git a/src/features/migration/components/migration-entry/MigrationEntry.tsx b/src/features/migration/components/migration-entry/MigrationEntry.tsx
index d3cb52db..0ad96d45 100644
--- a/src/features/migration/components/migration-entry/MigrationEntry.tsx
+++ b/src/features/migration/components/migration-entry/MigrationEntry.tsx
@@ -9,7 +9,7 @@
import type { MigrationMatch, TMigrationEntry } from '@/features/migration/Migration.types.ts';
import { MigrationManager } from '@/features/migration/MigrationManager.ts';
import Paper from '@mui/material/Paper';
-import { useMemo } from 'react';
+import { memo, useMemo } from 'react';
import { MediaQuery } from '@/base/utils/MediaQuery.tsx';
import { applyStyles } from '@/base/utils/ApplyStyles.ts';
import { MigrationSourceEntry } from '@/features/migration/components/migration-entry/MigrationSourceEntry.tsx';
@@ -28,214 +28,227 @@ import Divider from '@mui/material/Divider';
import { MigrationEntryStatusIndicator } from '@/features/migration/components/migration-entry/MigrationEntryStatusIndicator.tsx';
import Box from '@mui/material/Box';
-const MigrationEntryMobile = ({
- entry,
- entry: { mangaId, mangaTitle, status, error, isExcluded },
- destinationEntry,
- otherSearchMatches,
- isExpanded,
- setIsExpanded,
- isMigrating,
-}: {
- entry: TMigrationEntry;
- destinationEntry: MigrationMatch | undefined;
- otherSearchMatches: MigrationMatch[];
- isExpanded: boolean;
- setIsExpanded: (expanded: boolean) => void;
- isMigrating: boolean;
-}) => {
- const { t } = useLingui();
+const MigrationEntryMobile = memo(
+ ({
+ entry,
+ entry: { mangaId, mangaTitle, status, error, isExcluded },
+ destinationEntry,
+ otherSearchMatches,
+ isExpanded,
+ setIsExpanded,
+ isMigrating,
+ }: {
+ entry: TMigrationEntry;
+ destinationEntry: MigrationMatch | undefined;
+ otherSearchMatches: MigrationMatch[];
+ isExpanded: boolean;
+ setIsExpanded: (expanded: boolean) => void;
+ isMigrating: boolean;
+ }) => {
+ const { t } = useLingui();
- return (
- <>
-
-
-
-
-
-
- {t`Matches`}
- }
- variant="text"
- onClick={() => {
- ReactRouter.navigate(AppRoutes.migrate.childRoutes.manualSearch.path(mangaId, mangaTitle), {
- state: { mangaTitle: mangaTitle },
- });
- }}
- >{t`Manual search`}
-
-
- {otherSearchMatches.map((searchMatch) => {
- if (destinationEntry?.id === searchMatch.id) {
- return null;
- }
-
- return (
-
- );
- })}
-
-
-
- {!isMigrating && (
-
+
+
- )}
- >
- );
-};
-export const MigrationEntryDesktop = ({
- entry,
- entry: { mangaId, mangaTitle, status, error },
- destinationEntry,
- otherSearchMatches,
- isExpanded,
- setIsExpanded,
- isMigrating,
-}: {
- entry: TMigrationEntry;
- destinationEntry: MigrationMatch | undefined;
- otherSearchMatches: MigrationMatch[];
- isExpanded: boolean;
- setIsExpanded: (expanded: boolean) => void;
- isMigrating: boolean;
-}) => {
- const { t } = useLingui();
+
+
+
+ {t`Matches`}
+ }
+ variant="text"
+ onClick={() => {
+ ReactRouter.navigate(
+ AppRoutes.migrate.childRoutes.manualSearch.path(mangaId, mangaTitle),
+ {
+ state: { mangaTitle: mangaTitle },
+ },
+ );
+ }}
+ >{t`Manual search`}
+
+
+ {otherSearchMatches.map((searchMatch) => {
+ if (destinationEntry?.id === searchMatch.id) {
+ return null;
+ }
- return (
- <>
-
+ );
+ })}
+
+
+
+ {!isMigrating && (
+
+ )}
+ >
+ );
+ },
+);
+
+export const MigrationEntryDesktop = memo(
+ ({
+ entry,
+ entry: { mangaId, mangaTitle, status, error },
+ destinationEntry,
+ otherSearchMatches,
+ isExpanded,
+ setIsExpanded,
+ isMigrating,
+ }: {
+ entry: TMigrationEntry;
+ destinationEntry: MigrationMatch | undefined;
+ otherSearchMatches: MigrationMatch[];
+ isExpanded: boolean;
+ setIsExpanded: (expanded: boolean) => void;
+ isMigrating: boolean;
+ }) => {
+ const { t } = useLingui();
+
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+ {!isMigrating && (
+
+ )}
+
+
+
+
+
+ {t`Matches`}
+
+ {otherSearchMatches.map((searchMatch) => {
+ if (destinationEntry?.id === searchMatch.id) {
+ return null;
+ }
+
+ return (
+
+ );
+ })}
+
+
+ >
+ );
+ },
+);
+
+export const MigrationEntry = memo(
+ ({ entry: propEntry, isMigrating }: { entry: TMigrationEntry; isMigrating: boolean }) => {
+ const isTabletWidth = MediaQuery.useIsTabletWidth();
+
+ const entry = useMemo(() => MigrationManager.getUpToDateMigrationEntry(propEntry), [propEntry]);
+
+ const destinationEntry = useMemo(() => {
+ const match = entry.searchMatches.find((matchEntry) => matchEntry.id === entry.selectedMatchMangaId);
+ const manualMatch = entry.manualMatches.find((matchEntry) => matchEntry.id === entry.selectedMatchMangaId);
+
+ return match ?? manualMatch;
+ }, [entry.searchMatches, entry.selectedMatchMangaId]);
+ const otherMatches = useMemo(
+ () =>
+ entry.searchMatches
+ .filter((searchMatch) => searchMatch.id !== entry.selectedMatchMangaId)
+ .sort((a, b) => (b.latestChapterNumber ?? 0) - (a.latestChapterNumber ?? 0)),
+ [entry.searchMatches, entry.selectedMatchMangaId],
+ );
+
+ const MigrationComponent = useMemo(
+ () => (isTabletWidth ? MigrationEntryMobile : MigrationEntryDesktop),
+ [isTabletWidth],
+ );
+
+ return (
+
-
-
-
-
-
-
-
-
- {!isMigrating && (
-
- )}
-
-
-
-
-
- {t`Matches`}
-
- {otherSearchMatches.map((searchMatch) => {
- if (destinationEntry?.id === searchMatch.id) {
- return null;
- }
-
- return (
-
- );
- })}
-
-
- >
- );
-};
-
-export const MigrationEntry = ({ entry: propEntry, isMigrating }: { entry: TMigrationEntry; isMigrating: boolean }) => {
- const isTabletWidth = MediaQuery.useIsTabletWidth();
-
- const entry = useMemo(() => MigrationManager.getUpToDateMigrationEntry(propEntry), [propEntry]);
-
- const destinationEntry = useMemo(() => {
- const match = entry.searchMatches.find((matchEntry) => matchEntry.id === entry.selectedMatchMangaId);
- const manualMatch = entry.manualMatches.find((matchEntry) => matchEntry.id === entry.selectedMatchMangaId);
-
- return match ?? manualMatch;
- }, [entry.searchMatches, entry.selectedMatchMangaId]);
- const otherMatches = useMemo(
- () =>
- entry.searchMatches
- .filter((searchMatch) => searchMatch.id !== entry.selectedMatchMangaId)
- .sort((a, b) => (b.latestChapterNumber ?? 0) - (a.latestChapterNumber ?? 0)),
- [entry.searchMatches, entry.selectedMatchMangaId],
- );
-
- const MigrationComponent = useMemo(
- () => (isTabletWidth ? MigrationEntryMobile : MigrationEntryDesktop),
- [isTabletWidth],
- );
-
- return (
-
-
- MigrationManager.setEntryMatchesExpandState(entry.mangaId, !entry.areMatchesExpanded)
- }
- otherSearchMatches={otherMatches}
- isMigrating={isMigrating}
- />
-
- );
-};
+
+ MigrationManager.setEntryMatchesExpandState(entry.mangaId, !entry.areMatchesExpanded)
+ }
+ otherSearchMatches={otherMatches}
+ isMigrating={isMigrating}
+ />
+
+ );
+ },
+);
diff --git a/src/features/migration/components/migration-entry/MigrationMatchedEntry.tsx b/src/features/migration/components/migration-entry/MigrationMatchedEntry.tsx
index 3501a889..ab59ab31 100644
--- a/src/features/migration/components/migration-entry/MigrationMatchedEntry.tsx
+++ b/src/features/migration/components/migration-entry/MigrationMatchedEntry.tsx
@@ -24,69 +24,67 @@ import Button from '@mui/material/Button';
import CardActionArea from '@mui/material/CardActionArea';
import Link from '@mui/material/Link';
import { Link as RouterLink } from 'react-router-dom';
+import { memo } from 'react';
-export const MigrationMatchedEntry = ({
- sourceMangaId,
- entry,
-}: {
- sourceMangaId: MangaIdInfo['id'];
- entry: MigrationMatch;
-}) => {
- const { t } = useLingui();
+export const MigrationMatchedEntry = memo(
+ ({ sourceMangaId, entry }: { sourceMangaId: MangaIdInfo['id']; entry: MigrationMatch }) => {
+ const { t } = useLingui();
- return (
-
- MigrationManager.selectMatch(sourceMangaId, entry.id, entry.sourceId)}>
-
- {(() => (
- <>
- e.stopPropagation()}
- >
-
-
-
-
- {entry.sourceTitle}
-
+ return (
+
+ MigrationManager.selectMatch(sourceMangaId, entry.id, entry.sourceId)}>
+
+ {(() => (
+ <>
e.stopPropagation()}
>
-
- {entry.title}
-
+
-
-
- >
- ))()}
- {(() => (
-
- ))()}
-
-
-
- );
-};
+
+
+ {entry.sourceTitle}
+
+ e.stopPropagation()}
+ >
+
+ {entry.title}
+
+
+
+
+ >
+ ))()}
+ {(() => (
+
+ ))()}
+
+
+
+ );
+ },
+);
diff --git a/src/features/migration/components/migration-entry/MigrationSourceEntry.tsx b/src/features/migration/components/migration-entry/MigrationSourceEntry.tsx
index 8c2ca2c2..f45a0f1d 100644
--- a/src/features/migration/components/migration-entry/MigrationSourceEntry.tsx
+++ b/src/features/migration/components/migration-entry/MigrationSourceEntry.tsx
@@ -20,8 +20,9 @@ import { useLingui } from '@lingui/react/macro';
import Stack from '@mui/material/Stack';
import Link from '@mui/material/Link';
import { Link as RouterLink } from 'react-router-dom';
+import { memo } from 'react';
-export const MigrationSourceEntry = (entry: TMigrationEntry) => {
+export const MigrationSourceEntry = memo((entry: TMigrationEntry) => {
const {
mangaId,
mangaThumbnailUrl,
@@ -94,4 +95,4 @@ export const MigrationSourceEntry = (entry: TMigrationEntry) => {
);
-};
+});