refactor: optimize audit log filtering in OrganizationSettings by using refs to stabilize state updates and improve performance
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
'use client'
|
'use client'
|
||||||
|
|
||||||
import { useState, useEffect, useCallback } from 'react'
|
import { useState, useEffect, useCallback, useRef } from 'react'
|
||||||
import { useRouter, useSearchParams } from 'next/navigation'
|
import { useRouter, useSearchParams } from 'next/navigation'
|
||||||
import { useAuth } from '@/lib/auth/context'
|
import { useAuth } from '@/lib/auth/context'
|
||||||
import {
|
import {
|
||||||
@@ -90,6 +90,24 @@ export default function OrganizationSettings() {
|
|||||||
const [auditStartDate, setAuditStartDate] = useState('')
|
const [auditStartDate, setAuditStartDate] = useState('')
|
||||||
const [auditEndDate, setAuditEndDate] = useState('')
|
const [auditEndDate, setAuditEndDate] = useState('')
|
||||||
|
|
||||||
|
// Refs for filters to keep loadAudit stable and avoid rapid re-renders
|
||||||
|
const filtersRef = useRef({
|
||||||
|
action: auditActionFilter,
|
||||||
|
logId: auditLogIdFilter,
|
||||||
|
startDate: auditStartDate,
|
||||||
|
endDate: auditEndDate
|
||||||
|
})
|
||||||
|
|
||||||
|
// Update refs when state changes
|
||||||
|
useEffect(() => {
|
||||||
|
filtersRef.current = {
|
||||||
|
action: auditActionFilter,
|
||||||
|
logId: auditLogIdFilter,
|
||||||
|
startDate: auditStartDate,
|
||||||
|
endDate: auditEndDate
|
||||||
|
}
|
||||||
|
}, [auditActionFilter, auditLogIdFilter, auditStartDate, auditEndDate])
|
||||||
|
|
||||||
const getOrgIdFromToken = () => {
|
const getOrgIdFromToken = () => {
|
||||||
return user?.org_id || null
|
return user?.org_id || null
|
||||||
}
|
}
|
||||||
@@ -174,10 +192,10 @@ export default function OrganizationSettings() {
|
|||||||
limit: auditPageSize,
|
limit: auditPageSize,
|
||||||
offset: auditPage * auditPageSize,
|
offset: auditPage * auditPageSize,
|
||||||
}
|
}
|
||||||
if (auditActionFilter) params.action = auditActionFilter
|
if (filtersRef.current.action) params.action = filtersRef.current.action
|
||||||
if (auditLogIdFilter) params.log_id = auditLogIdFilter
|
if (filtersRef.current.logId) params.log_id = filtersRef.current.logId
|
||||||
if (auditStartDate) params.start_date = auditStartDate
|
if (filtersRef.current.startDate) params.start_date = filtersRef.current.startDate
|
||||||
if (auditEndDate) params.end_date = auditEndDate
|
if (filtersRef.current.endDate) params.end_date = filtersRef.current.endDate
|
||||||
const { entries, total } = await getAuditLog(params)
|
const { entries, total } = await getAuditLog(params)
|
||||||
setAuditEntries(Array.isArray(entries) ? entries : [])
|
setAuditEntries(Array.isArray(entries) ? entries : [])
|
||||||
setAuditTotal(typeof total === 'number' ? total : 0)
|
setAuditTotal(typeof total === 'number' ? total : 0)
|
||||||
@@ -187,7 +205,18 @@ export default function OrganizationSettings() {
|
|||||||
} finally {
|
} finally {
|
||||||
setIsLoadingAudit(false)
|
setIsLoadingAudit(false)
|
||||||
}
|
}
|
||||||
}, [currentOrgId, auditPage, auditActionFilter, auditLogIdFilter, auditStartDate, auditEndDate])
|
}, [currentOrgId, auditPage])
|
||||||
|
|
||||||
|
// Debounced filter change handler
|
||||||
|
useEffect(() => {
|
||||||
|
if (activeTab !== 'audit') return
|
||||||
|
|
||||||
|
const timer = setTimeout(() => {
|
||||||
|
setAuditPage(0) // Reset page on filter change
|
||||||
|
loadAudit()
|
||||||
|
}, 500)
|
||||||
|
return () => clearTimeout(timer)
|
||||||
|
}, [auditActionFilter, auditLogIdFilter, auditStartDate, auditEndDate, loadAudit])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (activeTab === 'audit' && currentOrgId) {
|
if (activeTab === 'audit' && currentOrgId) {
|
||||||
@@ -306,6 +335,11 @@ export default function OrganizationSettings() {
|
|||||||
// We can find the current user's membership entry which has org name.
|
// We can find the current user's membership entry which has org name.
|
||||||
const currentOrgName = members.find(m => m.user_id === user?.id)?.organization_name || 'Organization'
|
const currentOrgName = members.find(m => m.user_id === user?.id)?.organization_name || 'Organization'
|
||||||
|
|
||||||
|
const handleTabChange = (tab: 'general' | 'members' | 'billing' | 'audit') => {
|
||||||
|
setActiveTab(tab)
|
||||||
|
router.push(`?tab=${tab}`)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="max-w-4xl mx-auto space-y-8">
|
<div className="max-w-4xl mx-auto space-y-8">
|
||||||
<div>
|
<div>
|
||||||
@@ -319,7 +353,7 @@ export default function OrganizationSettings() {
|
|||||||
{/* Sidebar Navigation */}
|
{/* Sidebar Navigation */}
|
||||||
<nav className="w-full md:w-64 flex-shrink-0 space-y-1">
|
<nav className="w-full md:w-64 flex-shrink-0 space-y-1">
|
||||||
<button
|
<button
|
||||||
onClick={() => setActiveTab('general')}
|
onClick={() => handleTabChange('general')}
|
||||||
className={`w-full flex items-center gap-3 px-4 py-3 text-sm font-medium rounded-xl transition-all duration-200 ${
|
className={`w-full flex items-center gap-3 px-4 py-3 text-sm font-medium rounded-xl transition-all duration-200 ${
|
||||||
activeTab === 'general'
|
activeTab === 'general'
|
||||||
? 'bg-brand-orange/10 text-brand-orange'
|
? 'bg-brand-orange/10 text-brand-orange'
|
||||||
@@ -330,7 +364,7 @@ export default function OrganizationSettings() {
|
|||||||
General
|
General
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={() => setActiveTab('members')}
|
onClick={() => handleTabChange('members')}
|
||||||
className={`w-full flex items-center gap-3 px-4 py-3 text-sm font-medium rounded-xl transition-all duration-200 ${
|
className={`w-full flex items-center gap-3 px-4 py-3 text-sm font-medium rounded-xl transition-all duration-200 ${
|
||||||
activeTab === 'members'
|
activeTab === 'members'
|
||||||
? 'bg-brand-orange/10 text-brand-orange'
|
? 'bg-brand-orange/10 text-brand-orange'
|
||||||
@@ -341,7 +375,7 @@ export default function OrganizationSettings() {
|
|||||||
Members
|
Members
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={() => setActiveTab('billing')}
|
onClick={() => handleTabChange('billing')}
|
||||||
className={`w-full flex items-center gap-3 px-4 py-3 text-sm font-medium rounded-xl transition-all duration-200 ${
|
className={`w-full flex items-center gap-3 px-4 py-3 text-sm font-medium rounded-xl transition-all duration-200 ${
|
||||||
activeTab === 'billing'
|
activeTab === 'billing'
|
||||||
? 'bg-brand-orange/10 text-brand-orange'
|
? 'bg-brand-orange/10 text-brand-orange'
|
||||||
@@ -352,7 +386,7 @@ export default function OrganizationSettings() {
|
|||||||
Billing
|
Billing
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={() => setActiveTab('audit')}
|
onClick={() => handleTabChange('audit')}
|
||||||
className={`w-full flex items-center gap-3 px-4 py-3 text-sm font-medium rounded-xl transition-all duration-200 ${
|
className={`w-full flex items-center gap-3 px-4 py-3 text-sm font-medium rounded-xl transition-all duration-200 ${
|
||||||
activeTab === 'audit'
|
activeTab === 'audit'
|
||||||
? 'bg-brand-orange/10 text-brand-orange'
|
? 'bg-brand-orange/10 text-brand-orange'
|
||||||
|
|||||||
Reference in New Issue
Block a user