11"use client" ;
22
3- import { keepPreviousData } from "@tanstack/react-query" ;
4- import { getCoreRowModel , getSortedRowModel , useReactTable , type ColumnDef } from "@tanstack/react-table" ;
5- import { useMemo , useState } from "react" ;
3+ import { useState } from "react" ;
64
7- import { DataTableWrapper , DataTableToolbar , useDataTable } from "@calcom/features/data-table" ;
5+ import { DataTableToolbar } from "@calcom/features/data-table" ;
86import { useLocale } from "@calcom/lib/hooks/useLocale" ;
9- import { trpc } from "@calcom/trpc" ;
10- import type { RouterOutputs } from "@calcom/trpc/react" ;
11- import { Badge } from "@calcom/ui/components/badge" ;
127import { Button } from "@calcom/ui/components/button" ;
13- import { ButtonGroup } from "@calcom/ui/components/buttonGroup" ;
14- import { ConfirmationDialogContent , Dialog } from "@calcom/ui/components/dialog" ;
15- import { showToast } from "@calcom/ui/components/toast" ;
8+ import { ToggleGroup } from "@calcom/ui/components/form" ;
169
17- import { BlocklistEntryDetailsSheet } from "./components/blocklist-entry-details-sheet" ;
10+ import PendingReportsBadge from "./components/PendingReportsBadge" ;
11+ import { BlockedEntriesTable } from "./components/blocked-entries-table" ;
1812import { CreateBlocklistEntryModal } from "./components/create-blocklist-entry-modal" ;
13+ import { PendingReportsTable } from "./components/pending-reports-table" ;
1914
20- type BlocklistEntry = RouterOutputs [ "viewer" ] [ "organizations" ] [ "listWatchlistEntries" ] [ "rows" ] [ number ] ;
15+ type ViewType = "blocked" | "pending" ;
2116
2217interface BlocklistTableProps {
2318 permissions ?: {
@@ -29,179 +24,49 @@ interface BlocklistTableProps {
2924
3025export function BlocklistTable ( { permissions } : BlocklistTableProps ) {
3126 const { t } = useLocale ( ) ;
32- const { limit, offset, searchTerm } = useDataTable ( ) ;
33-
27+ const [ activeView , setActiveView ] = useState < ViewType > ( "blocked" ) ;
3428 const [ showCreateModal , setShowCreateModal ] = useState ( false ) ;
35- const [ showDetailsSheet , setShowDetailsSheet ] = useState ( false ) ;
36- const [ selectedEntry , setSelectedEntry ] = useState < BlocklistEntry | null > ( null ) ;
37- const [ entryToDelete , setEntryToDelete ] = useState < BlocklistEntry | null > ( null ) ;
38- const [ showDeleteDialog , setShowDeleteDialog ] = useState ( false ) ;
39-
40- const { data, isPending } = trpc . viewer . organizations . listWatchlistEntries . useQuery (
41- {
42- limit,
43- offset,
44- searchTerm,
45- } ,
46- {
47- placeholderData : keepPreviousData ,
48- }
49- ) ;
50-
51- const utils = trpc . useUtils ( ) ;
52-
53- const deleteWatchlistEntry = trpc . viewer . organizations . deleteWatchlistEntry . useMutation ( {
54- onSuccess : async ( ) => {
55- await utils . viewer . organizations . listWatchlistEntries . invalidate ( ) ;
56- showToast ( t ( "blocklist_entry_deleted" ) , "success" ) ;
57- setShowDeleteDialog ( false ) ;
58- setEntryToDelete ( null ) ;
59- } ,
60- onError : ( error ) => {
61- showToast ( error . message , "error" ) ;
62- } ,
63- } ) ;
64-
65- const handleDelete = ( entry : BlocklistEntry ) => {
66- setEntryToDelete ( entry ) ;
67- setShowDeleteDialog ( true ) ;
68- } ;
69-
70- const confirmDelete = ( ) => {
71- if ( entryToDelete ) {
72- deleteWatchlistEntry . mutate ( { id : entryToDelete . id } ) ;
73- }
74- } ;
75-
76- const handleViewDetails = ( entry : BlocklistEntry ) => {
77- setSelectedEntry ( entry ) ;
78- setShowDetailsSheet ( true ) ;
79- } ;
80-
81- const totalRowCount = data ?. meta ?. totalRowCount ?? 0 ;
82- const flatData = useMemo < BlocklistEntry [ ] > ( ( ) => data ?. rows ?? [ ] , [ data ] ) ;
83-
84- const columns = useMemo < ColumnDef < BlocklistEntry > [ ] > (
85- ( ) => [
86- {
87- id : "value" ,
88- header : t ( "value" ) ,
89- accessorKey : "value" ,
90- enableHiding : false ,
91- cell : ( { row } ) => < span className = "text-emphasis" > { row . original . value } </ span > ,
92- } ,
93- {
94- id : "type" ,
95- header : t ( "type" ) ,
96- accessorKey : "type" ,
97- size : 100 ,
98- cell : ( { row } ) => (
99- < Badge variant = "blue" > { row . original . type === "EMAIL" ? t ( "email" ) : t ( "domain" ) } </ Badge >
100- ) ,
101- } ,
102- {
103- id : "createdBy" ,
104- header : t ( "blocked_by" ) ,
105- size : 180 ,
106- cell : ( { row } ) => {
107- const audit = row . original . audits ?. [ 0 ] as
108- | { changedByUserId : number | null }
109- | {
110- changedByUser ?: { id : number ; email : string ; name : string | null } | undefined ;
111- changedByUserId : number | null ;
112- }
113- | undefined ;
114- const email =
115- ( audit && "changedByUser" in audit ? audit . changedByUser ?. email : undefined ) ?? undefined ;
116- return < span className = "text-default" > { email ?? "—" } </ span > ;
117- } ,
118- } ,
119- {
120- id : "actions" ,
121- header : "" ,
122- size : 120 ,
123- enableHiding : false ,
124- enableSorting : false ,
125- enableResizing : false ,
126- cell : ( { row } ) => {
127- const entry = row . original ;
128- return (
129- < div className = "flex items-center justify-end" >
130- < ButtonGroup combined containerProps = { { className : "border-default" } } >
131- < Button
132- color = "secondary"
133- variant = "icon"
134- StartIcon = "eye"
135- onClick = { ( ) => handleViewDetails ( entry ) }
136- tooltip = { t ( "view" ) }
137- />
138- { permissions ?. canDelete && (
139- < Button
140- color = "destructive"
141- variant = "icon"
142- StartIcon = "trash"
143- onClick = { ( ) => handleDelete ( entry ) }
144- tooltip = { t ( "delete" ) }
145- />
146- ) }
147- </ ButtonGroup >
148- </ div >
149- ) ;
150- } ,
151- } ,
152- ] ,
153- [ t , permissions ?. canDelete ]
154- ) ;
155-
156- const table = useReactTable ( {
157- data : flatData ,
158- columns,
159- getCoreRowModel : getCoreRowModel ( ) ,
160- getSortedRowModel : getSortedRowModel ( ) ,
161- manualPagination : true ,
162- pageCount : Math . ceil ( totalRowCount / limit ) ,
163- } ) ;
16429
16530 return (
16631 < >
167- < DataTableWrapper
168- table = { table }
169- isPending = { isPending }
170- variant = "default"
171- paginationMode = "standard"
172- totalRowCount = { totalRowCount } >
173- < div className = "flex items-center justify-between" >
32+ < div className = "mb-4 flex items-center justify-between" >
33+ < div className = "flex items-center gap-2" >
34+ < ToggleGroup
35+ value = { activeView }
36+ onValueChange = { ( value ) => {
37+ if ( value ) setActiveView ( value as ViewType ) ;
38+ } }
39+ options = { [
40+ { value : "blocked" , label : t ( "blocked" ) } ,
41+ {
42+ value : "pending" ,
43+ label : (
44+ < span className = "flex items-center" >
45+ { t ( "pending" ) }
46+ < PendingReportsBadge />
47+ </ span >
48+ ) ,
49+ } ,
50+ ] }
51+ />
17452 < DataTableToolbar . SearchBar />
175- < div className = "flex items-center gap-2" >
176- { permissions ?. canCreate && (
177- < Button color = "primary" StartIcon = "plus" onClick = { ( ) => setShowCreateModal ( true ) } >
178- { t ( "create_block_entry" ) }
179- </ Button >
180- ) }
181- </ div >
18253 </ div >
183- </ DataTableWrapper >
184-
185- < CreateBlocklistEntryModal isOpen = { showCreateModal } onClose = { ( ) => setShowCreateModal ( false ) } />
54+ < div className = "flex items-center gap-2" >
55+ { permissions ?. canCreate && (
56+ < Button color = "primary" StartIcon = "plus" onClick = { ( ) => setShowCreateModal ( true ) } >
57+ { t ( "add" ) }
58+ </ Button >
59+ ) }
60+ </ div >
61+ </ div >
18662
187- < BlocklistEntryDetailsSheet
188- entry = { selectedEntry }
189- isOpen = { showDetailsSheet }
190- onClose = { ( ) => {
191- setShowDetailsSheet ( false ) ;
192- setSelectedEntry ( null ) ;
193- } }
194- />
63+ { activeView === "blocked" ? (
64+ < BlockedEntriesTable permissions = { permissions } onAddClick = { ( ) => setShowCreateModal ( true ) } />
65+ ) : (
66+ < PendingReportsTable />
67+ ) }
19568
196- < Dialog open = { showDeleteDialog } onOpenChange = { setShowDeleteDialog } >
197- < ConfirmationDialogContent
198- variety = "danger"
199- title = { t ( "delete_blocklist_entry" ) }
200- confirmBtnText = { t ( "delete" ) }
201- onConfirm = { confirmDelete } >
202- { t ( "delete_blocklist_entry_confirmation" , { value : entryToDelete ?. value } ) }
203- </ ConfirmationDialogContent >
204- </ Dialog >
69+ < CreateBlocklistEntryModal isOpen = { showCreateModal } onClose = { ( ) => setShowCreateModal ( false ) } />
20570 </ >
20671 ) ;
20772}
0 commit comments