From 521fd7afdbb904887e6473dd2cb61a46964296ef Mon Sep 17 00:00:00 2001 From: waleed Date: Mon, 17 Nov 2025 15:00:45 -0800 Subject: [PATCH] fix(usage-data): refetch on usage limit update in settings --- .../components/usage-limit/usage-limit.tsx | 51 +++++++++++++------ .../components/subscription/subscription.tsx | 17 +------ 2 files changed, 38 insertions(+), 30 deletions(-) diff --git a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components-new/settings-modal/components/subscription/components/usage-limit/usage-limit.tsx b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components-new/settings-modal/components/subscription/components/usage-limit/usage-limit.tsx index 84d25e236f3..d33f01f2c4a 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components-new/settings-modal/components/subscription/components/usage-limit/usage-limit.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components-new/settings-modal/components/subscription/components/usage-limit/usage-limit.tsx @@ -6,6 +6,7 @@ import { Button } from '@/components/ui/button' import { createLogger } from '@/lib/logs/console/logger' import { cn } from '@/lib/utils' import { useUsageLimits } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel-new/hooks' +import { useUpdateUsageLimit } from '@/hooks/queries/subscription' const logger = createLogger('UsageLimit') @@ -42,20 +43,22 @@ export const UsageLimit = forwardRef( const [isEditing, setIsEditing] = useState(false) const inputRef = useRef(null) - // Use centralized usage limits hook - const { updateLimit, isUpdating } = useUsageLimits({ + const { updateLimit, isUpdating: isOrgUpdating } = useUsageLimits({ context, organizationId, autoRefresh: false, // Don't auto-refresh, we receive values via props }) + const updateUsageLimitMutation = useUpdateUsageLimit() + const isUpdating = + context === 'organization' ? isOrgUpdating : updateUsageLimitMutation.isPending + const handleStartEdit = () => { if (!canEdit) return setIsEditing(true) setInputValue(currentLimit.toString()) } - // Expose startEdit method through ref useImperativeHandle( ref, () => ({ @@ -68,7 +71,6 @@ export const UsageLimit = forwardRef( setInputValue(currentLimit.toString()) }, [currentLimit]) - // Focus input when entering edit mode useEffect(() => { if (isEditing && inputRef.current) { inputRef.current.focus() @@ -76,7 +78,6 @@ export const UsageLimit = forwardRef( } }, [isEditing]) - // Clear error after 2 seconds useEffect(() => { if (hasError) { const timer = setTimeout(() => { @@ -96,11 +97,9 @@ export const UsageLimit = forwardRef( return } - // Check if new limit is below current usage if (newLimit < currentUsage) { setHasError(true) setErrorType('belowUsage') - // Don't reset input value - let user see what they typed return } @@ -109,20 +108,43 @@ export const UsageLimit = forwardRef( return } - // Use the centralized hook to update the limit - const result = await updateLimit(newLimit) + try { + if (context === 'organization') { + const result = await updateLimit(newLimit) + + if (result.success) { + setInputValue(newLimit.toString()) + onLimitUpdated?.(newLimit) + setIsEditing(false) + setErrorType(null) + setHasError(false) + } else { + logger.error('Failed to update usage limit', { error: result.error }) + + if (result.error?.includes('below current usage')) { + setErrorType('belowUsage') + } else { + setErrorType('general') + } + + setHasError(true) + } + + return + } + + await updateUsageLimitMutation.mutateAsync({ limit: newLimit }) - if (result.success) { setInputValue(newLimit.toString()) onLimitUpdated?.(newLimit) setIsEditing(false) setErrorType(null) setHasError(false) - } else { - logger.error('Failed to update usage limit', { error: result.error }) + } catch (err) { + logger.error('Failed to update usage limit', { error: err }) - // Check if the error is about being below current usage - if (result.error?.includes('below current usage')) { + const message = err instanceof Error ? err.message : String(err) + if (message.includes('below current usage')) { setErrorType('belowUsage') } else { setErrorType('general') @@ -161,7 +183,6 @@ export const UsageLimit = forwardRef( onChange={(e) => setInputValue(e.target.value)} onKeyDown={handleKeyDown} onBlur={(e) => { - // Don't submit if clicking on the button (it will handle submission) const relatedTarget = e.relatedTarget as HTMLElement if (relatedTarget?.closest('button')) { return diff --git a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components-new/settings-modal/components/subscription/subscription.tsx b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components-new/settings-modal/components/subscription/subscription.tsx index 274be344bf4..eb535903572 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components-new/settings-modal/components/subscription/subscription.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components-new/settings-modal/components/subscription/subscription.tsx @@ -169,7 +169,6 @@ export function Subscription({ onOpenChange }: SubscriptionProps) { const canManageWorkspaceKeys = userPermissions.canAdmin const logger = createLogger('Subscription') - // React Query hooks for data fetching const { data: subscriptionData, isLoading: isSubscriptionLoading } = useSubscriptionData() const { data: usageLimitResponse, isLoading: isUsageLimitLoading } = useUsageLimitData() const { data: workspaceData, isLoading: isWorkspaceLoading } = useWorkspaceSettings(workspaceId) @@ -179,7 +178,6 @@ export function Subscription({ onOpenChange }: SubscriptionProps) { const activeOrganization = orgsData?.activeOrganization const activeOrgId = activeOrganization?.id - // Fetch organization billing data with React Query const { data: organizationBillingData, isLoading: isOrgBillingLoading } = useOrganizationBilling( activeOrgId || '' ) @@ -187,10 +185,8 @@ export function Subscription({ onOpenChange }: SubscriptionProps) { const [upgradeError, setUpgradeError] = useState<'pro' | 'team' | null>(null) const usageLimitRef = useRef(null) - // Combine all loading states const isLoading = isSubscriptionLoading || isUsageLimitLoading || isWorkspaceLoading - // Extract subscription status from subscriptionData.data const subscription = { isFree: subscriptionData?.data?.plan === 'free' || !subscriptionData?.data?.plan, isPro: subscriptionData?.data?.plan === 'pro', @@ -205,28 +201,23 @@ export function Subscription({ onOpenChange }: SubscriptionProps) { seats: subscriptionData?.data?.seats || 1, } - // Extract usage data from subscriptionData.data.usage (same source as panel usage indicator) const usage = { current: subscriptionData?.data?.usage?.current || 0, limit: subscriptionData?.data?.usage?.limit || 0, percentUsed: subscriptionData?.data?.usage?.percentUsed || 0, } - // Extract usage limit metadata from usageLimitResponse.data const usageLimitData = { currentLimit: usageLimitResponse?.data?.currentLimit || 0, minimumLimit: usageLimitResponse?.data?.minimumLimit || (subscription.isPro ? 20 : 40), } - // Extract billing status const billingStatus = subscriptionData?.data?.billingBlocked ? 'blocked' : 'ok' - // Extract workspace settings const billedAccountUserId = workspaceData?.settings?.workspace?.billedAccountUserId ?? null const workspaceAdmins = workspaceData?.permissions?.users?.filter((user: any) => user.permissionType === 'admin') || [] - // Update workspace settings handler const updateWorkspaceSettings = async (updates: { billedAccountUserId?: string }) => { if (!workspaceId) return try { @@ -240,7 +231,6 @@ export function Subscription({ onOpenChange }: SubscriptionProps) { } } - // Auto-clear upgrade error useEffect(() => { if (upgradeError) { const timer = setTimeout(() => { @@ -250,11 +240,9 @@ export function Subscription({ onOpenChange }: SubscriptionProps) { } }, [upgradeError]) - // User role and permissions const userRole = getUserRole(activeOrganization, session?.user?.email) const isTeamAdmin = ['owner', 'admin'].includes(userRole) - // Get permissions based on subscription state and user role const permissions = getSubscriptionPermissions( { isFree: subscription.isFree, @@ -271,7 +259,6 @@ export function Subscription({ onOpenChange }: SubscriptionProps) { } ) - // Get visible plans based on current subscription const visiblePlans = getVisiblePlans( { isFree: subscription.isFree, @@ -459,8 +446,8 @@ export function Subscription({ onOpenChange }: SubscriptionProps) { } context={subscription.isTeam && isTeamAdmin ? 'organization' : 'user'} organizationId={subscription.isTeam && isTeamAdmin ? activeOrgId : undefined} - onLimitUpdated={async () => { - // React Query will automatically refetch when the mutation completes + onLimitUpdated={() => { + logger.info('Usage limit updated') }} /> ) : undefined