fix: resolve lint warnings in hooks, store, and sentry modules
- Move ref assignments from render to useEffect (useViewportCommentRead, useViewportObserver) - Copy ref.current to local variable for effect cleanup closure - Add eslint-disable for intentional ref-as-cache pattern (useStableTeamMentionMeta) - Fix !== always-true comparison between undefined and null (store) - Add missing return types (sentry, composerDraftStorage) - Remove unused import isLeadAgentType (memberHelpers) - Suppress naming-convention warning for Vite-injected __APP_VERSION__
This commit is contained in:
parent
bbb34042a8
commit
bf2220daf6
8 changed files with 28 additions and 13 deletions
|
|
@ -88,6 +88,10 @@ export function useStableTeamMentionMeta(teams: readonly TeamSummary[]): TeamMen
|
|||
null
|
||||
);
|
||||
|
||||
// Intentional ref-as-cache pattern: avoids allocating a new object every
|
||||
// render while still returning a referentially-stable value when the
|
||||
// underlying data hasn't changed.
|
||||
|
||||
if (
|
||||
stableRef.current === null ||
|
||||
!areTeamMentionEntriesEqual(stableRef.current.entries, entries)
|
||||
|
|
@ -98,5 +102,6 @@ export function useStableTeamMentionMeta(teams: readonly TeamSummary[]): TeamMen
|
|||
};
|
||||
}
|
||||
|
||||
// eslint-disable-next-line react-hooks/refs -- stable ref cache pattern
|
||||
return stableRef.current.value;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,8 +47,11 @@ export function useViewportCommentRead({
|
|||
const seenIdsRef = useRef<Set<string>>(new Set());
|
||||
const teamNameRef = useRef(teamName);
|
||||
const taskIdRef = useRef(taskId);
|
||||
teamNameRef.current = teamName;
|
||||
taskIdRef.current = taskId;
|
||||
|
||||
useEffect(() => {
|
||||
teamNameRef.current = teamName;
|
||||
taskIdRef.current = taskId;
|
||||
}, [teamName, taskId]);
|
||||
|
||||
// Reset tracked state when team/task changes
|
||||
useEffect(() => {
|
||||
|
|
|
|||
|
|
@ -51,7 +51,10 @@ export function useViewportObserver({
|
|||
registerElement: (value: string) => (el: HTMLElement | null) => void;
|
||||
} {
|
||||
const onVisibleChangeRef = useRef(onVisibleChange);
|
||||
onVisibleChangeRef.current = onVisibleChange;
|
||||
|
||||
useEffect(() => {
|
||||
onVisibleChangeRef.current = onVisibleChange;
|
||||
}, [onVisibleChange]);
|
||||
|
||||
const observerRef = useRef<IntersectionObserver | null>(null);
|
||||
const visibleValuesRef = useRef<Set<string>>(new Set());
|
||||
|
|
@ -67,6 +70,9 @@ export function useViewportObserver({
|
|||
// and produce false positives for all visible elements.
|
||||
if (!root) return;
|
||||
|
||||
// Capture ref values for cleanup closure
|
||||
const visibleValues = visibleValuesRef.current;
|
||||
|
||||
const observer = new IntersectionObserver(
|
||||
(entries) => {
|
||||
let changed = false;
|
||||
|
|
@ -75,19 +81,19 @@ export function useViewportObserver({
|
|||
if (!value) continue;
|
||||
|
||||
if (entry.isIntersecting) {
|
||||
if (!visibleValuesRef.current.has(value)) {
|
||||
visibleValuesRef.current.add(value);
|
||||
if (!visibleValues.has(value)) {
|
||||
visibleValues.add(value);
|
||||
changed = true;
|
||||
}
|
||||
} else {
|
||||
if (visibleValuesRef.current.has(value)) {
|
||||
visibleValuesRef.current.delete(value);
|
||||
if (visibleValues.has(value)) {
|
||||
visibleValues.delete(value);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (changed) {
|
||||
onVisibleChangeRef.current(Array.from(visibleValuesRef.current));
|
||||
onVisibleChangeRef.current(Array.from(visibleValues));
|
||||
}
|
||||
},
|
||||
{ root, threshold }
|
||||
|
|
@ -105,7 +111,7 @@ export function useViewportObserver({
|
|||
return () => {
|
||||
observer.disconnect();
|
||||
observerRef.current = null;
|
||||
visibleValuesRef.current.clear();
|
||||
visibleValues.clear();
|
||||
};
|
||||
}, [root, threshold]);
|
||||
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ export function initSentryRenderer(): void {
|
|||
};
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- cross-version @sentry/core type mismatch
|
||||
const beforeSend = (event: any) => (telemetryAllowed ? event : null);
|
||||
const beforeSend = (event: any): any => (telemetryAllowed ? event : null);
|
||||
|
||||
if (window.electronAPI) {
|
||||
// Electron renderer — uses IPC transport to main process.
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ function storageKey(teamName: string): string {
|
|||
}
|
||||
|
||||
/** Legacy keys used by the old three-key approach. */
|
||||
function legacyKeys(teamName: string) {
|
||||
function legacyKeys(teamName: string): { text: string; chips: string; attachments: string } {
|
||||
return {
|
||||
text: `draft:compose:${teamName}`,
|
||||
chips: `draft:compose:${teamName}:chips`,
|
||||
|
|
|
|||
|
|
@ -695,7 +695,7 @@ export function initializeNotificationListeners(): () => void {
|
|||
updateStatus: 'available',
|
||||
availableVersion: s.version ?? null,
|
||||
releaseNotes: s.releaseNotes ?? null,
|
||||
showUpdateDialog: s.version !== dismissed,
|
||||
showUpdateDialog: (s.version ?? null) !== dismissed,
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import {
|
|||
MEMBER_COLOR_PALETTE,
|
||||
normalizeMemberColorName,
|
||||
} from '@shared/constants/memberColors';
|
||||
import { isLeadAgentType, isLeadMember } from '@shared/utils/leadDetection';
|
||||
import { isLeadMember } from '@shared/utils/leadDetection';
|
||||
|
||||
import type {
|
||||
LeadActivityState,
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
* (main: process.env, renderer: import.meta.env).
|
||||
*/
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention -- Vite `define` injects this global
|
||||
declare const __APP_VERSION__: string;
|
||||
|
||||
/** Release identifier injected at build time via Vite `define`. */
|
||||
|
|
|
|||
Loading…
Reference in a new issue