rip out some users context

This commit is contained in:
Nate Kelley 2025-03-12 14:28:32 -06:00
parent 55ffb94fe2
commit 7eaee18f09
No known key found for this signature in database
GPG Key ID: FD90372AB8D98B4F
13 changed files with 82 additions and 137 deletions

View File

@ -11,12 +11,15 @@ import {
deleteUserFavorite, deleteUserFavorite,
updateUserFavorites, updateUserFavorites,
getUserList, getUserList,
getUserList_server getUserList_server,
inviteUser
} from './requests'; } from './requests';
import { useMemoizedFn } from '@/hooks'; import { useMemoizedFn } from '@/hooks';
import { QueryClient, useQueryClient } from '@tanstack/react-query'; import { QueryClient, useQueryClient } from '@tanstack/react-query';
import { queryKeys } from '@/api/query_keys'; import { queryKeys } from '@/api/query_keys';
import type { UserRequestUserListPayload } from '@/api/request_interfaces/user/interfaces'; import type { UserRequestUserListPayload } from '@/api/request_interfaces/user/interfaces';
import { useBusterNotifications } from '@/context/BusterNotifications';
import { useCreateOrganization } from '../organizations/queryRequests';
export const useGetMyUserInfo = () => { export const useGetMyUserInfo = () => {
return useQuery({ return useQuery({
@ -115,7 +118,7 @@ export const useDeleteUserFavorite = () => {
mutationFn: deleteUserFavorite, mutationFn: deleteUserFavorite,
onMutate: (params) => { onMutate: (params) => {
queryClient.setQueryData(queryKeys.favoritesGetList.queryKey, (prev) => { queryClient.setQueryData(queryKeys.favoritesGetList.queryKey, (prev) => {
return prev?.filter((fav) => fav.id !== params.id); return prev?.filter((fav) => !params.some((p) => p.id === fav.id));
}); });
}, },
onSettled: () => { onSettled: () => {
@ -161,3 +164,38 @@ export const prefetchGetUserList = async (
}); });
return queryClient; return queryClient;
}; };
export const useInviteUser = () => {
const { openSuccessMessage } = useBusterNotifications();
return useMutation({
mutationFn: inviteUser,
onSuccess: () => {
openSuccessMessage('Invites sent');
// queryClient.invalidateQueries(queryKeys.userGetUserList);
}
});
};
export const useCreateUserOrganization = () => {
const { data: userResponse, refetch: refetchUserResponse } = useGetMyUserInfo();
const { mutateAsync: createOrganization } = useCreateOrganization();
const { mutateAsync: updateUserInfo } = useUpdateUser();
const onCreateUserOrganization = useMemoizedFn(
async ({ name, company }: { name: string; company: string }) => {
const alreadyHasOrganization = !!userResponse?.organizations?.[0];
if (!alreadyHasOrganization) await createOrganization({ name: company });
if (userResponse)
await updateUserInfo({
userId: userResponse.user.id,
name
});
await refetchUserResponse();
}
);
return onCreateUserOrganization;
};

View File

@ -14,7 +14,9 @@ import type { UserRequestUserListPayload } from '@/api/request_interfaces/user/i
const favoritesGetList = queryOptions<BusterUserFavorite[]>({ const favoritesGetList = queryOptions<BusterUserFavorite[]>({
queryKey: ['users', 'favorites', 'list'] as const, queryKey: ['users', 'favorites', 'list'] as const,
staleTime: 1000 * 60 * 60 // 1 hour staleTime: 1000 * 60 * 60, // 1 hour,
initialData: [],
initialDataUpdatedAt: 0
}); });
const userGetUserMyself = queryOptions<BusterUserResponse>({ const userGetUserMyself = queryOptions<BusterUserResponse>({

View File

@ -7,10 +7,10 @@ export interface UsersFavoritePostPayload {
name: string; name: string;
} }
export interface UserFavoriteDeletePayload { export type UserFavoriteDeletePayload = {
id: string; id: string;
asset_type: ShareAssetType; asset_type: ShareAssetType;
} }[];
export interface UserUpdateFavoritesPayload { export interface UserUpdateFavoritesPayload {
favorites: string[]; // Array of favorite ids favorites: string[]; // Array of favorite ids

View File

@ -11,11 +11,12 @@ import { BusterRoutes } from '@/routes/busterRoutes';
import { useBusterNotifications } from '@/context/BusterNotifications'; import { useBusterNotifications } from '@/context/BusterNotifications';
import { Button } from '@/components/ui/buttons'; import { Button } from '@/components/ui/buttons';
import { Input } from '@/components/ui/inputs'; import { Input } from '@/components/ui/inputs';
import { useCreateUserOrganization } from '@/api/buster_rest/users';
export const NewUserController = () => { export const NewUserController = () => {
const [started, setStarted] = useState(false); const [started, setStarted] = useState(false);
const onChangePage = useAppLayoutContextSelector((s) => s.onChangePage); const onChangePage = useAppLayoutContextSelector((s) => s.onChangePage);
const onCreateUserOrganization = useUserConfigContextSelector((s) => s.onCreateUserOrganization); const onCreateUserOrganization = useCreateUserOrganization();
const user = useUserConfigContextSelector((s) => s.user); const user = useUserConfigContextSelector((s) => s.user);
const userOrganizations = useUserConfigContextSelector((s) => s.userOrganizations); const userOrganizations = useUserConfigContextSelector((s) => s.userOrganizations);
const { openInfoMessage } = useBusterNotifications(); const { openInfoMessage } = useBusterNotifications();

View File

@ -7,6 +7,11 @@ import { Button } from '@/components/ui/buttons';
import { cn } from '@/lib/classMerge'; import { cn } from '@/lib/classMerge';
import { Star } from '@/components/ui/icons'; import { Star } from '@/components/ui/icons';
import { cva } from 'class-variance-authority'; import { cva } from 'class-variance-authority';
import {
useAddUserFavorite,
useDeleteUserFavorite,
useGetUserFavorites
} from '@/api/buster_rest/users';
const favoriteStarVariants = cva('transition-colors', { const favoriteStarVariants = cva('transition-colors', {
variants: { variants: {
@ -32,11 +37,9 @@ export const FavoriteStar: React.FC<{
className?: string; className?: string;
iconStyle?: 'default' | 'tertiary'; iconStyle?: 'default' | 'tertiary';
}> = React.memo(({ title: name, id, type, className = '', iconStyle = 'default' }) => { }> = React.memo(({ title: name, id, type, className = '', iconStyle = 'default' }) => {
const userFavorites = useUserConfigContextSelector((state) => state.userFavorites); const { data: userFavorites } = useGetUserFavorites();
const removeItemFromFavorite = useUserConfigContextSelector( const { mutateAsync: removeItemFromFavorite } = useDeleteUserFavorite();
(state) => state.removeItemFromFavorite const { mutateAsync: addItemToFavorite } = useAddUserFavorite();
);
const addItemToFavorite = useUserConfigContextSelector((state) => state.addItemToFavorite);
const isFavorited = useMemo(() => { const isFavorited = useMemo(() => {
return userFavorites?.some((favorite) => favorite.id === id || favorite.collection_id === id); return userFavorites?.some((favorite) => favorite.id === id || favorite.collection_id === id);
@ -52,10 +55,12 @@ export const FavoriteStar: React.FC<{
name name
}); });
await removeItemFromFavorite({ await removeItemFromFavorite([
{
asset_type: type, asset_type: type,
id id
}); }
]);
}); });
const tooltipText = isFavorited ? 'Remove from favorites' : 'Add to favorites'; const tooltipText = isFavorited ? 'Remove from favorites' : 'Add to favorites';

View File

@ -1,23 +1,18 @@
import React, { useMemo } from 'react'; import React, { useMemo } from 'react';
import { useMemoizedFn } from '@/hooks'; import { useMemoizedFn } from '@/hooks';
import { AppModal } from '@/components/ui/modal'; import { AppModal } from '@/components/ui/modal';
import { useUserConfigContextSelector } from '@/context/Users';
import { TagInput } from '@/components/ui/inputs/InputTagInput'; import { TagInput } from '@/components/ui/inputs/InputTagInput';
import { useInviteUser } from '@/api/buster_rest/users';
export const InvitePeopleModal: React.FC<{ export const InvitePeopleModal: React.FC<{
open: boolean; open: boolean;
onClose: () => void; onClose: () => void;
}> = React.memo(({ open, onClose }) => { }> = React.memo(({ open, onClose }) => {
const [emails, setEmails] = React.useState<string[]>([]); const [emails, setEmails] = React.useState<string[]>([]);
const [inviting, setInviting] = React.useState<boolean>(false); const { mutateAsync: inviteUsers, isPending: inviting } = useInviteUser();
const inviteUsers = useUserConfigContextSelector((state) => state.inviteUsers);
const isAdmin = useUserConfigContextSelector((state) => state.isAdmin);
const userTeams = useUserConfigContextSelector((state) => state.userTeams);
const handleInvite = useMemoizedFn(async () => { const handleInvite = useMemoizedFn(async () => {
setInviting(true); await inviteUsers({ emails });
await inviteUsers(emails);
setInviting(false);
onClose(); onClose();
}); });

View File

@ -18,6 +18,7 @@ import { SupportModal } from '../modal/SupportModal';
import { InvitePeopleModal } from '../modal/InvitePeopleModal'; import { InvitePeopleModal } from '../modal/InvitePeopleModal';
import { useMemoizedFn } from '@/hooks'; import { useMemoizedFn } from '@/hooks';
import { SidebarUserFooter } from './SidebarUserFooter/SidebarUserFooter'; import { SidebarUserFooter } from './SidebarUserFooter/SidebarUserFooter';
import { useGetUserFavorites } from '@/api/buster_rest';
const topItems: ISidebarList = { const topItems: ISidebarList = {
items: [ items: [
@ -106,7 +107,7 @@ const tryGroup = (onClickInvitePeople: () => void, onClickLeaveFeedback: () => v
export const SidebarPrimary = React.memo(() => { export const SidebarPrimary = React.memo(() => {
const isAdmin = useUserConfigContextSelector((x) => x.isAdmin); const isAdmin = useUserConfigContextSelector((x) => x.isAdmin);
const favorites = useUserConfigContextSelector((state) => state.userFavorites); const { data: favorites } = useGetUserFavorites();
const currentRoute = useAppLayoutContextSelector((x) => x.currentRoute); const currentRoute = useAppLayoutContextSelector((x) => x.currentRoute);
const onToggleSupportModal = useAppLayoutContextSelector((s) => s.onToggleSupportModal); const onToggleSupportModal = useAppLayoutContextSelector((s) => s.onToggleSupportModal);
const onToggleInviteModal = useAppLayoutContextSelector((s) => s.onToggleInviteModal); const onToggleInviteModal = useAppLayoutContextSelector((s) => s.onToggleInviteModal);

View File

@ -1,9 +1,8 @@
import { useMemoizedFn } from '@/hooks'; import { useMemoizedFn } from '@/hooks';
import type { IBusterMetric } from '@/api/asset_interfaces/metric'; import type { IBusterMetric } from '@/api/asset_interfaces/metric';
import { useUserConfigContextSelector } from '@/context/Users';
import { useBusterNotifications } from '@/context/BusterNotifications'; import { useBusterNotifications } from '@/context/BusterNotifications';
import { useUpdateMetricConfig } from './useMetricUpdateConfig'; import { useUpdateMetricConfig } from './useMetricUpdateConfig';
import { useGetUserFavorites } from '@/api/buster_rest/users';
export const useUpdateMetricAssosciations = ({ export const useUpdateMetricAssosciations = ({
getMetricMemoized, getMetricMemoized,
updateMetricMutation updateMetricMutation
@ -11,8 +10,7 @@ export const useUpdateMetricAssosciations = ({
getMetricMemoized: ({ metricId }: { metricId?: string }) => IBusterMetric; getMetricMemoized: ({ metricId }: { metricId?: string }) => IBusterMetric;
updateMetricMutation: ReturnType<typeof useUpdateMetricConfig>['updateMetricMutation']; updateMetricMutation: ReturnType<typeof useUpdateMetricConfig>['updateMetricMutation'];
}) => { }) => {
const userFavorites = useUserConfigContextSelector((state) => state.userFavorites); const { data: userFavorites, refetch: refreshFavoritesList } = useGetUserFavorites();
const refreshFavoritesList = useUserConfigContextSelector((x) => x.refreshFavoritesList);
const { openConfirmModal } = useBusterNotifications(); const { openConfirmModal } = useBusterNotifications();

View File

@ -2,29 +2,15 @@
import type { BusterUserResponse } from '@/api/asset_interfaces/users'; import type { BusterUserResponse } from '@/api/asset_interfaces/users';
import React, { PropsWithChildren } from 'react'; import React, { PropsWithChildren } from 'react';
import { useFavoriteProvider } from './useFavoriteProvider';
import { useGetMyUserInfo } from '@/api/buster_rest/users'; import { useGetMyUserInfo } from '@/api/buster_rest/users';
import { useSupabaseContext } from '../Supabase'; import { useSupabaseContext } from '../Supabase';
import { createContext, useContextSelector } from 'use-context-selector'; import { createContext, useContextSelector } from 'use-context-selector';
import { useUserOrganization } from './useUserOrganization';
import { useInviteUser } from './useInviteUser';
import { checkIfUserIsAdmin } from '@/lib/user'; import { checkIfUserIsAdmin } from '@/lib/user';
export const useUserConfigProvider = ({ userInfo }: { userInfo: BusterUserResponse | null }) => { export const useUserConfigProvider = ({ userInfo }: { userInfo: BusterUserResponse | null }) => {
const isAnonymousUser = useSupabaseContext((state) => state.isAnonymousUser); const isAnonymousUser = useSupabaseContext((state) => state.isAnonymousUser);
const { data: userResponseData } = useGetMyUserInfo();
const { data: userResponseData, refetch: refetchUserResponse } = useGetMyUserInfo();
const userResponse = userResponseData || userInfo; const userResponse = userResponseData || userInfo;
const favoriteConfig = useFavoriteProvider();
const inviteUsers = useInviteUser();
const { onCreateUserOrganization } = useUserOrganization({
userResponse,
refetchUserResponse
});
const user = userResponse?.user; const user = userResponse?.user;
const userTeams = userResponse?.teams || []; const userTeams = userResponse?.teams || [];
const userOrganizations = userResponse?.organizations?.[0]; const userOrganizations = userResponse?.organizations?.[0];
@ -35,16 +21,13 @@ export const useUserConfigProvider = ({ userInfo }: { userInfo: BusterUserRespon
const isAdmin = checkIfUserIsAdmin(userResponse); const isAdmin = checkIfUserIsAdmin(userResponse);
return { return {
onCreateUserOrganization,
userTeams, userTeams,
user, user,
userRole, userRole,
isAdmin, isAdmin,
userOrganizations, userOrganizations,
isUserRegistered, isUserRegistered,
isAnonymousUser, isAnonymousUser
...inviteUsers,
...favoriteConfig
}; };
}; };

View File

@ -1,31 +0,0 @@
import { useMemoizedFn } from '@/hooks';
import type { BusterUserFavorite } from '@/api/asset_interfaces/users';
import isEmpty from 'lodash/isEmpty';
import {
useAddUserFavorite,
useDeleteUserFavorite,
useGetUserFavorites
} from '@/api/buster_rest/users';
const DEFAULT_FAVORITES: BusterUserFavorite[] = [];
export const useFavoriteProvider = () => {
const { data: userFavorites, refetch: refreshFavoritesList } = useGetUserFavorites();
const { mutate: addItemToFavorite } = useAddUserFavorite();
const { mutate: removeItemFromFavorite } = useDeleteUserFavorite();
const bulkEditFavorites = useMemoizedFn(async (favorites: string[]) => {
// return updateFavorites({ favorites });
alert('TODO - feature not implemented yet');
});
return {
bulkEditFavorites,
refreshFavoritesList,
userFavorites: isEmpty(userFavorites) ? DEFAULT_FAVORITES : userFavorites!,
addItemToFavorite,
removeItemFromFavorite
};
};

View File

@ -1,18 +0,0 @@
import { useMemoizedFn } from '@/hooks';
import { timeout } from '@/lib';
import { useBusterNotifications } from '../BusterNotifications';
import { inviteUser as inviteUserRest } from '@/api/buster_rest';
export const useInviteUser = () => {
const { openSuccessMessage } = useBusterNotifications();
const inviteUsers = useMemoizedFn(async (emails: string[], team_ids?: string[]) => {
await inviteUserRest({ emails, team_ids });
await timeout(100);
openSuccessMessage('Invites sent');
});
return {
inviteUsers
};
};

View File

@ -1,34 +0,0 @@
import { useMemoizedFn } from '@/hooks';
import type { BusterUserResponse } from '@/api/asset_interfaces/users';
import { useCreateOrganization, useUpdateUser } from '@/api/buster_rest';
export const useUserOrganization = ({
userResponse,
refetchUserResponse
}: {
userResponse: BusterUserResponse | null | undefined;
refetchUserResponse: () => Promise<unknown>;
}) => {
const { mutateAsync: createOrganization } = useCreateOrganization();
const { mutateAsync: updateUserInfo } = useUpdateUser();
const onCreateUserOrganization = useMemoizedFn(
async ({ name, company }: { name: string; company: string }) => {
const alreadyHasOrganization = !!userResponse?.organizations?.[0];
if (!alreadyHasOrganization) await createOrganization({ name: company });
if (userResponse)
await updateUserInfo({
userId: userResponse.user.id,
name
});
await refetchUserResponse();
}
);
return {
onCreateUserOrganization
};
};

View File

@ -6,12 +6,17 @@ import { BusterListSelectedOptionPopupContainer } from '@/components/ui/list';
import { Dropdown, DropdownItems } from '@/components/ui/dropdown'; import { Dropdown, DropdownItems } from '@/components/ui/dropdown';
import { Button } from '@/components/ui/buttons'; import { Button } from '@/components/ui/buttons';
import { useBusterMetricsIndividualContextSelector } from '@/context/Metrics'; import { useBusterMetricsIndividualContextSelector } from '@/context/Metrics';
import { useUserConfigContextSelector } from '@/context/Users';
import { useMemoizedFn } from '@/hooks'; import { useMemoizedFn } from '@/hooks';
import { SaveToCollectionsDropdown } from '@/components/features/dropdowns/SaveToCollectionsDropdown'; import { SaveToCollectionsDropdown } from '@/components/features/dropdowns/SaveToCollectionsDropdown';
import { useBusterNotifications } from '@/context/BusterNotifications'; import { useBusterNotifications } from '@/context/BusterNotifications';
import { ASSET_ICONS } from '@/components/features/config/assetIcons'; import { ASSET_ICONS } from '@/components/features/config/assetIcons';
import { useDeleteMetric } from '@/api/buster_rest/metrics'; import { useDeleteMetric } from '@/api/buster_rest/metrics';
import {
useAddUserFavorite,
useDeleteUserFavorite,
useGetUserFavorites
} from '@/api/buster_rest/users';
import { ShareAssetType } from '@/api/asset_interfaces/share';
export const ChatSelectedOptionPopup: React.FC<{ export const ChatSelectedOptionPopup: React.FC<{
selectedRowKeys: string[]; selectedRowKeys: string[];
@ -137,8 +142,8 @@ const ThreeDotButton: React.FC<{
selectedRowKeys: string[]; selectedRowKeys: string[];
onSelectChange: (selectedRowKeys: string[]) => void; onSelectChange: (selectedRowKeys: string[]) => void;
}> = ({ selectedRowKeys, onSelectChange }) => { }> = ({ selectedRowKeys, onSelectChange }) => {
const bulkEditFavorites = useUserConfigContextSelector((state) => state.bulkEditFavorites); const { mutateAsync: removeUserFavorite } = useDeleteUserFavorite();
const userFavorites = useUserConfigContextSelector((state) => state.userFavorites); const { data: userFavorites } = useGetUserFavorites();
const dropdownOptions: DropdownItems = [ const dropdownOptions: DropdownItems = [
{ {
@ -156,10 +161,10 @@ const ThreeDotButton: React.FC<{
icon: <Xmark />, icon: <Xmark />,
value: 'remove-from-favorites', value: 'remove-from-favorites',
onClick: async () => { onClick: async () => {
const allFavorites: string[] = userFavorites const allFavorites: Parameters<typeof removeUserFavorite>[0] = userFavorites
.map((f) => f.id) .filter((f) => !selectedRowKeys.includes(f.id))
.filter((id) => !selectedRowKeys.includes(id)); .map((f) => ({ id: f.id, asset_type: ShareAssetType.METRIC }));
bulkEditFavorites(allFavorites); await removeUserFavorite(allFavorites);
} }
} }
]; ];