Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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')

Expand Down Expand Up @@ -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,
() => ({
Expand All @@ -68,15 +71,13 @@ export const UsageLimit = forwardRef<UsageLimitRef, UsageLimitProps>(
setInputValue(currentLimit.toString())
}, [currentLimit])

// Focus input when entering edit mode
useEffect(() => {
if (isEditing && inputRef.current) {
inputRef.current.focus()
inputRef.current.select()
}
}, [isEditing])

// Clear error after 2 seconds
useEffect(() => {
if (hasError) {
const timer = setTimeout(() => {
Expand All @@ -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
}

Expand All @@ -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')
Expand Down Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -179,18 +178,15 @@ 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 || ''
)

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',
Expand All @@ -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 {
Expand All @@ -240,7 +231,6 @@ export function Subscription({ onOpenChange }: SubscriptionProps) {
}
}

// Auto-clear upgrade error
useEffect(() => {
if (upgradeError) {
const timer = setTimeout(() => {
Expand All @@ -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,
Expand All @@ -271,7 +259,6 @@ export function Subscription({ onOpenChange }: SubscriptionProps) {
}
)

// Get visible plans based on current subscription
const visiblePlans = getVisiblePlans(
{
isFree: subscription.isFree,
Expand Down Expand Up @@ -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
Expand Down