mirror of
https://github.com/simstudioai/sim.git
synced 2026-01-31 01:37:58 -05:00
fix(invite-modal): remove custom button heights and useEffect anti-pattern (#3082)
* fix(invite-modal): remove custom button heights and useEffect anti-pattern * cleanup
This commit is contained in:
@@ -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() {
|
||||
<VariantRow label='primary'>
|
||||
<Button variant='primary'>Primary</Button>
|
||||
</VariantRow>
|
||||
<VariantRow label='destructive'>
|
||||
<Button variant='destructive'>Destructive</Button>
|
||||
</VariantRow>
|
||||
<VariantRow label='secondary'>
|
||||
<Button variant='secondary'>Secondary</Button>
|
||||
</VariantRow>
|
||||
@@ -290,6 +295,9 @@ export default function PlaygroundPage() {
|
||||
<VariantRow label='outline'>
|
||||
<Badge variant='outline'>Outline</Badge>
|
||||
</VariantRow>
|
||||
<VariantRow label='type'>
|
||||
<Badge variant='type'>Type</Badge>
|
||||
</VariantRow>
|
||||
<VariantRow label='green'>
|
||||
<Badge variant='green'>Green</Badge>
|
||||
<Badge variant='green' dot>
|
||||
@@ -323,6 +331,9 @@ export default function PlaygroundPage() {
|
||||
<VariantRow label='teal'>
|
||||
<Badge variant='teal'>Teal</Badge>
|
||||
</VariantRow>
|
||||
<VariantRow label='cyan'>
|
||||
<Badge variant='cyan'>Cyan</Badge>
|
||||
</VariantRow>
|
||||
<VariantRow label='gray'>
|
||||
<Badge variant='gray'>Gray</Badge>
|
||||
</VariantRow>
|
||||
@@ -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' },
|
||||
|
||||
@@ -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<Map<string, NodeJS.Timeout>>(new Map())
|
||||
const [errorMessage, setErrorMessage] = useState<string | null>(null)
|
||||
const [successMessage, setSuccessMessage] = useState<string | null>(null)
|
||||
const [memberToRemove, setMemberToRemove] = useState<{ userId: string; email: string } | null>(
|
||||
null
|
||||
)
|
||||
@@ -121,10 +120,17 @@ export function InviteModal({ open, onOpenChange, workspaceName }: InviteModalPr
|
||||
useEffect(() => {
|
||||
if (open) {
|
||||
setErrorMessage(null)
|
||||
setSuccessMessage(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
|
||||
@@ -255,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 =
|
||||
@@ -282,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) => {
|
||||
@@ -337,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 =
|
||||
@@ -385,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 =
|
||||
@@ -427,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) => {
|
||||
@@ -450,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]
|
||||
@@ -458,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]
|
||||
@@ -473,7 +471,6 @@ export function InviteModal({ open, onOpenChange, workspaceName }: InviteModalPr
|
||||
e.preventDefault()
|
||||
|
||||
setErrorMessage(null)
|
||||
setSuccessMessage(null)
|
||||
|
||||
if (validEmails.length === 0 || !workspaceId) {
|
||||
return
|
||||
@@ -562,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)
|
||||
@@ -588,13 +580,16 @@ 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 (
|
||||
@@ -703,7 +698,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
|
||||
</Button>
|
||||
@@ -712,7 +706,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'}
|
||||
</Button>
|
||||
|
||||
Reference in New Issue
Block a user