← back to Open Seo

src/client/features/backlinks/BacklinksPageContent.tsx

182 lines

import { useMemo } from "react";
import type { OnChangeFn, SortingState } from "@tanstack/react-table";
import { BacklinksOverviewPanels } from "./BacklinksOverviewPanels";
import { BacklinksResultsCard } from "./BacklinksPageSections";
import {
  BacklinksErrorState,
  BacklinksLoadingState,
} from "./BacklinksPageStates";
import { BacklinksHistorySection } from "./BacklinksHistorySection";
import type { BacklinksSearchHistoryItem } from "@/client/hooks/useBacklinksSearchHistory";
import type {
  BacklinksOverviewData,
  BacklinksReferringDomainsData,
  BacklinksRowsPageData,
  BacklinksSearchState,
  BacklinksTabRows,
  BacklinksTopPagesData,
} from "./backlinksPageTypes";
import { buildSummaryStats } from "./backlinksPageUtils";
import type { BacklinksDomainExpansion } from "./useBacklinksDomainExpansion";
import type { BacklinksFiltersState } from "./useBacklinksFilters";
import {
  SearchTabStrip,
  type SearchTab,
} from "@/client/features/search-tabs/SearchTabStrip";

type BacklinksBodyProps = {
  projectId: string;
  history: BacklinksSearchHistoryItem[];
  historyLoaded: boolean;
  overviewData: BacklinksOverviewData | undefined;
  overviewError: string | null;
  overviewLoading: boolean;
  backlinksRowsPage: BacklinksRowsPageData | undefined;
  referringDomainsPage: BacklinksReferringDomainsData | undefined;
  topPagesPage: BacklinksTopPagesData | undefined;
  searchState: BacklinksSearchState;
  filters: BacklinksFiltersState;
  sorting: SortingState;
  domainExpansion: BacklinksDomainExpansion;
  tabErrorMessage: string | null;
  tabLoading: boolean;
  tabFetching: boolean;
  onPageChange: (nextPage: number) => void;
  onPageSizeChange: (nextPageSize: number) => void;
  onRemoveHistoryItem: (timestamp: number) => void;
  onRetryOverview: () => void;
  onSortingChange: OnChangeFn<SortingState>;
  onTabChange: (tab: BacklinksSearchState["tab"]) => void;
  onViewChange: (view: "all" | undefined) => void;
  searchTabs: {
    activeTabId: string | null;
    tabs: SearchTab[];
    onSelect: (tab: SearchTab) => void;
    onClose: (tabId: string) => void;
    onViewed: (tabId: string, when?: number) => void;
  } | null;
};

export function BacklinksBody({
  projectId,
  history,
  historyLoaded,
  overviewData,
  overviewError,
  overviewLoading,
  backlinksRowsPage,
  referringDomainsPage,
  topPagesPage,
  searchState,
  filters,
  sorting,
  domainExpansion,
  tabErrorMessage,
  tabLoading,
  tabFetching,
  onPageChange,
  onPageSizeChange,
  onRemoveHistoryItem,
  onRetryOverview,
  onSortingChange,
  onTabChange,
  onViewChange,
  searchTabs,
}: BacklinksBodyProps) {
  const tabRows = useMemo<BacklinksTabRows>(
    () => ({
      backlinks: backlinksRowsPage?.rows ?? [],
      referringDomains: referringDomainsPage?.rows ?? [],
      topPages: topPagesPage?.rows ?? [],
    }),
    [backlinksRowsPage, referringDomainsPage, topPagesPage],
  );
  const activeTabPage =
    searchState.tab === "backlinks"
      ? backlinksRowsPage
      : searchState.tab === "domains"
        ? referringDomainsPage
        : topPagesPage;
  const summaryStats = useMemo(
    () => buildSummaryStats(overviewData),
    [overviewData],
  );
  const tabStrip = searchTabs ? (
    <SearchTabStrip
      projectId={projectId}
      activeTabId={searchTabs.activeTabId}
      tabs={searchTabs.tabs}
      onSelect={searchTabs.onSelect}
      onClose={searchTabs.onClose}
      onViewed={searchTabs.onViewed}
    />
  ) : null;

  if (!searchState.target) {
    return (
      <BacklinksHistorySection
        projectId={projectId}
        history={history}
        historyLoaded={historyLoaded}
        onRemoveHistoryItem={onRemoveHistoryItem}
      />
    );
  }

  if (overviewLoading) {
    return (
      <>
        {tabStrip}
        <BacklinksLoadingState />
      </>
    );
  }

  if (!overviewData) {
    return (
      <>
        {tabStrip}
        <BacklinksErrorState
          errorMessage={overviewError}
          onRetry={onRetryOverview}
        />
      </>
    );
  }

  return (
    <>
      {tabStrip}
      <BacklinksOverviewPanels
        projectId={projectId}
        data={overviewData}
        summaryStats={summaryStats}
      />
      <BacklinksResultsCard
        projectId={projectId}
        activeTab={searchState.tab}
        tabRows={tabRows}
        filters={filters}
        sorting={sorting}
        view={searchState.view}
        domainExpansion={domainExpansion}
        isTabLoading={tabLoading}
        tabErrorMessage={tabErrorMessage}
        exportTarget={overviewData.displayTarget || searchState.target}
        pagination={{
          page: searchState.page,
          pageSize: searchState.pageSize,
          totalCount: activeTabPage?.totalCount ?? null,
          hasNextPage: activeTabPage?.hasMore ?? false,
          isFetching: tabFetching,
        }}
        onPageChange={onPageChange}
        onPageSizeChange={onPageSizeChange}
        onSortingChange={onSortingChange}
        onTabChange={onTabChange}
        onViewChange={onViewChange}
      />
    </>
  );
}