From df7b0fc9631424b70086bb1a740f7a39fb4e7913 Mon Sep 17 00:00:00 2001 From: waleed Date: Fri, 30 Jan 2026 11:17:57 -0800 Subject: [PATCH 1/2] fix(invite-modal): remove custom button heights and useEffect anti-pattern --- .../components/invite-modal/invite-modal.tsx | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/workspace-header/components/invite-modal/invite-modal.tsx b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/workspace-header/components/invite-modal/invite-modal.tsx index daa4817b71..7a3020c409 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/workspace-header/components/invite-modal/invite-modal.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/workspace-header/components/invite-modal/invite-modal.tsx @@ -118,13 +118,6 @@ export function InviteModal({ open, onOpenChange, workspaceName }: InviteModalPr } }, [open, workspaceId, fetchPendingInvitations, refetchPermissions]) - useEffect(() => { - if (open) { - setErrorMessage(null) - setSuccessMessage(null) - } - }, [open]) - const addEmail = useCallback( (email: string) => { if (!email.trim()) return false @@ -601,7 +594,10 @@ export function InviteModal({ open, onOpenChange, workspaceName }: InviteModalPr { - if (!newOpen) { + if (newOpen) { + setErrorMessage(null) + setSuccessMessage(null) + } else { resetState() } onOpenChange(newOpen) @@ -703,7 +699,6 @@ export function InviteModal({ open, onOpenChange, workspaceName }: InviteModalPr variant='default' disabled={isSaving || isSubmitting} onClick={handleRestoreChanges} - className='h-[32px] gap-[8px] px-[12px] font-medium' > Restore Changes @@ -712,7 +707,6 @@ export function InviteModal({ open, onOpenChange, workspaceName }: InviteModalPr variant='tertiary' disabled={isSaving || isSubmitting} onClick={handleSaveChanges} - className='h-[32px] gap-[8px] px-[12px] font-medium' > {isSaving ? 'Saving...' : 'Save Changes'} From d16416f68119e3897ecf3ba6aee209ec07db8b56 Mon Sep 17 00:00:00 2001 From: waleed Date: Fri, 30 Jan 2026 11:40:26 -0800 Subject: [PATCH 2/2] cleanup --- apps/sim/app/playground/page.tsx | 13 ++++ .../components/invite-modal/invite-modal.tsx | 61 +++++++++---------- 2 files changed, 43 insertions(+), 31 deletions(-) diff --git a/apps/sim/app/playground/page.tsx b/apps/sim/app/playground/page.tsx index d380256a21..bd5e6b7b5c 100644 --- a/apps/sim/app/playground/page.tsx +++ b/apps/sim/app/playground/page.tsx @@ -24,6 +24,7 @@ import { Cursor, DatePicker, DocumentAttachment, + Download, Duplicate, Expand, Eye, @@ -51,6 +52,7 @@ import { NoWrap, PanelLeft, Play, + PlayOutline, Popover, PopoverBackButton, PopoverContent, @@ -214,6 +216,9 @@ export default function PlaygroundPage() { + + + @@ -290,6 +295,9 @@ export default function PlaygroundPage() { Outline + + Type + Green @@ -323,6 +331,9 @@ export default function PlaygroundPage() { Teal + + Cyan + Gray @@ -996,6 +1007,7 @@ export default function PlaygroundPage() { { Icon: Copy, name: 'Copy' }, { Icon: Cursor, name: 'Cursor' }, { Icon: DocumentAttachment, name: 'DocumentAttachment' }, + { Icon: Download, name: 'Download' }, { Icon: Duplicate, name: 'Duplicate' }, { Icon: Expand, name: 'Expand' }, { Icon: Eye, name: 'Eye' }, @@ -1011,6 +1023,7 @@ export default function PlaygroundPage() { { Icon: NoWrap, name: 'NoWrap' }, { Icon: PanelLeft, name: 'PanelLeft' }, { Icon: Play, name: 'Play' }, + { Icon: PlayOutline, name: 'PlayOutline' }, { Icon: Redo, name: 'Redo' }, { Icon: Rocket, name: 'Rocket' }, { Icon: Trash, name: 'Trash' }, diff --git a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/workspace-header/components/invite-modal/invite-modal.tsx b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/workspace-header/components/invite-modal/invite-modal.tsx index 7a3020c409..9d962d86d7 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/workspace-header/components/invite-modal/invite-modal.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/workspace-header/components/invite-modal/invite-modal.tsx @@ -50,9 +50,8 @@ export function InviteModal({ open, onOpenChange, workspaceName }: InviteModalPr >({}) const [isSubmitting, setIsSubmitting] = useState(false) const [isSaving, setIsSaving] = useState(false) - const [showSent, setShowSent] = useState(false) + const cooldownIntervalsRef = useRef>(new Map()) const [errorMessage, setErrorMessage] = useState(null) - const [successMessage, setSuccessMessage] = useState(null) const [memberToRemove, setMemberToRemove] = useState<{ userId: string; email: string } | null>( null ) @@ -118,6 +117,20 @@ export function InviteModal({ open, onOpenChange, workspaceName }: InviteModalPr } }, [open, workspaceId, fetchPendingInvitations, refetchPermissions]) + useEffect(() => { + if (open) { + setErrorMessage(null) + } + }, [open]) + + useEffect(() => { + const intervalsRef = cooldownIntervalsRef.current + return () => { + intervalsRef.forEach((interval) => clearInterval(interval)) + intervalsRef.clear() + } + }, []) + const addEmail = useCallback( (email: string) => { if (!email.trim()) return false @@ -248,11 +261,6 @@ export function InviteModal({ open, onOpenChange, workspaceName }: InviteModalPr } setExistingUserPermissionChanges({}) - - setSuccessMessage( - `Permission changes saved for ${updates.length} user${updates.length !== 1 ? 's' : ''}!` - ) - setTimeout(() => setSuccessMessage(null), 3000) } catch (error) { logger.error('Error saving permission changes:', error) const errorMsg = @@ -275,9 +283,6 @@ export function InviteModal({ open, onOpenChange, workspaceName }: InviteModalPr if (!userPerms.canAdmin || !hasPendingChanges) return setExistingUserPermissionChanges({}) - setSuccessMessage('Changes restored to original permissions!') - - setTimeout(() => setSuccessMessage(null), 3000) }, [userPerms.canAdmin, hasPendingChanges]) const handleRemoveMemberClick = useCallback((userId: string, email: string) => { @@ -330,9 +335,6 @@ export function InviteModal({ open, onOpenChange, workspaceName }: InviteModalPr delete updated[memberToRemove.userId] return updated }) - - setSuccessMessage(`${memberToRemove.email} has been removed from the workspace`) - setTimeout(() => setSuccessMessage(null), 3000) } catch (error) { logger.error('Error removing member:', error) const errorMsg = @@ -378,9 +380,6 @@ export function InviteModal({ open, onOpenChange, workspaceName }: InviteModalPr setPendingInvitations((prev) => prev.filter((inv) => inv.invitationId !== invitationToRemove.invitationId) ) - - setSuccessMessage(`Invitation for ${invitationToRemove.email} has been cancelled`) - setTimeout(() => setSuccessMessage(null), 3000) } catch (error) { logger.error('Error cancelling invitation:', error) const errorMsg = @@ -420,9 +419,6 @@ export function InviteModal({ open, onOpenChange, workspaceName }: InviteModalPr throw new Error(data.error || 'Failed to resend invitation') } - setSuccessMessage(`Invitation resent to ${email}`) - setTimeout(() => setSuccessMessage(null), 3000) - setResentInvitationIds((prev) => ({ ...prev, [invitationId]: true })) setTimeout(() => { setResentInvitationIds((prev) => { @@ -443,6 +439,12 @@ export function InviteModal({ open, onOpenChange, workspaceName }: InviteModalPr return next }) setResendCooldowns((prev) => ({ ...prev, [invitationId]: 60 })) + + const existingInterval = cooldownIntervalsRef.current.get(invitationId) + if (existingInterval) { + clearInterval(existingInterval) + } + const interval = setInterval(() => { setResendCooldowns((prev) => { const current = prev[invitationId] @@ -451,11 +453,14 @@ export function InviteModal({ open, onOpenChange, workspaceName }: InviteModalPr const next = { ...prev } delete next[invitationId] clearInterval(interval) + cooldownIntervalsRef.current.delete(invitationId) return next } return { ...prev, [invitationId]: current - 1 } }) }, 1000) + + cooldownIntervalsRef.current.set(invitationId, interval) } }, [workspaceId, userPerms.canAdmin, resendCooldowns] @@ -466,7 +471,6 @@ export function InviteModal({ open, onOpenChange, workspaceName }: InviteModalPr e.preventDefault() setErrorMessage(null) - setSuccessMessage(null) if (validEmails.length === 0 || !workspaceId) { return @@ -555,11 +559,6 @@ export function InviteModal({ open, onOpenChange, workspaceName }: InviteModalPr setEmailItems([]) setUserPermissions([]) } - setShowSent(true) - - setTimeout(() => { - setShowSent(false) - }, 4000) } } catch (err) { logger.error('Error inviting members:', err) @@ -581,23 +580,23 @@ export function InviteModal({ open, onOpenChange, workspaceName }: InviteModalPr setExistingUserPermissionChanges({}) setIsSubmitting(false) setIsSaving(false) - setShowSent(false) setErrorMessage(null) - setSuccessMessage(null) setMemberToRemove(null) setIsRemovingMember(false) setInvitationToRemove(null) setIsRemovingInvitation(false) + setResendCooldowns({}) + setResentInvitationIds({}) + + cooldownIntervalsRef.current.forEach((interval) => clearInterval(interval)) + cooldownIntervalsRef.current.clear() }, []) return ( { - if (newOpen) { - setErrorMessage(null) - setSuccessMessage(null) - } else { + if (!newOpen) { resetState() } onOpenChange(newOpen)