diff --git a/web/apps/admin/src/pages/admins/AdminsPage.tsx b/web/apps/admin/src/pages/admins/AdminsPage.tsx index 8dfa7fb29..8bc110cec 100644 --- a/web/apps/admin/src/pages/admins/AdminsPage.tsx +++ b/web/apps/admin/src/pages/admins/AdminsPage.tsx @@ -1,5 +1,12 @@ import { AdminsView } from "@raystack/frontier/admin"; +import { useNavigate } from "react-router-dom"; export function AdminsPage() { - return ; + const navigate = useNavigate(); + + return ( + navigate(`/organizations/${orgId}`)} + /> + ); } diff --git a/web/apps/admin/src/pages/plans/PlansPage.tsx b/web/apps/admin/src/pages/plans/PlansPage.tsx index 9097921d0..a79d074f5 100644 --- a/web/apps/admin/src/pages/plans/PlansPage.tsx +++ b/web/apps/admin/src/pages/plans/PlansPage.tsx @@ -9,6 +9,7 @@ export function PlansPage() { navigate("/plans")} + onSelectPlan={(id: string) => navigate(`/plans/${id}`)} /> ); } diff --git a/web/apps/admin/src/pages/preferences/PreferencesPage.tsx b/web/apps/admin/src/pages/preferences/PreferencesPage.tsx index a6771afa1..49f040800 100644 --- a/web/apps/admin/src/pages/preferences/PreferencesPage.tsx +++ b/web/apps/admin/src/pages/preferences/PreferencesPage.tsx @@ -9,6 +9,7 @@ export function PreferencesPage() { navigate("/preferences")} + onSelectPreference={(prefName: string) => navigate(`/preferences/${prefName}`)} /> ); } diff --git a/web/apps/admin/src/pages/users/UsersPage.tsx b/web/apps/admin/src/pages/users/UsersPage.tsx index 3561b8f6e..31fc92f4d 100644 --- a/web/apps/admin/src/pages/users/UsersPage.tsx +++ b/web/apps/admin/src/pages/users/UsersPage.tsx @@ -1,6 +1,6 @@ import { UsersView } from "@raystack/frontier/admin"; import { useCallback } from "react"; -import { useParams, useNavigate } from "react-router-dom"; +import { useParams, useNavigate, useLocation } from "react-router-dom"; import { clients } from "~/connect/clients"; import { exportCsvFromStream } from "~/utils/helper"; @@ -9,6 +9,7 @@ const adminClient = clients.admin({ useBinary: true }); export function UsersPage() { const { userId } = useParams(); const navigate = useNavigate(); + const location = useLocation(); const onExportUsers = useCallback(async () => { await exportCsvFromStream(adminClient.exportUsers, {}, "users.csv"); @@ -27,6 +28,8 @@ export function UsersPage() { onCloseDetail={() => navigate("/users")} onExportUsers={onExportUsers} onNavigateToUser={onNavigateToUser} + currentPath={location.pathname} + onNavigate={navigate} /> ); } diff --git a/web/pnpm-lock.yaml b/web/pnpm-lock.yaml index 2167447df..d4ab66f8e 100644 --- a/web/pnpm-lock.yaml +++ b/web/pnpm-lock.yaml @@ -263,9 +263,6 @@ importers: react-image-crop: specifier: ^10.1.8 version: 10.1.8(react@18.3.1) - react-router-dom: - specifier: '>=6.0.0' - version: 7.13.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) slugify: specifier: ^1.6.6 version: 1.6.6 diff --git a/web/sdk/admin/views/admins/columns.tsx b/web/sdk/admin/views/admins/columns.tsx index d45a9019c..400b881ac 100644 --- a/web/sdk/admin/views/admins/columns.tsx +++ b/web/sdk/admin/views/admins/columns.tsx @@ -1,11 +1,12 @@ -import type { DataTableColumnDef } from "@raystack/apsara"; +import { Text, type DataTableColumnDef } from "@raystack/apsara"; import type { ServiceUser, User } from "@raystack/proton/frontier"; -import { Link } from "react-router-dom"; -export const getColumns: () => DataTableColumnDef< +export const getColumns: (options?: { + onNavigateToOrg?: (orgId: string) => void; +}) => DataTableColumnDef< User | ServiceUser, unknown ->[] = () => { +>[] = ({ onNavigateToOrg } = {}) => { return [ { header: "Title", @@ -40,7 +41,12 @@ export const getColumns: () => DataTableColumnDef< cell: (info) => { const org_id = info.getValue() as string; return org_id ? ( - {org_id} + onNavigateToOrg?.(org_id)} + > + {org_id} + ) : ( "-" ); diff --git a/web/sdk/admin/views/admins/index.tsx b/web/sdk/admin/views/admins/index.tsx index c52582aab..c334e61db 100644 --- a/web/sdk/admin/views/admins/index.tsx +++ b/web/sdk/admin/views/admins/index.tsx @@ -21,7 +21,11 @@ const NoAdmins = () => { ); }; -export default function AdminsView() { +export type AdminsViewProps = { + onNavigateToOrg?: (orgId: string) => void; +}; + +export default function AdminsView({ onNavigateToOrg }: AdminsViewProps = {}) { const { data: platformUsersData, isLoading, @@ -31,7 +35,7 @@ export default function AdminsView() { staleTime: Infinity, }); - const columns = getColumns(); + const columns = getColumns({ onNavigateToOrg }); const data = [ ...(platformUsersData?.users || []), ...(platformUsersData?.serviceusers || []), diff --git a/web/sdk/admin/views/plans/columns.tsx b/web/sdk/admin/views/plans/columns.tsx index 85e6c440e..e2da52e07 100644 --- a/web/sdk/admin/views/plans/columns.tsx +++ b/web/sdk/admin/views/plans/columns.tsx @@ -1,20 +1,29 @@ -import { Link } from "react-router-dom"; -import { type DataTableColumnDef } from "@raystack/apsara"; +import { Text, type DataTableColumnDef } from "@raystack/apsara"; import type { Plan } from "@raystack/proton/frontier"; import { timestampToDate, type TimeStamp } from "../../utils/connect-timestamp"; -export const getColumns: () => DataTableColumnDef< +export const getColumns: (options?: { + onSelectPlan?: (planId: string) => void; +}) => DataTableColumnDef< Plan, unknown ->[] = () => { +>[] = ({ onSelectPlan } = {}) => { return [ { header: "ID", accessorKey: "id", filterVariant: "text", - cell: ({ row, getValue }) => ( - {getValue() as string} - ), + cell: ({ getValue }) => { + const id = getValue() as string; + return ( + onSelectPlan?.(id)} + > + {id} + + ); + }, }, { header: "Title", diff --git a/web/sdk/admin/views/plans/index.tsx b/web/sdk/admin/views/plans/index.tsx index 0e1dfc3c6..a2f5fba43 100644 --- a/web/sdk/admin/views/plans/index.tsx +++ b/web/sdk/admin/views/plans/index.tsx @@ -19,12 +19,14 @@ const pageHeader = { export type PlansViewProps = { selectedPlanId?: string; onCloseDetail?: () => void; + onSelectPlan?: (planId: string) => void; appName?: string; }; export default function PlansView({ selectedPlanId, onCloseDetail, + onSelectPlan, appName, }: PlansViewProps = {}) { const { @@ -38,7 +40,7 @@ export default function PlansView({ const plans = plansResponse?.plans || []; const planMapById = reduceByKey(plans ?? [], "id"); - const columns = getColumns(); + const columns = getColumns({ onSelectPlan }); if (isError) { console.error("ConnectRPC Error:", error); diff --git a/web/sdk/admin/views/preferences/PreferencesView.tsx b/web/sdk/admin/views/preferences/PreferencesView.tsx index eb12c2757..1b5c75595 100644 --- a/web/sdk/admin/views/preferences/PreferencesView.tsx +++ b/web/sdk/admin/views/preferences/PreferencesView.tsx @@ -17,11 +17,13 @@ import PreferenceDetails from "./details"; export type PreferencesViewProps = { selectedPreferenceName?: string; onCloseDetail?: () => void; + onSelectPreference?: (name: string) => void; }; export default function PreferencesView({ selectedPreferenceName, onCloseDetail, + onSelectPreference, }: PreferencesViewProps = {}) { const transport = useTransport(); @@ -80,6 +82,7 @@ export default function PreferencesView({ preferences={preferences} traits={traits} isLoading={isLoading} + onSelectPreference={onSelectPreference} /> ); diff --git a/web/sdk/admin/views/preferences/columns.tsx b/web/sdk/admin/views/preferences/columns.tsx index d3c17a992..45aa588e0 100644 --- a/web/sdk/admin/views/preferences/columns.tsx +++ b/web/sdk/admin/views/preferences/columns.tsx @@ -1,11 +1,11 @@ -import type { DataTableColumnDef } from "@raystack/apsara"; +import { Text, type DataTableColumnDef } from "@raystack/apsara"; import { Preference, PreferenceTrait } from "@raystack/proton/frontier"; -import { Link } from "react-router-dom"; import styles from "./preferences.module.css"; interface getColumnsOptions { traits: PreferenceTrait[]; preferences: Preference[]; + onSelectPreference?: (name: string) => void; } export const getColumns: ( @@ -13,6 +13,7 @@ export const getColumns: ( ) => DataTableColumnDef[] = ({ traits, preferences, + onSelectPreference, }) => { return [ { @@ -25,7 +26,19 @@ export const getColumns: ( { header: "Action", accessorKey: "name", - cell: (info) => Edit, + cell: (info) => { + const name = info.getValue() as string; + return ( + onSelectPreference?.(name)} + > + Edit + + ); + }, footer: (props) => props.column.id, }, { diff --git a/web/sdk/admin/views/preferences/index.tsx b/web/sdk/admin/views/preferences/index.tsx index e1a169eee..28787af11 100644 --- a/web/sdk/admin/views/preferences/index.tsx +++ b/web/sdk/admin/views/preferences/index.tsx @@ -14,16 +14,19 @@ export type PreferencesListProps = { preferences: Preference[]; traits: PreferenceTrait[]; isLoading: boolean; + onSelectPreference?: (name: string) => void; }; export default function PreferencesList({ preferences, traits, isLoading, + onSelectPreference, }: PreferencesListProps) { const columns = getColumns({ traits, preferences, + onSelectPreference, }); return ( diff --git a/web/sdk/admin/views/users/UsersView.tsx b/web/sdk/admin/views/users/UsersView.tsx index 2c016e22d..87b27f42a 100644 --- a/web/sdk/admin/views/users/UsersView.tsx +++ b/web/sdk/admin/views/users/UsersView.tsx @@ -6,6 +6,8 @@ export type UsersViewProps = { onCloseDetail?: () => void; onExportUsers?: () => Promise; onNavigateToUser?: (userId: string) => void; + currentPath?: string; + onNavigate?: (path: string) => void; }; export default function UsersView({ @@ -13,9 +15,11 @@ export default function UsersView({ onCloseDetail, onExportUsers, onNavigateToUser, + currentPath, + onNavigate, }: UsersViewProps = {}) { if (selectedUserId) { - return ; + return ; } return ( diff --git a/web/sdk/admin/views/users/details/layout/layout.tsx b/web/sdk/admin/views/users/details/layout/layout.tsx index 06629e08c..57a955a3c 100644 --- a/web/sdk/admin/views/users/details/layout/layout.tsx +++ b/web/sdk/admin/views/users/details/layout/layout.tsx @@ -6,9 +6,11 @@ import { UserDetailsNavbar } from "./navbar"; interface UserDetailsLayoutProps { children: ReactNode; + currentPath?: string; + onNavigate?: (path: string) => void; } -export const UserDetailsLayout = ({ children }: UserDetailsLayoutProps) => { +export const UserDetailsLayout = ({ children, currentPath, onNavigate }: UserDetailsLayoutProps) => { const [showSidePanel, setShowSidePanel] = useState(true); function toggleSidePanel() { @@ -17,7 +19,7 @@ export const UserDetailsLayout = ({ children }: UserDetailsLayoutProps) => { return ( - + void; + currentPath?: string; + onNavigate?: (path: string) => void; } export const UserDetailsNavbar = ({ toggleSidePanel, + currentPath = "", + onNavigate, }: UserDetailsNavbarProps) => { const { user } = useUser(); @@ -50,18 +53,19 @@ export const UserDetailsNavbar = ({ - {links.map((link, index) => ( - - {({ isActive }) => ( - - {link.name} - - )} - - ))} + {links.map((link, index) => { + const isActive = currentPath.startsWith(link.path); + return ( + onNavigate?.(link.path)}> + {link.name} + + ); + })} diff --git a/web/sdk/admin/views/users/details/user-details.tsx b/web/sdk/admin/views/users/details/user-details.tsx index 8dfb03afc..f3b8deee5 100644 --- a/web/sdk/admin/views/users/details/user-details.tsx +++ b/web/sdk/admin/views/users/details/user-details.tsx @@ -11,12 +11,14 @@ import { UserDetailsSecurityContent } from "./security/security"; interface UserDetailContentProps { user: User; refetch: () => void; + currentPath?: string; + onNavigate?: (path: string) => void; } -export const UserDetailContent = ({ user, refetch }: UserDetailContentProps) => { +export const UserDetailContent = ({ user, refetch, currentPath, onNavigate }: UserDetailContentProps) => { return ( - + @@ -25,9 +27,11 @@ export const UserDetailContent = ({ user, refetch }: UserDetailContentProps) => interface UserDetailsByUserIdProps { userId: string; + currentPath?: string; + onNavigate?: (path: string) => void; } -export const UserDetailsByUserId = ({ userId }: UserDetailsByUserIdProps) => { +export const UserDetailsByUserId = ({ userId, currentPath, onNavigate }: UserDetailsByUserIdProps) => { const { data, isLoading, refetch } = useQuery( AdminServiceQueries.searchUsers, { query: { search: userId } }, @@ -66,5 +70,5 @@ export const UserDetailsByUserId = ({ userId }: UserDetailsByUserIdProps) => { ); } - return ; + return ; }; diff --git a/web/sdk/admin/views/users/list/columns.tsx b/web/sdk/admin/views/users/list/columns.tsx index 122ea7abb..0083dc7d7 100644 --- a/web/sdk/admin/views/users/list/columns.tsx +++ b/web/sdk/admin/views/users/list/columns.tsx @@ -6,7 +6,6 @@ import { getAvatarColor, Text, } from "@raystack/apsara"; -import { Link } from "react-router-dom"; import dayjs from "dayjs"; import styles from "./list.module.css"; import { getUserName, USER_STATES, UserState } from "../util"; @@ -19,10 +18,12 @@ import { interface getColumnsOptions { groupCountMap: Record>; + onNavigateToUser?: (userId: string) => void; } export const getColumns = ({ groupCountMap, + onNavigateToUser, }: getColumnsOptions): DataTableColumnDef[] => { return [ { @@ -37,16 +38,19 @@ export const getColumns = ({ const name = getUserName(row.original); const userId = row.original.id; return ( - - - - {name} - - + userId && onNavigateToUser?.(userId)} + > + + {name} + ); }, enableColumnFilter: true, diff --git a/web/sdk/admin/views/users/list/list.tsx b/web/sdk/admin/views/users/list/list.tsx index 96ce9516c..8537b6256 100644 --- a/web/sdk/admin/views/users/list/list.tsx +++ b/web/sdk/admin/views/users/list/list.tsx @@ -98,7 +98,7 @@ export const UsersList = ({ onExportUsers, onNavigateToUser }: UsersListProps) = } }; - const columns = getColumns({ groupCountMap }); + const columns = getColumns({ groupCountMap, onNavigateToUser }); const loading = isLoading || isFetchingNextPage; diff --git a/web/sdk/admin/views/webhooks/webhooks/create/index.tsx b/web/sdk/admin/views/webhooks/webhooks/create/index.tsx index 7bbe49df2..3db2e6813 100644 --- a/web/sdk/admin/views/webhooks/webhooks/create/index.tsx +++ b/web/sdk/admin/views/webhooks/webhooks/create/index.tsx @@ -1,6 +1,5 @@ import { useCallback } from "react"; import { Button, Flex, Sheet } from "@raystack/apsara"; -import { useNavigate } from "react-router-dom"; import { SheetHeader } from "../../../../components/SheetHeader"; import { SheetFooter } from "../../../../components/SheetFooter"; import * as z from "zod"; @@ -36,13 +35,11 @@ export type CreateWebhooksProps = { }; export default function CreateWebhooks({ onClose: onCloseProp }: CreateWebhooksProps = {}) { - const navigate = useNavigate(); const { invalidateWebhooksList } = useWebhookQueries(); const onOpenChange = useCallback(() => { - if (onCloseProp) onCloseProp(); - else navigate("/webhooks"); - }, [navigate, onCloseProp]); + onCloseProp?.(); + }, [onCloseProp]); const { mutateAsync: createWebhook, isPending: isSubmitting } = useMutation( AdminServiceQueries.createWebhook, diff --git a/web/sdk/admin/views/webhooks/webhooks/header.tsx b/web/sdk/admin/views/webhooks/webhooks/header.tsx index e58bb0556..baeeedfda 100644 --- a/web/sdk/admin/views/webhooks/webhooks/header.tsx +++ b/web/sdk/admin/views/webhooks/webhooks/header.tsx @@ -1,7 +1,6 @@ import { PlusIcon } from "@radix-ui/react-icons"; import { Button, Flex, DataTable } from "@raystack/apsara"; -import { useNavigate } from "react-router-dom"; import { PageHeader } from "../../../components/PageHeader"; import styles from "./webhooks.module.css"; @@ -16,8 +15,7 @@ export type WebhooksHeaderProps = { }; export const WebhooksHeader = ({ header = pageHeader, onOpenCreate }: WebhooksHeaderProps) => { - const navigate = useNavigate(); - const handleCreate = () => (onOpenCreate ? onOpenCreate() : navigate("/webhooks/create")); + const handleCreate = () => onOpenCreate?.(); return ( { - if (onCloseProp) onCloseProp(); - else navigate("/webhooks"); - }, [navigate, onCloseProp]); + onCloseProp?.(); + }, [onCloseProp]); const methods = useForm({ resolver: zodResolver(UpdateWebhookSchema), diff --git a/web/sdk/package.json b/web/sdk/package.json index c54bca967..ef85465fb 100644 --- a/web/sdk/package.json +++ b/web/sdk/package.json @@ -122,8 +122,7 @@ "peerDependencies": { "@raystack/apsara": ">=0.30.0", "react": "^18.2.0", - "react-dom": "^18.2.0", - "react-router-dom": ">=6.0.0" + "react-dom": "^18.2.0" }, "peerDependenciesMeta": { "react": { @@ -132,9 +131,6 @@ "react-dom": { "optional": true }, - "react-router-dom": { - "optional": true - }, "svelte": { "optional": true },