Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions src/core/components/Filter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -154,18 +154,20 @@ function DebouncedInput({
debounce?: number
} & Omit<React.InputHTMLAttributes<HTMLInputElement>, "onChange">) {
const [value, setValue] = React.useState(initialValue)
const onChangeRef = React.useRef(onChange)
onChangeRef.current = onChange

React.useEffect(() => {
setValue(initialValue)
}, [initialValue])

React.useEffect(() => {
const timeout = setTimeout(() => {
onChange(value)
onChangeRef.current(value)
}, debounce)

return () => clearTimeout(timeout)
}, [value, debounce, onChange])
}, [value, debounce])

return <input {...props} value={value} onChange={(e) => setValue(e.target.value)} />
}
Expand Down
41 changes: 38 additions & 3 deletions src/core/components/Table.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {
ColumnDef,
ColumnFiltersState,
FilterFn,
flexRender,
getCoreRowModel,
Expand Down Expand Up @@ -138,6 +139,8 @@ type TableProps<TData> = {
onPaginationChange?: OnChangeFn<PaginationState>
pageCount?: number
pageSizeOptions?: number[]
onGlobalFilterChange?: (filter: string) => void
onColumnFiltersChange?: (filters: ColumnFiltersState) => void
classNames?: {
table?: string
thead?: string
Expand Down Expand Up @@ -191,9 +194,12 @@ const Table = <TData,>({
onPaginationChange,
pageCount: controlledPageCount,
pageSizeOptions = [5, 10, 20, 30, 40, 50],
onGlobalFilterChange,
onColumnFiltersChange,
}: TableProps<TData>) => {
const [sorting, setSorting] = React.useState([])
const [globalFilter, setGlobalFilter] = React.useState("")
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>([])
const [internalPagination, setInternalPagination] = React.useState<PaginationState>({
pageIndex: 0,
pageSize: 5,
Expand Down Expand Up @@ -222,10 +228,12 @@ const Table = <TData,>({
pageCount: manualPagination ? controlledPageCount : undefined,
state: {
sorting: sorting,
columnFilters: columnFilters,
globalFilter: globalFilter,
pagination: resolvedPaginationState,
},
onSortingChange: setSorting,
onColumnFiltersChange: setColumnFilters,
onGlobalFilterChange: setGlobalFilter,
onPaginationChange: handlePaginationChange,
globalFilterFn: defaultGlobalFilterFn,
Expand All @@ -239,14 +247,41 @@ const Table = <TData,>({
const globalSearchTooltipId = React.useId()

React.useEffect(() => {
if (!addPagination) {
if (!addPagination) return
if (!manualPagination && pageCount > 0 && pageIndex >= pageCount) {
table.setPageIndex(0)
}
}, [addPagination, pageCount, pageIndex, table, manualPagination])

const isFirstFilterRender = React.useRef(true)
React.useEffect(() => {
if (isFirstFilterRender.current) {
isFirstFilterRender.current = false
return
}
if (!addPagination) return
if (manualPagination) {
onGlobalFilterChange?.(globalFilter)
} else {
table.setPageIndex(0)
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [globalFilter])

if (!manualPagination && pageCount > 0 && pageIndex >= pageCount) {
const isFirstColumnFilterRender = React.useRef(true)
React.useEffect(() => {
if (isFirstColumnFilterRender.current) {
isFirstColumnFilterRender.current = false
return
}
if (!addPagination) return
if (manualPagination) {
onColumnFiltersChange?.(columnFilters)
} else {
table.setPageIndex(0)
}
}, [addPagination, pageCount, pageIndex, table, manualPagination])
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [columnFilters])

return (
<>
Expand Down
3 changes: 3 additions & 0 deletions src/forms/components/FormsList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ type FormsListProps = {
onPaginationChange?: OnChangeFn<PaginationState>
pageCount?: number
pageSizeOptions?: number[]
onGlobalFilterChange?: (filter: string) => void
}

export const FormsList = ({
Expand All @@ -20,6 +21,7 @@ export const FormsList = ({
onPaginationChange,
pageCount,
pageSizeOptions,
onGlobalFilterChange,
}: FormsListProps) => {
const formsTableData = processForms(forms)

Expand All @@ -34,6 +36,7 @@ export const FormsList = ({
onPaginationChange={onPaginationChange}
pageCount={pageCount}
pageSizeOptions={pageSizeOptions}
onGlobalFilterChange={onGlobalFilterChange}
/>
</main>
)
Expand Down
8 changes: 8 additions & 0 deletions src/pages/forms/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const AllFormsPage = () => {
pageIndex: 0,
pageSize: 10,
})
const [search, setSearch] = useState("")

const paginationArgs = useMemo(
() => ({
Expand All @@ -39,6 +40,7 @@ const AllFormsPage = () => {
where: {
user: { id: currentUser?.id },
archived: false,
...(search ? { name: { contains: search, mode: "insensitive" } } : {}),
},
orderBy: { id: "desc" },
...paginationArgs,
Expand All @@ -52,6 +54,11 @@ const AllFormsPage = () => {
setPagination((prev) => (typeof updater === "function" ? updater(prev) : updater))
}

const handleGlobalFilterChange = (filter: string) => {
setSearch(filter)
setPagination((prev) => ({ ...prev, pageIndex: 0 }))
}

return (
// @ts-expect-error children are clearly passed below
<Layout title="Forms">
Expand Down Expand Up @@ -91,6 +98,7 @@ const AllFormsPage = () => {
onPaginationChange={handlePaginationChange}
pageCount={pageCount}
pageSizeOptions={[10, 25, 50, 100]}
onGlobalFilterChange={handleGlobalFilterChange}
/>
</Card>
</Suspense>
Expand Down
57 changes: 44 additions & 13 deletions src/pages/notifications/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { MultiReadToggleButton } from "src/notifications/components/MultiReadTog
import { InformationCircleIcon } from "@heroicons/react/24/outline"
import { Tooltip } from "react-tooltip"
import Card from "src/core/components/Card"
import { PaginationState } from "@tanstack/react-table"
import { ColumnFiltersState, PaginationState } from "@tanstack/react-table"
import { Prisma } from "db"

const NotificationContent = () => {
Expand All @@ -31,30 +31,47 @@ const NotificationContent = () => {
pageIndex: 0,
pageSize: 10,
})
const [search, setSearch] = useState("")
const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([])

const baseWhere = useMemo<Prisma.NotificationWhereInput>(
const coreWhere = useMemo<Prisma.NotificationWhereInput>(
() => ({
recipients: {
some: {
id: currentUser!.id,
},
},
// Only include notifications for projects where the contributor is not deleted
recipients: { some: { id: currentUser!.id } },
project: {
projectMembers: {
some: {
users: {
some: { id: currentUser!.id },
},
name: null, // Contributor (indicating it's not a team)
deleted: false, // Only include undeleted project members
users: { some: { id: currentUser!.id } },
name: null,
deleted: false,
},
},
},
}),
[currentUser]
)

const baseWhere = useMemo<Prisma.NotificationWhereInput>(() => {
const conditions: Prisma.NotificationWhereInput[] = [coreWhere]
if (search) {
conditions.push({
OR: [
{ message: { contains: search, mode: "insensitive" } },
{ project: { name: { contains: search, mode: "insensitive" } } },
],
})
}
for (const filter of columnFilters) {
const value = String(filter.value ?? "").trim()
if (!value) continue
if (filter.id === "readStatus") {
conditions.push({ read: value === "Read" })
} else if (filter.id === "projectName") {
conditions.push({ project: { name: { contains: value, mode: "insensitive" } } })
}
}
return conditions.length === 1 ? conditions[0]! : { AND: conditions }
}, [coreWhere, search, columnFilters])

const paginationArgs = useMemo(
() => ({
skip: pagination.pageIndex * pagination.pageSize,
Expand Down Expand Up @@ -103,6 +120,18 @@ const NotificationContent = () => {
disableGlobalSelection()
}

const handleGlobalFilterChange = (filter: string) => {
setSearch(filter)
setPagination((prev) => ({ ...prev, pageIndex: 0 }))
disableGlobalSelection()
}

const handleColumnFiltersChange = (filters: ColumnFiltersState) => {
setColumnFilters(filters)
setPagination((prev) => ({ ...prev, pageIndex: 0 }))
disableGlobalSelection()
}

const handleActionCompleted = async () => {
await refetch()
resetSelection()
Expand Down Expand Up @@ -169,6 +198,8 @@ const NotificationContent = () => {
onPaginationChange={handlePaginationChange}
pageCount={pageCount}
pageSizeOptions={[10, 25, 50, 100]}
onGlobalFilterChange={handleGlobalFilterChange}
onColumnFiltersChange={handleColumnFiltersChange}
/>
</Card>
</main>
Expand Down
46 changes: 39 additions & 7 deletions src/pages/projects/[projectId]/notifications/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { MultiReadToggleButton } from "src/notifications/components/MultiReadTog
import Card from "src/core/components/Card"
import { InformationCircleIcon } from "@heroicons/react/24/outline"
import { Tooltip } from "react-tooltip"
import { PaginationState } from "@tanstack/react-table"
import { ColumnFiltersState, PaginationState } from "@tanstack/react-table"
import { Prisma } from "db"

const NotificationContent = () => {
Expand All @@ -31,19 +31,37 @@ const NotificationContent = () => {
pageIndex: 0,
pageSize: 10,
})
const [search, setSearch] = useState("")
const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([])

const baseWhere = useMemo<Prisma.NotificationWhereInput>(
const coreWhere = useMemo<Prisma.NotificationWhereInput>(
() => ({
recipients: {
some: {
id: currentUser!.id,
},
},
recipients: { some: { id: currentUser!.id } },
projectId: projectId ?? undefined,
}),
[currentUser, projectId]
)

const baseWhere = useMemo<Prisma.NotificationWhereInput>(() => {
const conditions: Prisma.NotificationWhereInput[] = [coreWhere]
if (search) {
conditions.push({
OR: [
{ message: { contains: search, mode: "insensitive" } },
{ project: { name: { contains: search, mode: "insensitive" } } },
],
})
}
for (const filter of columnFilters) {
const value = String(filter.value ?? "").trim()
if (!value) continue
if (filter.id === "readStatus") {
conditions.push({ read: value === "Read" })
}
}
return conditions.length === 1 ? conditions[0]! : { AND: conditions }
}, [coreWhere, search, columnFilters])

const paginationArgs = useMemo(
() => ({
skip: pagination.pageIndex * pagination.pageSize,
Expand Down Expand Up @@ -93,6 +111,18 @@ const NotificationContent = () => {
disableGlobalSelection()
}

const handleGlobalFilterChange = (filter: string) => {
setSearch(filter)
setPagination((prev) => ({ ...prev, pageIndex: 0 }))
disableGlobalSelection()
}

const handleColumnFiltersChange = (filters: ColumnFiltersState) => {
setColumnFilters(filters)
setPagination((prev) => ({ ...prev, pageIndex: 0 }))
disableGlobalSelection()
}

const handleActionCompleted = async () => {
await refetch()
resetSelection()
Expand Down Expand Up @@ -158,6 +188,8 @@ const NotificationContent = () => {
onPaginationChange={handlePaginationChange}
pageCount={pageCount}
pageSizeOptions={[10, 25, 50, 100]}
onGlobalFilterChange={handleGlobalFilterChange}
onColumnFiltersChange={handleColumnFiltersChange}
/>
</Card>
</main>
Expand Down
9 changes: 8 additions & 1 deletion src/pages/projects/[projectId]/teams/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,12 @@ export const AllTeamList = ({ privilege, projectId }: AllTeamListProps) => {
pageIndex: 0,
pageSize: 10,
})
const [search, setSearch] = useState("")

const [{ projectMembers, count }] = usePaginatedQuery(getProjectMembers, {
where: {
projectId: projectId,
name: { not: null }, // Ensures the name in ProjectMember is non-null
name: { not: null, ...(search ? { contains: search, mode: "insensitive" } : {}) },
users: {
some: { id: { not: undefined } }, // Ensures there's at least one user
},
Expand Down Expand Up @@ -67,6 +68,11 @@ export const AllTeamList = ({ privilege, projectId }: AllTeamListProps) => {
setPagination((prev) => (typeof updater === "function" ? updater(prev) : updater))
}

const handleGlobalFilterChange = (filter: string) => {
setSearch(filter)
setPagination((prev) => ({ ...prev, pageIndex: 0 }))
}

return (
<div>
<Table
Expand All @@ -78,6 +84,7 @@ export const AllTeamList = ({ privilege, projectId }: AllTeamListProps) => {
onPaginationChange={handlePaginationChange}
pageCount={pageCount}
pageSizeOptions={[10, 25, 50, 100]}
onGlobalFilterChange={handleGlobalFilterChange}
/>
</div>
)
Expand Down
Loading
Loading