// Copyright (c) 2025-2026 Probo Inc . // // Permission to use, copy, modify, and/or distribute this software for any // purpose with or without fee is hereby granted, provided that the above // copyright notice and this permission notice appear in all copies. // // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY // AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR // OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR // PERFORMANCE OF THIS SOFTWARE. import { useTranslate } from "@probo/i18n"; import { Button, IconChevronDown, IconChevronTriangleDownSmall, Spinner, Table, Th, } from "@probo/ui"; import { clsx } from "clsx"; import { type ComponentProps, createContext, startTransition, useContext, useState, } from "react"; import type { LoadMoreFn } from "react-relay"; import type { OperationType } from "relay-runtime"; export type Order = { direction: "ASC" | "DESC"; field: string; }; const defaultPageSize = 50; export const SortableContext = createContext({ order: { direction: "DESC", field: "CREATED_AT", }, changeOrder: (() => {}) as (order: Order) => void, }); const defaultOrder = { direction: "DESC", field: "CREATED_AT", } as Order; export function SortableTable({ refetch, hasNext, loadNext, isLoadingNext, pageSize = defaultPageSize, ...props }: ComponentProps & { refetch: (o: { order: Order }) => void; hasNext?: boolean; loadNext?: LoadMoreFn; isLoadingNext?: boolean; pageSize?: number; }) { const { __ } = useTranslate(); const [order, setOrder] = useState(defaultOrder); const changeOrder = (o: Order) => { startTransition(() => { setOrder(o); refetch({ order: o }); }); }; return (
{hasNext && loadNext && ( )} ); } export function SortableTh({ children, field, onOrderChange, ...props }: ComponentProps & { field: string; onOrderChange?: (order: { direction: "ASC" | "DESC"; field: string }) => void; }) { const { order, changeOrder } = useContext(SortableContext); const isCurrentField = order.field === field; const isDesc = order.direction === "DESC"; const handleChangeOrder = () => { const newOrder = { direction: isDesc && isCurrentField ? ("ASC" as const) : ("DESC" as const), field, }; changeOrder(newOrder); onOrderChange?.(newOrder); }; return ( ); }