import React, { useState, useEffect, useCallback, useRef } from "react"; import { Card, Title, Subtitle, Table, TableHead, TableHeaderCell, TableRow, TableCell, TableBody, Tab, Text, TabGroup, TabList, TabPanels, Metric, Grid, TabPanel, Select, SelectItem, Dialog, DialogPanel, Icon, TextInput, NumberInput, } from "@tremor/react"; import { message } from "antd"; import { Modal } from "antd"; import { userInfoCall, userUpdateUserCall, getPossibleUserRoles, userListCall, } from "./networking"; import { Badge, BadgeDelta, Button } from "@tremor/react"; import RequestAccess from "./request_model_access"; import CreateUser from "./create_user_button"; import EditUserModal from "./edit_user"; import Paragraph from "antd/es/skeleton/Paragraph"; import { PencilAltIcon, InformationCircleIcon, TrashIcon, } from "@heroicons/react/outline"; import { userDeleteCall } from "./networking"; import { columns } from "./view_users/columns"; import { UserDataTable } from "./view_users/table"; import { UserInfo } from "./view_users/types"; import BulkCreateUsers from "./bulk_create_users_button"; import SSOSettings from "./SSOSettings"; import debounce from "lodash/debounce"; interface ViewUserDashboardProps { accessToken: string | null; token: string | null; keys: any[] | null; userRole: string | null; userID: string | null; teams: any[] | null; setKeys: React.Dispatch>; } interface UserListResponse { users: any[] | null; total: number; page: number; page_size: number; total_pages: number; } interface CreateuserProps { userID: string; accessToken: string; teams: any[]; possibleUIRoles: Record>; onUserCreated: () => Promise; } interface FilterState { email: string; user_id: string; user_role: string; sso_user_id: string; team: string; model: string; min_spend: number | null; max_spend: number | null; sort_by: string; sort_order: 'asc' | 'desc'; } const isLocal = process.env.NODE_ENV === "development"; const proxyBaseUrl = isLocal ? "http://localhost:4000" : null; if (isLocal != true) { console.log = function() {}; } const ViewUserDashboard: React.FC = ({ accessToken, token, keys, userRole, userID, teams, setKeys, }) => { const [userListResponse, setUserListResponse] = useState(null); const [endUsers, setEndUsers] = useState(null); const [currentPage, setCurrentPage] = useState(1); const [openDialogId, setOpenDialogId] = React.useState(null); const [selectedItem, setSelectedItem] = useState(null); const [editModalVisible, setEditModalVisible] = useState(false); const [selectedUser, setSelectedUser] = useState(null); const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false); const [userToDelete, setUserToDelete] = useState(null); const [possibleUIRoles, setPossibleUIRoles] = useState< Record> >({}); const defaultPageSize = 25; const [searchTerm, setSearchTerm] = useState(""); const [activeTab, setActiveTab] = useState("users"); const [filters, setFilters] = useState({ email: "", user_id: "", user_role: "", sso_user_id: "", team: "", model: "", min_spend: null, max_spend: null, sort_by: "created_at", sort_order: "desc" }); const [showFilters, setShowFilters] = useState(false); const [showColumnDropdown, setShowColumnDropdown] = useState(false); const [selectedFilter, setSelectedFilter] = useState("Email"); const filtersRef = useRef(null); const lastSearchTimestamp = useRef(0); // check if window is not undefined if (typeof window !== "undefined") { window.addEventListener("beforeunload", function () { // Clear session storage sessionStorage.clear(); }); } const handleDelete = (userId: string) => { setUserToDelete(userId); setIsDeleteModalOpen(true); }; const handleFilterChange = (key: keyof FilterState, value: string | number | null) => { const newFilters = { ...filters, [key]: value }; setFilters(newFilters); console.log("called from handleFilterChange - newFilters:", JSON.stringify(newFilters)); debouncedSearch(newFilters); }; const handleSortChange = (sortBy: string, sortOrder: 'asc' | 'desc') => { const newFilters = { ...filters, sort_by: sortBy, sort_order: sortOrder }; setFilters(newFilters); debouncedSearch(newFilters); }; // Create a debounced version of the search function const debouncedSearch = useCallback( debounce(async (filters: FilterState) => { if (!accessToken || !token || !userRole || !userID) { return; } const currentTimestamp = Date.now(); lastSearchTimestamp.current = currentTimestamp; try { // Make the API call using userListCall with all filter parameters const data = await userListCall( accessToken, filters.user_id ? [filters.user_id] : null, 1, // Reset to first page when searching defaultPageSize, filters.email || null, filters.user_role || null, filters.team || null, filters.sso_user_id || null, filters.sort_by, filters.sort_order ); // Only update state if this is the most recent search if (currentTimestamp === lastSearchTimestamp.current) { if (data) { setUserListResponse(data); console.log("called from debouncedSearch filters:", JSON.stringify(filters)); console.log("called from debouncedSearch data:", JSON.stringify(data)); } } } catch (error) { console.error("Error searching users:", error); } }, 300), [accessToken, token, userRole, userID] ); // Cleanup the debounced function on component unmount useEffect(() => { return () => { debouncedSearch.cancel(); }; }, [debouncedSearch]); const handleSearch = (value: string) => { setSearchTerm(value); if (value === "") { refreshUserData(); // Reset to original data when search is cleared } else { debouncedSearch(filters); } }; const confirmDelete = async () => { if (userToDelete && accessToken) { try { await userDeleteCall(accessToken, [userToDelete]); message.success("User deleted successfully"); // Update the user list after deletion if (userListResponse) { const updatedUserData = userListResponse.users?.filter(user => user.user_id !== userToDelete); setUserListResponse({ ...userListResponse, users: updatedUserData || [] }); } } catch (error) { console.error("Error deleting user:", error); message.error("Failed to delete user"); } } setIsDeleteModalOpen(false); setUserToDelete(null); }; const cancelDelete = () => { setIsDeleteModalOpen(false); setUserToDelete(null); }; const handleEditCancel = async () => { setSelectedUser(null); setEditModalVisible(false); }; const handleEditSubmit = async (editedUser: any) => { console.log("inside handleEditSubmit:", editedUser); if (!accessToken || !token || !userRole || !userID) { return; } try { await userUpdateUserCall(accessToken, editedUser, null); message.success(`User ${editedUser.user_id} updated successfully`); } catch (error) { console.error("There was an error updating the user", error); } if (userListResponse) { const updatedUserData = userListResponse.users?.map((user) => user.user_id === editedUser.user_id ? editedUser : user ); setUserListResponse({ ...userListResponse, users: updatedUserData || [] }); } setSelectedUser(null); setEditModalVisible(false); // Close the modal }; const refreshUserData = async () => { console.log("called from refreshUserData"); if (!accessToken || !token || !userRole || !userID) { return; } try { const userDataResponse = await userInfoCall( accessToken, null, userRole, true, currentPage, defaultPageSize ); // Update session storage with new data sessionStorage.setItem( `userList_${currentPage}`, JSON.stringify(userDataResponse) ); console.log("called from refreshUserData"); setUserListResponse(userDataResponse); } catch (error) { console.error("Error refreshing user data:", error); } }; const handlePageChange = async (newPage: number) => { if (!accessToken || !token || !userRole || !userID) { return; } try { const userDataResponse = await userListCall( accessToken, filters.user_id ? [filters.user_id] : null, newPage, defaultPageSize, filters.email || null, filters.user_role || null, filters.team || null, filters.sort_by, filters.sort_order ); // Update session storage with new data sessionStorage.setItem( `userList_${newPage}`, JSON.stringify(userDataResponse) ); setUserListResponse(userDataResponse); setCurrentPage(newPage); } catch (error) { console.error("Error changing page:", error); } }; useEffect(() => { if (!accessToken || !token || !userRole || !userID) { return; } const fetchData = async () => { try { // Check session storage first const cachedUserData = sessionStorage.getItem(`userList_${currentPage}`); if (cachedUserData) { const parsedData = JSON.parse(cachedUserData); setUserListResponse(parsedData); console.log("called from useEffect"); } else { // Fetch from API using userListCall with current filters const userDataResponse = await userListCall( accessToken, filters.user_id ? [filters.user_id] : null, currentPage, defaultPageSize, filters.email || null, filters.user_role || null, filters.team || null, filters.sort_by, filters.sort_order ); // Store in session storage sessionStorage.setItem( `userList_${currentPage}`, JSON.stringify(userDataResponse) ); setUserListResponse(userDataResponse); console.log("called from useEffect 2"); } // Fetch roles if not cached const cachedRoles = sessionStorage.getItem('possibleUserRoles'); if (cachedRoles) { setPossibleUIRoles(JSON.parse(cachedRoles)); } else { const availableUserRoles = await getPossibleUserRoles(accessToken); sessionStorage.setItem('possibleUserRoles', JSON.stringify(availableUserRoles)); setPossibleUIRoles(availableUserRoles); } } catch (error) { console.error("There was an error fetching the model data", error); } }; if (accessToken && token && userRole && userID) { fetchData(); } }, [accessToken, token, userRole, userID]); if (!userListResponse) { return
Loading...
; } if (!accessToken || !token || !userRole || !userID) { return
Loading...
; } const tableColumns = columns( possibleUIRoles, (user) => { setSelectedUser(user); setEditModalVisible(true); }, handleDelete ); return (

Users

setActiveTab(index === 0 ? "users" : "settings")}> Users Default User Settings
{/* Search and Filter Controls */}
{/* Email Search */}
handleFilterChange('email', e.target.value)} />
{/* Filter Button */} {/* Reset Filters Button */}
{/* Additional Filters */} {showFilters && (
{/* User ID Search */}
handleFilterChange('user_id', e.target.value)} />
{/* Role Dropdown */}
{/* Team Dropdown */}
{/* SSO ID Search */}
handleFilterChange('sso_user_id', e.target.value)} />
)} {/* Results Count and Pagination */}
Showing{" "} {userListResponse && userListResponse.users && userListResponse.users.length > 0 ? (userListResponse.page - 1) * userListResponse.page_size + 1 : 0}{" "} -{" "} {userListResponse && userListResponse.users ? Math.min( userListResponse.page * userListResponse.page_size, userListResponse.total ) : 0}{" "} of {userListResponse ? userListResponse.total : 0} results {/* Pagination Buttons */}
{/* Existing Modals */} {/* Delete Confirmation Modal */} {isDeleteModalOpen && (
{/* Modal Panel */} {/* Confirmation Modal Content */}

Delete User

Are you sure you want to delete this user?

User ID: {userToDelete}

)}
); }; export default ViewUserDashboard;