event.stopPropagation()} className="flex items-center gap-1.5">
-
+
+
+
+
+ void toggleWaVisibility(group.id, group.title, group.hide)}
+ />
+
+
+
+ setEditingKey(row.original.key)} />
+
+
+
+
)
}
@@ -200,20 +173,33 @@ export function CombinedGroupsTable({
const pending = updatingId === group.telegramId
const visible = !group.hide
return (
-
event.stopPropagation()} className="flex items-center gap-1.5">
-
-
+
+
+
+
+
+ void toggleVisibility(group.telegramId, group.title, group.hide)}
+ />
+
+
+
+
setEditingKey(row.original.key)} />
+
+
+
+
)
},
@@ -227,8 +213,15 @@ export function CombinedGroupsTable({
data: displayRows,
getRowId: (row) => row.key,
initialState: { sorting: [{ id: "title", desc: false }], pagination: { pageIndex: 0, pageSize: 20 } },
+ autoResetPageIndex: false,
})
+ useEffect(() => {
+ const pageCount = table.getPageCount()
+ if (table.state.pagination.pageIndex >= pageCount) table.setPageIndex(Math.max(0, pageCount - 1))
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [displayRows.length])
+
const editingGroupRef =
editingRow?.platform === "telegram"
? { id: editingRow.group.telegramId, title: editingRow.title, type: "tg" as const }
@@ -275,19 +268,7 @@ export function CombinedGroupsTable({
{table.getRowModel().rows.map((row) => (
- setEditingKey(row.original.key)}
- onKeyDown={(event) => {
- if (event.key === "Enter" || event.key === " ") {
- event.preventDefault()
- setEditingKey(row.original.key)
- }
- }}
- >
+
{row.getAllCells().map((cell) => (
diff --git a/src/features/telegram/groups-table.tsx b/src/features/telegram/groups-table.tsx
index cd70807..441d1f4 100644
--- a/src/features/telegram/groups-table.tsx
+++ b/src/features/telegram/groups-table.tsx
@@ -1,22 +1,12 @@
import { useRouter } from "@tanstack/react-router"
import { useServerFn } from "@tanstack/react-start"
import type { Column } from "@tanstack/react-table"
-import {
- ArrowDown,
- ArrowUp,
- ChevronsUpDown,
- ExternalLink,
- Eye,
- EyeOff,
- LoaderCircle,
- type LucideIcon,
- MessageCircleMore,
- X,
-} from "lucide-react"
-import { useMemo, useState } from "react"
+import { ArrowDown, ArrowUp, ChevronsUpDown, type LucideIcon, MessageCircleMore } from "lucide-react"
+import { useEffect, useMemo, useState } from "react"
import { toast } from "sonner"
import { EmptyState } from "@/components/empty-state"
+import { InviteLinkButton, VisibilityToggleButton, EditLabelsButton } from "@/components/group-action-buttons"
import { Pagination } from "@/components/pagination"
import { Alert, AlertDescription } from "@/components/ui/alert"
import { Badge } from "@/components/ui/badge"
@@ -29,11 +19,10 @@ import { LeaveGroupDialog } from "@/features/telegram/leave-group-dialog"
import { useGroupVisibilityToggle } from "@/hooks/use-group-visibility-toggle"
import type { TgGroup, TgGroupLabel } from "@/lib/api/types"
import { createAppColumnHelper, type dashboardFeatures, useAppTable } from "@/lib/table"
-import { cn } from "@/lib/utils"
const groupColumnHelper = createAppColumnHelper()
-/** The interactive groups table (visibility toggle, invite link, leave, click-to-edit-labels), given an already-filtered group list. */
+/** The interactive groups table (visibility toggle, invite link, leave, edit labels), given an already-filtered group list. */
export function GroupsTable({
groups: loadedGroups,
allLabels,
@@ -56,10 +45,15 @@ export function GroupsTable({
)
const [editingGroup, setEditingGroup] = useState(null)
- const groups = loadedGroups.map((group) => ({
- ...group,
- hide: resolveHide(group.telegramId, group.hide),
- }))
+ // Keep the data reference stable across table-state renders; TanStack Table resets pagination when data changes.
+ const groups = useMemo(
+ () =>
+ loadedGroups.map((group) => ({
+ ...group,
+ hide: resolveHide(group.telegramId, group.hide),
+ })),
+ [loadedGroups, resolveHide]
+ )
const columns = useMemo(() => {
const sortableHeader = (
@@ -114,30 +108,6 @@ export function GroupsTable({
header: "Labels",
cell: ({ row }) => ,
}),
- groupColumnHelper.display({
- id: "invite",
- header: "",
- cell: ({ row }) => {
- const link = row.original.link
- return link ? (
- event.stopPropagation()}
- >
-
- Open invite link
-
- ) : (
-
-
- Not shared
-
- )
- },
- }),
groupColumnHelper.display({
id: "actions",
header: "",
@@ -146,20 +116,24 @@ export function GroupsTable({
const pending = updatingId === group.telegramId
const visible = !group.hide
return (
- event.stopPropagation()} className="flex items-center gap-1.5">
-
-
+
+
+
+
+
+ void toggleVisibility(group.telegramId, group.title, group.hide)}
+ />
+
+
+ setEditingGroup(group)} />
+
+
+
+
)
},
@@ -175,8 +149,15 @@ export function GroupsTable({
sorting: [{ id: "title", desc: false }],
pagination: { pageIndex: 0, pageSize: 20 },
},
+ autoResetPageIndex: false,
})
+ useEffect(() => {
+ const pageCount = table.getPageCount()
+ if (table.state.pagination.pageIndex >= pageCount) table.setPageIndex(Math.max(0, pageCount - 1))
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [groups.length])
+
return (
<>
{mutationError && (
@@ -215,19 +196,7 @@ export function GroupsTable({
{table.getRowModel().rows.map((row) => (
- setEditingGroup(row.original)}
- onKeyDown={(event) => {
- if (event.key === "Enter" || event.key === " ") {
- event.preventDefault()
- setEditingGroup(row.original)
- }
- }}
- >
+
{row.getAllCells().map((cell) => (
diff --git a/src/features/telegram/users-page.tsx b/src/features/telegram/users-page.tsx
index e50a4fa..882ce9f 100644
--- a/src/features/telegram/users-page.tsx
+++ b/src/features/telegram/users-page.tsx
@@ -103,7 +103,10 @@ export function TelegramUsersPage({ users }: { users: TgUser[] }) {
{table.getHeaderGroups().map((headerGroup) => (
{headerGroup.headers.map((header) => (
-
+
{header.isPlaceholder ? null : }
))}
@@ -134,7 +137,10 @@ export function TelegramUsersPage({ users }: { users: TgUser[] }) {
}}
>
{row.getAllCells().map((cell) => (
-
+
))}
diff --git a/src/features/whatsapp/create-edit-group-dialog.tsx b/src/features/whatsapp/create-edit-group-dialog.tsx
index 5a28b13..282a047 100644
--- a/src/features/whatsapp/create-edit-group-dialog.tsx
+++ b/src/features/whatsapp/create-edit-group-dialog.tsx
@@ -107,7 +107,19 @@ export function CreateEditGroupDialog({
if (!nextOpen) reset()
}}
>
- : }>
+
+ ) : (
+
+ )
+ }
+ >
{group ? (
<>
diff --git a/src/features/whatsapp/whatsapp-groups-page.tsx b/src/features/whatsapp/whatsapp-groups-page.tsx
index 14160bc..e4f9fab 100644
--- a/src/features/whatsapp/whatsapp-groups-page.tsx
+++ b/src/features/whatsapp/whatsapp-groups-page.tsx
@@ -1,23 +1,13 @@
import { useRouter } from "@tanstack/react-router"
import { useServerFn } from "@tanstack/react-start"
import type { Column } from "@tanstack/react-table"
-import {
- ArrowDown,
- ArrowUp,
- ChevronsUpDown,
- ExternalLink,
- Eye,
- EyeOff,
- LoaderCircle,
- MessageCircleMore,
- Tag,
- X,
-} from "lucide-react"
-import { useMemo, useState } from "react"
+import { ArrowDown, ArrowUp, ChevronsUpDown, MessageCircleMore, Tag } from "lucide-react"
+import { useEffect, useMemo, useState } from "react"
import { toast } from "sonner"
import { DataToolbar } from "@/components/data-toolbar"
import { EmptyState } from "@/components/empty-state"
+import { InviteLinkButton, VisibilityToggleButton, EditLabelsButton } from "@/components/group-action-buttons"
import { Pagination } from "@/components/pagination"
import { Alert, AlertDescription } from "@/components/ui/alert"
import { Badge } from "@/components/ui/badge"
@@ -42,7 +32,6 @@ import { setWhatsappGroupVisibility } from "@/features/whatsapp/groups.functions
import { useGroupVisibilityToggle } from "@/hooks/use-group-visibility-toggle"
import type { GroupWithLabels, TgGroupLabel, WaGroup } from "@/lib/api/types"
import { createAppColumnHelper, type dashboardFeatures, useAppTable } from "@/lib/table"
-import { cn } from "@/lib/utils"
function setManyGroupLabels(current: TgGroupLabel[], labels: TgGroupLabel[], select: boolean): TgGroupLabel[] {
if (select) {
@@ -136,30 +125,6 @@ export function WhatsappGroupsPage({
header: "Labels",
cell: ({ row }) => ,
}),
- groupColumnHelper.display({
- id: "invite",
- header: "",
- cell: ({ row }) => {
- const link = row.original.link
- return link ? (
- event.stopPropagation()}
- >
-
- Open invite link
-
- ) : (
-
-
- Not shared
-
- )
- },
- }),
groupColumnHelper.display({
id: "actions",
header: "",
@@ -168,25 +133,25 @@ export function WhatsappGroupsPage({
const pending = updatingId === group.id
const visible = !group.hide
return (
- event.stopPropagation()} className="flex items-center gap-1.5">
-
-
-
+
+
+
+
+
+ void toggleVisibility(group.id, group.title, group.hide)}
+ />
+
+
+
+ setEditingLabelsGroup(group)} />
+
+
+
+
)
},
@@ -200,8 +165,15 @@ export function WhatsappGroupsPage({
data: visibleGroups,
getRowId: (group) => String(group.id),
initialState: { sorting: [{ id: "title", desc: false }], pagination: { pageIndex: 0, pageSize: 20 } },
+ autoResetPageIndex: false,
})
+ useEffect(() => {
+ const pageCount = table.getPageCount()
+ if (table.state.pagination.pageIndex >= pageCount) table.setPageIndex(Math.max(0, pageCount - 1))
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [visibleGroups.length])
+
return (
{mutationError && (
@@ -316,19 +288,7 @@ export function WhatsappGroupsPage({
{table.getRowModel().rows.map((row) => (
- setEditingLabelsGroup(row.original)}
- onKeyDown={(event) => {
- if (event.key === "Enter" || event.key === " ") {
- event.preventDefault()
- setEditingLabelsGroup(row.original)
- }
- }}
- >
+
{row.getAllCells().map((cell) => (