feat(ticket): add issues map to ticket assignment page
This commit is contained in:
@@ -7,11 +7,16 @@ import { MultiSelectPopover } from '@/components/form/MultiSelectPopover';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { useDebounce } from '@/hooks/useDebounce';
|
||||
|
||||
import { useTicketDetectionsQuery } from '../../../hooks/useTicketQueries';
|
||||
import {
|
||||
useDetectionCoordinatesQuery,
|
||||
useTicketDetectionsQuery,
|
||||
} from '../../../hooks/useTicketQueries';
|
||||
import { AssignmentIssuesMap } from './AssignmentIssuesMap';
|
||||
import { useIssueColumns } from './IssueColumns';
|
||||
import { IssueTable } from './IssueTable';
|
||||
|
||||
const DEFAULT_PAGE_SIZE = 10;
|
||||
const MAP_PAGE_SIZE = 50;
|
||||
|
||||
interface IssueTypeOption {
|
||||
class_name: string;
|
||||
@@ -59,44 +64,87 @@ export function ChooseIssuesSection({
|
||||
[debouncedSearch, limit, selectedIssueTypes, skip],
|
||||
);
|
||||
const detectionsQuery = useTicketDetectionsQuery(videoId, queryParams);
|
||||
const mapQueryParams = useMemo(
|
||||
() => ({
|
||||
limit: MAP_PAGE_SIZE,
|
||||
class_name:
|
||||
selectedIssueTypes.length > 0 ? selectedIssueTypes : undefined,
|
||||
search: debouncedSearch || undefined,
|
||||
}),
|
||||
[debouncedSearch, selectedIssueTypes],
|
||||
);
|
||||
const coordinatesQuery = useDetectionCoordinatesQuery(
|
||||
videoId,
|
||||
mapQueryParams,
|
||||
);
|
||||
const result = detectionsQuery.data;
|
||||
const mapData = useMemo(() => {
|
||||
const pages = coordinatesQuery.data?.pages;
|
||||
|
||||
if (!pages?.length) return undefined;
|
||||
|
||||
const latestPage = pages[pages.length - 1];
|
||||
|
||||
return {
|
||||
...latestPage,
|
||||
items: pages.flatMap((page) => page.items),
|
||||
truncated: Boolean(coordinatesQuery.hasNextPage),
|
||||
};
|
||||
}, [coordinatesQuery.data?.pages, coordinatesQuery.hasNextPage]);
|
||||
|
||||
return (
|
||||
<IssueTable
|
||||
columns={columns}
|
||||
issues={result?.items ?? []}
|
||||
isLoading={detectionsQuery.isLoading || detectionsQuery.isFetching}
|
||||
isError={detectionsQuery.isError}
|
||||
toolbar={
|
||||
<div className="flex flex-col gap-3 sm:flex-row sm:items-center">
|
||||
<div className="w-fit">
|
||||
<MultiSelectPopover
|
||||
label="Issue Types"
|
||||
options={issueTypeOptions}
|
||||
values={selectedIssueTypes}
|
||||
onValuesChange={setSelectedIssueTypes}
|
||||
searchPlaceholder="Search issue types"
|
||||
emptyMessage="No issue types found."
|
||||
align="start"
|
||||
/>
|
||||
</div>
|
||||
<div className="relative w-full sm:ml-auto sm:w-72">
|
||||
<Search className="pointer-events-none absolute top-1/2 left-3 size-4 -translate-y-1/2 text-muted-foreground" />
|
||||
<Input
|
||||
value={detectionSearch}
|
||||
onChange={(event) => setDetectionSearch(event.target.value)}
|
||||
placeholder="Search by detection ID"
|
||||
aria-label="Search by detection ID"
|
||||
className="pl-9"
|
||||
/>
|
||||
</div>
|
||||
<div className="min-w-0 space-y-5">
|
||||
<div
|
||||
aria-label="Issue filters"
|
||||
className="flex flex-col gap-3 sm:flex-row sm:items-center"
|
||||
>
|
||||
<div className="w-fit">
|
||||
<MultiSelectPopover
|
||||
label="Issue Types"
|
||||
options={issueTypeOptions}
|
||||
values={selectedIssueTypes}
|
||||
onValuesChange={setSelectedIssueTypes}
|
||||
searchPlaceholder="Search issue types"
|
||||
emptyMessage="No issue types found."
|
||||
align="start"
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
skip={skip}
|
||||
limit={limit}
|
||||
total={result?.total ?? 0}
|
||||
onPageChange={setSkip}
|
||||
onLimitChange={setLimit}
|
||||
/>
|
||||
|
||||
<div className="relative w-full sm:ml-auto sm:w-72">
|
||||
<Search className="pointer-events-none absolute top-1/2 left-3 size-4 -translate-y-1/2 text-muted-foreground" />
|
||||
<Input
|
||||
id="assignment-issue-search"
|
||||
value={detectionSearch}
|
||||
onChange={(event) => setDetectionSearch(event.target.value)}
|
||||
placeholder="Search by detection ID"
|
||||
aria-label="Search by detection ID"
|
||||
className="pl-9"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<AssignmentIssuesMap
|
||||
data={mapData}
|
||||
isLoading={coordinatesQuery.isLoading}
|
||||
isFetchingMore={coordinatesQuery.isFetchingNextPage}
|
||||
isError={coordinatesQuery.isError}
|
||||
hasMore={Boolean(coordinatesQuery.hasNextPage)}
|
||||
onLoadMore={() => void coordinatesQuery.fetchNextPage()}
|
||||
onRetry={() => void coordinatesQuery.refetch()}
|
||||
/>
|
||||
|
||||
<IssueTable
|
||||
columns={columns}
|
||||
issues={result?.items ?? []}
|
||||
isLoading={detectionsQuery.isLoading || detectionsQuery.isFetching}
|
||||
isError={detectionsQuery.isError}
|
||||
toolbar={null}
|
||||
skip={skip}
|
||||
limit={limit}
|
||||
total={result?.total ?? 0}
|
||||
onPageChange={setSkip}
|
||||
onLimitChange={setLimit}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user