Enhance DocumentPrintButton and UserNotifierToggle with Subscription Logic
- Updated DocumentPrintButton to include subscription handling for document templates, improving real-time updates and user experience. - Refactored UserNotifierToggle to manage user notifier states with enhanced subscription logic, ensuring accurate updates and improved performance. - Introduced memoization and callback optimizations to streamline data fetching and state management in both components.
This commit is contained in:
parent
8ab44fc9da
commit
835c287810
@ -21,7 +21,12 @@ const DocumentPrintButton = ({
|
|||||||
disabled = false,
|
disabled = false,
|
||||||
...buttonProps
|
...buttonProps
|
||||||
}) => {
|
}) => {
|
||||||
const { fetchObjects } = useContext(ApiServerContext)
|
const {
|
||||||
|
fetchObjects,
|
||||||
|
connected,
|
||||||
|
subscribeToObjectUpdates,
|
||||||
|
subscribeToObjectTypeUpdates
|
||||||
|
} = useContext(ApiServerContext)
|
||||||
const fetchObjectsRef = useRef(fetchObjects)
|
const fetchObjectsRef = useRef(fetchObjects)
|
||||||
fetchObjectsRef.current = fetchObjects
|
fetchObjectsRef.current = fetchObjects
|
||||||
|
|
||||||
@ -30,34 +35,59 @@ const DocumentPrintButton = ({
|
|||||||
const [loading, setLoading] = useState(false)
|
const [loading, setLoading] = useState(false)
|
||||||
const [newDocumentJobOpen, setNewDocumentJobOpen] = useState(false)
|
const [newDocumentJobOpen, setNewDocumentJobOpen] = useState(false)
|
||||||
|
|
||||||
|
const subscribedIdsRef = useRef([])
|
||||||
|
const unsubscribesRef = useRef([])
|
||||||
|
const subscribeToObjectTypeUpdatesRef = useRef(null)
|
||||||
|
const updateEventHandlerRef = useRef()
|
||||||
|
|
||||||
const { token } = useContext(AuthContext)
|
const { token } = useContext(AuthContext)
|
||||||
|
|
||||||
// Get the model by name
|
const subscriptionFilter = useMemo(
|
||||||
//const model = getModelByName(type)
|
() => ({
|
||||||
|
objectType: type,
|
||||||
|
global: false,
|
||||||
|
active: true
|
||||||
|
}),
|
||||||
|
[type]
|
||||||
|
)
|
||||||
|
|
||||||
const loadDocumentTemplates = useCallback(async () => {
|
const templateMatchesFilter = useCallback(
|
||||||
if (!type || token == null) return
|
(template) =>
|
||||||
|
template?.objectType === type &&
|
||||||
|
template?.global === false &&
|
||||||
|
template?.active === true,
|
||||||
|
[type]
|
||||||
|
)
|
||||||
|
|
||||||
setLoading(true)
|
const loadDocumentTemplates = useCallback(
|
||||||
try {
|
async (silent = false) => {
|
||||||
const result = await fetchObjectsRef.current('documentTemplate', {
|
if (!type || token == null) return
|
||||||
filter: {
|
|
||||||
objectType: type,
|
|
||||||
global: false,
|
|
||||||
active: true
|
|
||||||
},
|
|
||||||
limit: 100 // Get more templates to show in dropdown
|
|
||||||
})
|
|
||||||
|
|
||||||
if (result && result.data) {
|
if (!silent) {
|
||||||
setDocumentTemplates(result.data)
|
setLoading(true)
|
||||||
}
|
}
|
||||||
} catch (error) {
|
try {
|
||||||
console.error('Error fetching document templates:', error)
|
const result = await fetchObjectsRef.current('documentTemplate', {
|
||||||
} finally {
|
filter: subscriptionFilter,
|
||||||
setLoading(false)
|
limit: 100 // Get more templates to show in dropdown
|
||||||
}
|
})
|
||||||
}, [type, token])
|
|
||||||
|
if (result && result.data) {
|
||||||
|
setDocumentTemplates(result.data)
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error fetching document templates:', error)
|
||||||
|
} finally {
|
||||||
|
if (!silent) {
|
||||||
|
setLoading(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[type, token, subscriptionFilter]
|
||||||
|
)
|
||||||
|
|
||||||
|
const loadDocumentTemplatesRef = useRef(loadDocumentTemplates)
|
||||||
|
loadDocumentTemplatesRef.current = loadDocumentTemplates
|
||||||
|
|
||||||
// Stable key from objectData._id (excludes _isEditing so toggling edit mode doesn't trigger template reload)
|
// Stable key from objectData._id (excludes _isEditing so toggling edit mode doesn't trigger template reload)
|
||||||
const objectKey = useMemo(() => {
|
const objectKey = useMemo(() => {
|
||||||
@ -70,6 +100,103 @@ const DocumentPrintButton = ({
|
|||||||
loadDocumentTemplates()
|
loadDocumentTemplates()
|
||||||
}, [objectKey, token, type, loadDocumentTemplates])
|
}, [objectKey, token, type, loadDocumentTemplates])
|
||||||
|
|
||||||
|
const updateEventHandler = useCallback(
|
||||||
|
(id, updatedData) => {
|
||||||
|
setDocumentTemplates((prev) => {
|
||||||
|
const existing = prev.find((template) => template._id === id)
|
||||||
|
const merged = existing
|
||||||
|
? { ...existing, ...updatedData }
|
||||||
|
: { _id: id, ...updatedData }
|
||||||
|
|
||||||
|
if (!templateMatchesFilter(merged)) {
|
||||||
|
return prev.filter((template) => template._id !== id)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (existing) {
|
||||||
|
return prev.map((template) =>
|
||||||
|
template._id === id ? merged : template
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return [...prev, merged]
|
||||||
|
})
|
||||||
|
},
|
||||||
|
[templateMatchesFilter]
|
||||||
|
)
|
||||||
|
|
||||||
|
updateEventHandlerRef.current = updateEventHandler
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (connected !== true) return
|
||||||
|
|
||||||
|
const unsubscribe = subscribeToObjectTypeUpdates(
|
||||||
|
'documentTemplate',
|
||||||
|
subscriptionFilter,
|
||||||
|
() => loadDocumentTemplatesRef.current(true)
|
||||||
|
)
|
||||||
|
subscribeToObjectTypeUpdatesRef.current = unsubscribe
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
if (unsubscribe) unsubscribe()
|
||||||
|
if (subscribeToObjectTypeUpdatesRef.current === unsubscribe) {
|
||||||
|
subscribeToObjectTypeUpdatesRef.current = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [connected, subscriptionFilter, subscribeToObjectTypeUpdates])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (connected !== true) return
|
||||||
|
|
||||||
|
const templateIds = documentTemplates.map((template) => template._id).filter(Boolean)
|
||||||
|
|
||||||
|
const newTemplateIds = templateIds.filter(
|
||||||
|
(id) => !subscribedIdsRef.current.includes(id)
|
||||||
|
)
|
||||||
|
|
||||||
|
newTemplateIds.forEach((itemId) => {
|
||||||
|
const unsubscribe = subscribeToObjectUpdates(
|
||||||
|
itemId?.toLowerCase(),
|
||||||
|
'documentTemplate',
|
||||||
|
(updateData) => updateEventHandlerRef.current(itemId, updateData)
|
||||||
|
)
|
||||||
|
subscribedIdsRef.current.push(itemId)
|
||||||
|
if (unsubscribe) {
|
||||||
|
unsubscribesRef.current.push(unsubscribe)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const templateIdsToUnsubscribe = subscribedIdsRef.current.filter(
|
||||||
|
(id) => !templateIds.includes(id)
|
||||||
|
)
|
||||||
|
|
||||||
|
templateIdsToUnsubscribe.forEach((itemId) => {
|
||||||
|
const index = subscribedIdsRef.current.indexOf(itemId)
|
||||||
|
if (index > -1) {
|
||||||
|
subscribedIdsRef.current.splice(index, 1)
|
||||||
|
const unsubscribe = unsubscribesRef.current[index]
|
||||||
|
if (unsubscribe) {
|
||||||
|
unsubscribe()
|
||||||
|
}
|
||||||
|
unsubscribesRef.current.splice(index, 1)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}, [documentTemplates, connected, subscribeToObjectUpdates])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
return () => {
|
||||||
|
unsubscribesRef.current.forEach((unsubscribe) => {
|
||||||
|
if (unsubscribe) unsubscribe()
|
||||||
|
})
|
||||||
|
unsubscribesRef.current = []
|
||||||
|
subscribedIdsRef.current = []
|
||||||
|
|
||||||
|
if (subscribeToObjectTypeUpdatesRef.current) {
|
||||||
|
subscribeToObjectTypeUpdatesRef.current()
|
||||||
|
subscribeToObjectTypeUpdatesRef.current = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
// Handle template selection
|
// Handle template selection
|
||||||
const handleTemplateSelect = (template) => {
|
const handleTemplateSelect = (template) => {
|
||||||
setCurrentDocumentTemplate(template)
|
setCurrentDocumentTemplate(template)
|
||||||
@ -78,13 +205,54 @@ const DocumentPrintButton = ({
|
|||||||
// This could open a print dialog, navigate to a print page, etc.
|
// This could open a print dialog, navigate to a print page, etc.
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create dropdown menu items
|
// Group templates by tag for nested dropdown menu; untagged templates at root
|
||||||
const menuItems = documentTemplates.map((template) => ({
|
const menuItems = useMemo(() => {
|
||||||
key: template._id,
|
const templatesByTag = new Map()
|
||||||
label: template.name,
|
const untaggedTemplates = []
|
||||||
icon: <DocumentTemplateIcon />,
|
|
||||||
onClick: () => handleTemplateSelect(template)
|
const toTemplateMenuItem = (template) => ({
|
||||||
}))
|
key: template._id,
|
||||||
|
label: template.name,
|
||||||
|
icon: <DocumentTemplateIcon />,
|
||||||
|
onClick: () => handleTemplateSelect(template)
|
||||||
|
})
|
||||||
|
|
||||||
|
for (const template of documentTemplates) {
|
||||||
|
const templateTags = Array.isArray(template.tags)
|
||||||
|
? template.tags.filter(Boolean)
|
||||||
|
: []
|
||||||
|
|
||||||
|
if (templateTags.length === 0) {
|
||||||
|
untaggedTemplates.push(template)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const tag of templateTags) {
|
||||||
|
const templates = templatesByTag.get(tag) ?? []
|
||||||
|
templates.push(template)
|
||||||
|
templatesByTag.set(tag, templates)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const taggedMenuItems = [...templatesByTag.keys()]
|
||||||
|
.sort((a, b) => a.localeCompare(b))
|
||||||
|
.map((tag) => ({
|
||||||
|
key: tag,
|
||||||
|
label: tag,
|
||||||
|
children: templatesByTag
|
||||||
|
.get(tag)
|
||||||
|
.slice()
|
||||||
|
.sort((a, b) => a.name.localeCompare(b.name))
|
||||||
|
.map(toTemplateMenuItem)
|
||||||
|
}))
|
||||||
|
|
||||||
|
const rootUntaggedItems = untaggedTemplates
|
||||||
|
.slice()
|
||||||
|
.sort((a, b) => a.name.localeCompare(b.name))
|
||||||
|
.map(toTemplateMenuItem)
|
||||||
|
|
||||||
|
return [...rootUntaggedItems, ...taggedMenuItems]
|
||||||
|
}, [documentTemplates])
|
||||||
|
|
||||||
// If no templates available, show disabled state
|
// If no templates available, show disabled state
|
||||||
if (documentTemplates.length === 0 && !loading) {
|
if (documentTemplates.length === 0 && !loading) {
|
||||||
|
|||||||
@ -23,10 +23,13 @@ const UserNotifierToggle = memo(({
|
|||||||
toggleUserNotifier,
|
toggleUserNotifier,
|
||||||
editUserNotifier,
|
editUserNotifier,
|
||||||
fetchUserNotifiersForObject,
|
fetchUserNotifiersForObject,
|
||||||
fetchAllUserNotifiersForObject
|
fetchAllUserNotifiersForObject,
|
||||||
|
connected,
|
||||||
|
subscribeToObjectUpdates,
|
||||||
|
subscribeToObjectTypeUpdates
|
||||||
} = useContext(ApiServerContext)
|
} = useContext(ApiServerContext)
|
||||||
const { userProfile, token, authInitialized } = useContext(AuthContext)
|
const { userProfile, token, authInitialized } = useContext(AuthContext)
|
||||||
const [isNotifying, setIsNotifying] = useState(false)
|
const [currentUserNotifier, setCurrentUserNotifier] = useState(null)
|
||||||
const [loading, setLoading] = useState(false)
|
const [loading, setLoading] = useState(false)
|
||||||
const [initialLoad, setInitialLoad] = useState(true)
|
const [initialLoad, setInitialLoad] = useState(true)
|
||||||
const [allNotifiers, setAllNotifiers] = useState([])
|
const [allNotifiers, setAllNotifiers] = useState([])
|
||||||
@ -34,8 +37,32 @@ const UserNotifierToggle = memo(({
|
|||||||
const [popoverLoading, setPopoverLoading] = useState(false)
|
const [popoverLoading, setPopoverLoading] = useState(false)
|
||||||
const [emailTogglingId, setEmailTogglingId] = useState(null)
|
const [emailTogglingId, setEmailTogglingId] = useState(null)
|
||||||
|
|
||||||
|
const subscribedIdsRef = useRef([])
|
||||||
|
const unsubscribesRef = useRef([])
|
||||||
|
const subscribeToObjectTypeUpdatesRef = useRef(null)
|
||||||
|
const updateEventHandlerRef = useRef()
|
||||||
|
const popoverOpenRef = useRef(popoverOpen)
|
||||||
|
popoverOpenRef.current = popoverOpen
|
||||||
|
|
||||||
const objectId = objectData?._id
|
const objectId = objectData?._id
|
||||||
const authReady = Boolean(token && authInitialized)
|
const authReady = Boolean(token && authInitialized)
|
||||||
|
const isNotifying = Boolean(currentUserNotifier)
|
||||||
|
|
||||||
|
const subscriptionFilter = useMemo(
|
||||||
|
() => ({
|
||||||
|
object: objectId,
|
||||||
|
objectType: type
|
||||||
|
}),
|
||||||
|
[objectId, type]
|
||||||
|
)
|
||||||
|
|
||||||
|
const notifierMatchesFilter = useCallback(
|
||||||
|
(notifier) => {
|
||||||
|
const objectRef = notifier?.object?._id ?? notifier?.object
|
||||||
|
return objectRef === objectId && notifier?.objectType === type
|
||||||
|
},
|
||||||
|
[objectId, type]
|
||||||
|
)
|
||||||
|
|
||||||
const apiRef = useRef({
|
const apiRef = useRef({
|
||||||
fetchUserNotifiersForObject,
|
fetchUserNotifiersForObject,
|
||||||
@ -46,42 +73,196 @@ const UserNotifierToggle = memo(({
|
|||||||
fetchAllUserNotifiersForObject
|
fetchAllUserNotifiersForObject
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
const loadNotifierState = useCallback(
|
||||||
if (!authReady || !objectId || !type) return
|
async (silent = false) => {
|
||||||
|
if (!authReady || !objectId || !type) return
|
||||||
|
|
||||||
const loadNotifierState = async () => {
|
if (!silent) {
|
||||||
setInitialLoad(true)
|
setInitialLoad(true)
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
const { data } = await apiRef.current.fetchUserNotifiersForObject(objectId, type)
|
const { data } = await apiRef.current.fetchUserNotifiersForObject(
|
||||||
setIsNotifying(data?.length > 0)
|
objectId,
|
||||||
|
type
|
||||||
|
)
|
||||||
|
setCurrentUserNotifier(data?.[0] ?? null)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error fetching user notifier state:', error)
|
console.error('Error fetching user notifier state:', error)
|
||||||
} finally {
|
} finally {
|
||||||
setInitialLoad(false)
|
if (!silent) {
|
||||||
|
setInitialLoad(false)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
[authReady, objectId, type]
|
||||||
|
)
|
||||||
|
|
||||||
loadNotifierState()
|
const loadAllNotifiers = useCallback(
|
||||||
}, [authReady, objectId, type])
|
async (silent = false) => {
|
||||||
|
if (!authReady || !objectId || !type) return
|
||||||
|
|
||||||
useEffect(() => {
|
if (!silent) {
|
||||||
if (!authReady || !objectId || !type || !popoverOpen) return
|
setPopoverLoading(true)
|
||||||
|
}
|
||||||
const loadAllNotifiers = async () => {
|
|
||||||
setPopoverLoading(true)
|
|
||||||
try {
|
try {
|
||||||
const { data } = await apiRef.current.fetchAllUserNotifiersForObject(objectId, type)
|
const { data } = await apiRef.current.fetchAllUserNotifiersForObject(
|
||||||
|
objectId,
|
||||||
|
type
|
||||||
|
)
|
||||||
setAllNotifiers(data || [])
|
setAllNotifiers(data || [])
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error fetching all user notifiers:', error)
|
console.error('Error fetching all user notifiers:', error)
|
||||||
setAllNotifiers([])
|
setAllNotifiers([])
|
||||||
} finally {
|
} finally {
|
||||||
setPopoverLoading(false)
|
if (!silent) {
|
||||||
|
setPopoverLoading(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[authReady, objectId, type]
|
||||||
|
)
|
||||||
|
|
||||||
|
const loadNotifierStateRef = useRef(loadNotifierState)
|
||||||
|
loadNotifierStateRef.current = loadNotifierState
|
||||||
|
|
||||||
|
const loadAllNotifiersRef = useRef(loadAllNotifiers)
|
||||||
|
loadAllNotifiersRef.current = loadAllNotifiers
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
loadNotifierState()
|
||||||
|
}, [loadNotifierState])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!popoverOpen) return
|
||||||
|
loadAllNotifiers()
|
||||||
|
}, [popoverOpen, loadAllNotifiers])
|
||||||
|
|
||||||
|
const updateEventHandler = useCallback(
|
||||||
|
(id, updatedData) => {
|
||||||
|
setAllNotifiers((prev) => {
|
||||||
|
const existing = prev.find((notifier) => notifier._id === id)
|
||||||
|
const merged = existing
|
||||||
|
? { ...existing, ...updatedData }
|
||||||
|
: { _id: id, ...updatedData }
|
||||||
|
|
||||||
|
if (!notifierMatchesFilter(merged)) {
|
||||||
|
return prev.filter((notifier) => notifier._id !== id)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (existing) {
|
||||||
|
return prev.map((notifier) =>
|
||||||
|
notifier._id === id ? merged : notifier
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return [...prev, merged]
|
||||||
|
})
|
||||||
|
|
||||||
|
setCurrentUserNotifier((prev) => {
|
||||||
|
if (prev?._id === id) {
|
||||||
|
const merged = { ...prev, ...updatedData }
|
||||||
|
return notifierMatchesFilter(merged) ? merged : null
|
||||||
|
}
|
||||||
|
|
||||||
|
const userRef = updatedData?.user?._id ?? updatedData?.user
|
||||||
|
if (
|
||||||
|
userRef === userProfile?._id &&
|
||||||
|
notifierMatchesFilter({ _id: id, ...updatedData })
|
||||||
|
) {
|
||||||
|
return { _id: id, ...updatedData }
|
||||||
|
}
|
||||||
|
|
||||||
|
return prev
|
||||||
|
})
|
||||||
|
},
|
||||||
|
[notifierMatchesFilter, userProfile?._id]
|
||||||
|
)
|
||||||
|
|
||||||
|
updateEventHandlerRef.current = updateEventHandler
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (connected !== true || !objectId || !type) return
|
||||||
|
|
||||||
|
const unsubscribe = subscribeToObjectTypeUpdates(
|
||||||
|
'userNotifier',
|
||||||
|
subscriptionFilter,
|
||||||
|
() => {
|
||||||
|
loadNotifierStateRef.current(true)
|
||||||
|
if (popoverOpenRef.current) {
|
||||||
|
loadAllNotifiersRef.current(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
subscribeToObjectTypeUpdatesRef.current = unsubscribe
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
if (unsubscribe) unsubscribe()
|
||||||
|
if (subscribeToObjectTypeUpdatesRef.current === unsubscribe) {
|
||||||
|
subscribeToObjectTypeUpdatesRef.current = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}, [connected, subscriptionFilter, subscribeToObjectTypeUpdates, objectId, type])
|
||||||
|
|
||||||
loadAllNotifiers()
|
const subscribedNotifierIds = useMemo(() => {
|
||||||
}, [authReady, objectId, type, popoverOpen])
|
const ids = new Set(
|
||||||
|
allNotifiers.map((notifier) => notifier._id).filter(Boolean)
|
||||||
|
)
|
||||||
|
if (currentUserNotifier?._id) {
|
||||||
|
ids.add(currentUserNotifier._id)
|
||||||
|
}
|
||||||
|
return [...ids]
|
||||||
|
}, [allNotifiers, currentUserNotifier])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (connected !== true) return
|
||||||
|
|
||||||
|
const newNotifierIds = subscribedNotifierIds.filter(
|
||||||
|
(id) => !subscribedIdsRef.current.includes(id)
|
||||||
|
)
|
||||||
|
|
||||||
|
newNotifierIds.forEach((itemId) => {
|
||||||
|
const unsubscribe = subscribeToObjectUpdates(
|
||||||
|
itemId?.toLowerCase(),
|
||||||
|
'userNotifier',
|
||||||
|
(updateData) => updateEventHandlerRef.current(itemId, updateData)
|
||||||
|
)
|
||||||
|
subscribedIdsRef.current.push(itemId)
|
||||||
|
if (unsubscribe) {
|
||||||
|
unsubscribesRef.current.push(unsubscribe)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const notifierIdsToUnsubscribe = subscribedIdsRef.current.filter(
|
||||||
|
(id) => !subscribedNotifierIds.includes(id)
|
||||||
|
)
|
||||||
|
|
||||||
|
notifierIdsToUnsubscribe.forEach((itemId) => {
|
||||||
|
const index = subscribedIdsRef.current.indexOf(itemId)
|
||||||
|
if (index > -1) {
|
||||||
|
subscribedIdsRef.current.splice(index, 1)
|
||||||
|
const unsubscribe = unsubscribesRef.current[index]
|
||||||
|
if (unsubscribe) {
|
||||||
|
unsubscribe()
|
||||||
|
}
|
||||||
|
unsubscribesRef.current.splice(index, 1)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}, [subscribedNotifierIds, connected, subscribeToObjectUpdates])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
return () => {
|
||||||
|
unsubscribesRef.current.forEach((unsubscribe) => {
|
||||||
|
if (unsubscribe) unsubscribe()
|
||||||
|
})
|
||||||
|
unsubscribesRef.current = []
|
||||||
|
subscribedIdsRef.current = []
|
||||||
|
|
||||||
|
if (subscribeToObjectTypeUpdatesRef.current) {
|
||||||
|
subscribeToObjectTypeUpdatesRef.current()
|
||||||
|
subscribeToObjectTypeUpdatesRef.current = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
const handleClick = useCallback(async () => {
|
const handleClick = useCallback(async () => {
|
||||||
if (!authReady || !objectId || !type || loading) return
|
if (!authReady || !objectId || !type || loading) return
|
||||||
@ -89,7 +270,12 @@ const UserNotifierToggle = memo(({
|
|||||||
setLoading(true)
|
setLoading(true)
|
||||||
try {
|
try {
|
||||||
const enabled = await toggleUserNotifier(objectId, type)
|
const enabled = await toggleUserNotifier(objectId, type)
|
||||||
setIsNotifying(enabled)
|
if (enabled) {
|
||||||
|
const { data } = await fetchUserNotifiersForObject(objectId, type)
|
||||||
|
setCurrentUserNotifier(data?.[0] ?? null)
|
||||||
|
} else {
|
||||||
|
setCurrentUserNotifier(null)
|
||||||
|
}
|
||||||
if (popoverOpen) {
|
if (popoverOpen) {
|
||||||
const { data } = await fetchAllUserNotifiersForObject(objectId, type)
|
const { data } = await fetchAllUserNotifiersForObject(objectId, type)
|
||||||
setAllNotifiers(data || [])
|
setAllNotifiers(data || [])
|
||||||
@ -105,7 +291,7 @@ const UserNotifierToggle = memo(({
|
|||||||
} finally {
|
} finally {
|
||||||
setLoading(false)
|
setLoading(false)
|
||||||
}
|
}
|
||||||
}, [authReady, objectId, type, loading, popoverOpen, toggleUserNotifier, fetchAllUserNotifiersForObject])
|
}, [authReady, objectId, type, loading, popoverOpen, toggleUserNotifier, fetchUserNotifiersForObject, fetchAllUserNotifiersForObject])
|
||||||
|
|
||||||
const getUserDisplayName = useCallback((user) => {
|
const getUserDisplayName = useCallback((user) => {
|
||||||
if (!user) return 'Unknown'
|
if (!user) return 'Unknown'
|
||||||
@ -132,6 +318,11 @@ const UserNotifierToggle = memo(({
|
|||||||
n._id === item._id ? { ...n, email: result.email ?? newEmail } : n
|
n._id === item._id ? { ...n, email: result.email ?? newEmail } : n
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
setCurrentUserNotifier((prev) =>
|
||||||
|
prev?._id === item._id
|
||||||
|
? { ...prev, email: result.email ?? newEmail }
|
||||||
|
: prev
|
||||||
|
)
|
||||||
message.success(
|
message.success(
|
||||||
(result.email ?? newEmail)
|
(result.email ?? newEmail)
|
||||||
? 'Email notifications enabled'
|
? 'Email notifications enabled'
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user