~ knotless Search/
↑↓ move↵ open⇧↵ all results

chadtmiller.com/pds.js

An atproto PDS in JavaScript, for Cloudflare Workers and Node

0
0
main
86 lines · 2.6 KB Raw History
import { useInfiniteQuery } from '@tanstack/react-query';
import { HistoryIcon } from 'lucide-react';
import { Notice } from '#/components/atoms/notice.jsx';
import { Panel } from '#/components/atoms/panel.jsx';
import { Skeleton } from '#/components/atoms/skeleton.jsx';
import { ActivityList } from '#/components/molecules/activity-list.jsx';
import { EmptyState } from '#/components/molecules/empty-state.jsx';
import { TextLink } from '#/components/molecules/text-link.jsx';
import { get } from '#/lib/api.js';
import { queryKeys } from '#/lib/query.js';

export function HistoryPage({ recordHref, onNavigate }) {
  const {
    data,
    error,
    isPending,
    hasNextPage,
    fetchNextPage,
    isFetchingNextPage,
  } = useInfiniteQuery({
    queryKey: queryKeys.activity,
    queryFn: ({ pageParam }) =>
      get(
        pageParam
          ? `/activity?limit=40&cursor=${encodeURIComponent(pageParam)}`
          : '/activity?limit=40',
      ),
    initialPageParam: null,
    getNextPageParam: (last) => last.cursor ?? undefined,
  });

  if (error) return <Notice variant="error">{error.message}</Notice>;
  if (isPending) {
    return (
      <Panel>
        <div className="flex flex-col gap-1">
          {['a', 'b', 'c', 'd', 'e', 'f'].map((key) => (
            <div key={key} className="flex items-center gap-4 px-1 py-3">
              <Skeleton className="size-9 rounded-xl" />
              <div className="flex-1 space-y-2">
                <Skeleton className="h-3.5 w-48 max-w-full" />
                <Skeleton className="h-3 w-24" />
              </div>
              <Skeleton className="h-3 w-12" />
            </div>
          ))}
        </div>
      </Panel>
    );
  }

  const events = data.pages.flatMap((page) => page.events);
  if (events.length === 0) {
    return (
      <EmptyState
        className="py-16"
        icon={<HistoryIcon />}
        title="No history yet"
        description="Every record an app adds, changes or removes will be listed here, newest first."
      />
    );
  }

  return (
    <Panel>
      <p className="mb-4 border-border border-b pb-4 text-[12px] text-faint leading-relaxed">
        This is the activity this server has kept. It stays here and does not
        move with your account if you change hosts.
      </p>
      <ActivityList
        events={events}
        recordHref={recordHref}
        onNavigate={onNavigate}
      />
      {hasNextPage && (
        <TextLink
          className="mt-3"
          onClick={() => fetchNextPage()}
          disabled={isFetchingNextPage}
        >
          {isFetchingNextPage ? 'Loading…' : 'Load more'}
        </TextLink>
      )}
    </Panel>
  );
}