UsersFooter.tsx139 lines · main
1import { THRESHOLD_COUNT, type OptimizedSearchColumns } from '@supabase/pg-meta'
2import { keepPreviousData } from '@tanstack/react-query'
3import { useParams } from 'common'
4import { HelpCircle, Loader2 } from 'lucide-react'
5import { useEffect, useState } from 'react'
6import { Button, Tooltip, TooltipContent, TooltipTrigger } from 'ui'
7import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal'
8
9import type { Filter, SpecificFilterColumn } from './Users.constants'
10import { formatEstimatedCount } from '@/components/grid/components/footer/pagination/Pagination.utils'
11import { useUsersCountQuery } from '@/data/auth/users-count-query'
12import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject'
13
14interface UsersFooterProps {
15 filter: Filter
16 filterKeywords: string
17 selectedProviders: string[]
18 specificFilterColumn: SpecificFilterColumn
19}
20
21export const UsersFooter = ({
22 filter,
23 filterKeywords,
24 selectedProviders,
25 specificFilterColumn,
26}: UsersFooterProps) => {
27 const { ref: projectRef } = useParams()
28 const { data: project } = useSelectedProjectQuery()
29
30 const [forceExactCount, setForceExactCount] = useState(false)
31 const [showFetchExactCountModal, setShowFetchExactCountModal] = useState(false)
32
33 const {
34 data: countData,
35 isPending: isLoadingCount,
36 isFetching: isFetchingCount,
37 isSuccess: isSuccessCount,
38 } = useUsersCountQuery(
39 {
40 projectRef,
41 connectionString: project?.connectionString,
42 keywords: filterKeywords,
43 filter: filter === 'all' ? undefined : filter,
44 providers: selectedProviders,
45 forceExactCount,
46 // Use optimized search when filtering by specific column
47 ...(specificFilterColumn !== 'freeform'
48 ? { column: specificFilterColumn as OptimizedSearchColumns }
49 : { column: undefined }),
50 },
51 { placeholderData: keepPreviousData }
52 )
53 const totalUsers = countData?.count ?? 0
54
55 useEffect(() => {
56 if (isSuccessCount && specificFilterColumn === 'freeform') {
57 setForceExactCount(countData.is_estimate && countData.count <= THRESHOLD_COUNT)
58 }
59 // eslint-disable-next-line react-hooks/exhaustive-deps
60 }, [isSuccessCount, specificFilterColumn])
61
62 return (
63 <>
64 <div className="flex justify-between min-h-9 h-9 overflow-hidden items-center px-6 w-full border-t text-xs text-foreground-light">
65 <div className="flex items-center gap-x-2">
66 {isLoadingCount || isFetchingCount || countData === undefined ? (
67 <span className="flex items-center gap-2">
68 <Loader2 size={14} className="animate-spin" /> Loading...
69 </span>
70 ) : (
71 <>
72 <span>
73 Total:{' '}
74 {countData?.is_estimate
75 ? formatEstimatedCount(totalUsers)
76 : totalUsers.toLocaleString()}{' '}
77 user{totalUsers !== 1 ? 's' : ''}
78 {countData?.is_estimate && ' (estimated)'}
79 </span>
80 {countData?.is_estimate && (
81 <Tooltip>
82 <TooltipTrigger asChild>
83 <Button
84 size="tiny"
85 type="text"
86 className="px-1.5"
87 icon={<HelpCircle />}
88 onClick={() => {
89 if (specificFilterColumn === 'freeform') {
90 setShowFetchExactCountModal(true)
91 }
92 }}
93 />
94 </TooltipTrigger>
95 <TooltipContent side="top" className="w-80">
96 {specificFilterColumn === 'freeform' ? (
97 <>
98 This is an estimated value as your project has more than{' '}
99 {THRESHOLD_COUNT.toLocaleString()} users.
100 <br />
101 <span className="text-brand">Click to retrieve the exact count.</span>{' '}
102 </>
103 ) : (
104 <>
105 <p className="mb-1">
106 This is an estimated value which may not be accurate.
107 </p>
108 <p>
109 If you'd like to retrieve the exact count, change the search to{' '}
110 <span className="text-warning">all columns</span> from the header.
111 </p>{' '}
112 </>
113 )}
114 </TooltipContent>
115 </Tooltip>
116 )}
117 </>
118 )}
119 </div>
120 </div>
121 <ConfirmationModal
122 variant="warning"
123 visible={showFetchExactCountModal}
124 title="Fetch exact user count"
125 confirmLabel="Fetch exact count"
126 onCancel={() => setShowFetchExactCountModal(false)}
127 onConfirm={() => {
128 setForceExactCount(true)
129 setShowFetchExactCountModal(false)
130 }}
131 >
132 <p className="text-sm text-foreground-light">
133 Your project has more than {THRESHOLD_COUNT.toLocaleString()} users, and fetching the
134 exact count may cause performance issues on your database.
135 </p>
136 </ConfirmationModal>
137 </>
138 )
139}