@@ -92,6 +92,7 @@ import {
9292 optimisticallyScheduleNewlyEligibleGroups ,
9393} from '@/lib/table/deps'
9494import { runUploadStrategy } from '@/lib/uploads/client/direct-upload'
95+ import { useSettingsNavigation } from '@/hooks/use-settings-navigation'
9596
9697const logger = createLogger ( 'TableQueries' )
9798
@@ -571,8 +572,28 @@ export function useDeleteTable(workspaceId: string) {
571572 * Populates the cache on success so the new row is immediately available
572573 * without waiting for the background refetch triggered by invalidation.
573574 */
575+ /**
576+ * Toasts a failed row write. A plan row-limit failure (the best-effort cap in
577+ * `assertRowCapacity`) gets an "Upgrade" action routing to billing; other errors are
578+ * a plain auto-dismissing toast. Validation errors are surfaced inline, not here.
579+ */
580+ function notifyRowWriteError (
581+ error : Error ,
582+ navigateToSettings : ReturnType < typeof useSettingsNavigation > [ 'navigateToSettings' ]
583+ ) : void {
584+ if ( isValidationError ( error ) ) return
585+ if ( error . message . toLowerCase ( ) . includes ( 'row limit' ) ) {
586+ toast . error ( error . message , {
587+ action : { label : 'Upgrade' , onClick : ( ) => navigateToSettings ( { section : 'billing' } ) } ,
588+ } )
589+ return
590+ }
591+ toast . error ( error . message , { duration : 5000 } )
592+ }
593+
574594export function useCreateTableRow ( { workspaceId, tableId } : RowMutationContext ) {
575595 const queryClient = useQueryClient ( )
596+ const { navigateToSettings } = useSettingsNavigation ( )
576597
577598 return useMutation ( {
578599 mutationFn : async (
@@ -617,10 +638,7 @@ export function useCreateTableRow({ workspaceId, tableId }: RowMutationContext)
617638 predicate : ( query ) => ! isDefaultOrderRowsQuery ( query . queryKey ) ,
618639 } )
619640 } ,
620- onError : ( error ) => {
621- if ( isValidationError ( error ) ) return
622- toast . error ( error . message , { duration : 5000 } )
623- } ,
641+ onError : ( error ) => notifyRowWriteError ( error , navigateToSettings ) ,
624642 onSettled : ( ) => {
625643 // `reconcileCreatedRow` (onSuccess) is the source of truth for the rows
626644 // cache + its `totalCount`; only refresh the count surfaces here so a late
@@ -783,6 +801,7 @@ type BatchCreateTableRowsResponse = ContractJsonResponse<typeof batchCreateTable
783801 */
784802export function useBatchCreateTableRows ( { workspaceId, tableId } : RowMutationContext ) {
785803 const queryClient = useQueryClient ( )
804+ const { navigateToSettings } = useSettingsNavigation ( )
786805
787806 return useMutation ( {
788807 mutationFn : async (
@@ -798,10 +817,7 @@ export function useBatchCreateTableRows({ workspaceId, tableId }: RowMutationCon
798817 } ,
799818 } )
800819 } ,
801- onError : ( error ) => {
802- if ( isValidationError ( error ) ) return
803- toast . error ( error . message , { duration : 5000 } )
804- } ,
820+ onError : ( error ) => notifyRowWriteError ( error , navigateToSettings ) ,
805821 onSettled : ( ) => {
806822 invalidateRowCount ( queryClient , tableId )
807823 } ,
0 commit comments