mirror of
https://github.com/simstudioai/sim.git
synced 2026-04-06 03:00:16 -04:00
fix(usage-data): refetch on usage limit update in settings (#2032)
This commit is contained in:
@@ -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<UsageLimitRef, UsageLimitProps>(
|
||||
const [isEditing, setIsEditing] = useState(false)
|
||||
const inputRef = useRef<HTMLInputElement>(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<UsageLimitRef, UsageLimitProps>(
|
||||
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<UsageLimitRef, UsageLimitProps>(
|
||||
}
|
||||
}, [isEditing])
|
||||
|
||||
// Clear error after 2 seconds
|
||||
useEffect(() => {
|
||||
if (hasError) {
|
||||
const timer = setTimeout(() => {
|
||||
@@ -96,11 +97,9 @@ export const UsageLimit = forwardRef<UsageLimitRef, UsageLimitProps>(
|
||||
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<UsageLimitRef, UsageLimitProps>(
|
||||
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<UsageLimitRef, UsageLimitProps>(
|
||||
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
|
||||
|
||||
@@ -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<UsageLimitRef | null>(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
|
||||
|
||||
Reference in New Issue
Block a user