Skip to content

Commit aac7949

Browse files
committed
optimize a bit
1 parent 53ca84c commit aac7949

File tree

1 file changed

+87
-104
lines changed

1 file changed

+87
-104
lines changed

frontend/src/components/profile-info-tooltip.tsx

Lines changed: 87 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -11,64 +11,68 @@ interface ProfileInfoTooltipProps {
1111
className?: string;
1212
}
1313

14-
function isValidProfileId(profileId: string): boolean {
15-
return typeof profileId === 'string' &&
16-
profileId.length > 0 &&
17-
profileId.length <= 64 &&
18-
/^[a-zA-Z0-9_\- ]+$/.test(profileId);
19-
}
20-
21-
22-
function getPortFromAdvanced(profile: LocalLoginProfile): string | null {
23-
const dbType = profile.Type;
24-
const defaultPortItem = databaseTypeDropdownItems.find(item => item.id === dbType);
14+
const PROFILE_ID_REGEX = /^[a-zA-Z0-9_\- ]+$/;
15+
const PROFILE_ID_MAX_LENGTH = 64;
16+
const TOOLTIP_OFFSET = 12;
17+
18+
const isValidProfileId = (profileId: string): boolean =>
19+
typeof profileId === 'string' &&
20+
profileId.length > 0 &&
21+
profileId.length <= PROFILE_ID_MAX_LENGTH &&
22+
PROFILE_ID_REGEX.test(profileId);
23+
24+
const getPortFromAdvanced = (profile: LocalLoginProfile): string | null => {
25+
const defaultPortItem = databaseTypeDropdownItems.find(item => item.id === profile.Type);
26+
const defaultPort = defaultPortItem?.extra?.Port;
2527

26-
if (!defaultPortItem?.extra?.Port) {
27-
return null;
28-
}
28+
if (!defaultPort) return null;
2929

30-
const defaultPort = defaultPortItem.extra.Port;
31-
3230
if (profile.Advanced) {
3331
const portObj = profile.Advanced.find(item => item.Key === 'Port');
3432
return portObj?.Value || defaultPort;
3533
}
3634

3735
return defaultPort;
38-
}
36+
};
3937

40-
function getLastAccessedTime(profileId: string): string | null {
41-
if (!isValidProfileId(profileId)) {
42-
return null;
43-
}
38+
const getLastAccessedTime = (profileId: string): string | null => {
39+
if (!isValidProfileId(profileId)) return null;
4440

4541
try {
4642
const lastAccessed = localStorage.getItem(`whodb_profile_last_accessed_${profileId}`);
47-
if (lastAccessed) {
48-
const date = new Date(lastAccessed);
49-
if (isNaN(date.getTime())) {
50-
return null;
51-
}
52-
const timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
53-
const formattedTimeZone = timeZone.replace(/_/g, ' ').split('/').join(' / ');
54-
return `${date.toLocaleDateString()} ${date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })} (${formattedTimeZone})`;
55-
}
56-
} catch (error) {
43+
if (!lastAccessed) return null;
44+
45+
const date = new Date(lastAccessed);
46+
if (isNaN(date.getTime())) return null;
47+
48+
const timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
49+
const formattedTimeZone = timeZone.replace(/_/g, ' ').split('/').join(' / ');
50+
return `${date.toLocaleDateString()} ${date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })} (${formattedTimeZone})`;
51+
} catch {
5752
return null;
5853
}
59-
return null;
60-
}
54+
};
6155

6256
let tooltipPortalContainer: HTMLDivElement | null = null;
6357

64-
function getTooltipPortalContainer(): HTMLDivElement {
58+
const getTooltipPortalContainer = (): HTMLDivElement => {
6559
if (!tooltipPortalContainer) {
6660
tooltipPortalContainer = document.createElement('div');
6761
tooltipPortalContainer.id = 'whodb-tooltip-portal';
6862
document.body.appendChild(tooltipPortalContainer);
6963
}
7064
return tooltipPortalContainer;
71-
}
65+
};
66+
67+
const TOOLTIP_CLASSES = {
68+
container: classNames(
69+
"fixed z-[9999] px-3 py-2 text-xs font-medium bg-white border border-gray-200 rounded-lg shadow-lg",
70+
"dark:bg-[#2C2F33] dark:border-white/20 dark:text-gray-200",
71+
"min-w-[180px]",
72+
"animate-fade"
73+
),
74+
button: "flex items-center justify-center w-4 h-4 text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200 focus:outline-none focus:ring-1 focus:ring-blue-400 focus:ring-offset-2 focus:ring-offset-gray-900 rounded-full transition-colors"
75+
};
7276

7377
export const ProfileInfoTooltip: FC<ProfileInfoTooltipProps> = ({ profile, className }) => {
7478
const [isVisible, setIsVisible] = useState(false);
@@ -78,33 +82,24 @@ export const ProfileInfoTooltip: FC<ProfileInfoTooltipProps> = ({ profile, class
7882
const port = getPortFromAdvanced(profile);
7983
const lastAccessed = getLastAccessedTime(profile.Id);
8084

81-
const hasInfo = port !== null || lastAccessed !== null;
82-
if (!hasInfo) {
83-
return null;
84-
}
85+
if (!port && !lastAccessed) return null;
8586

8687
const showTooltip = useCallback(() => {
87-
if (btnRef.current) {
88-
const rect = btnRef.current.getBoundingClientRect();
89-
setTooltipPos({
90-
top: rect.top + rect.height / 2,
91-
left: rect.right + 12,
92-
});
93-
}
88+
if (!btnRef.current) return;
89+
90+
const rect = btnRef.current.getBoundingClientRect();
91+
setTooltipPos({
92+
top: rect.top + rect.height / 2,
93+
left: rect.right + TOOLTIP_OFFSET,
94+
});
9495
setIsVisible(true);
9596
}, []);
9697

97-
const hideTooltip = useCallback(() => {
98-
setIsVisible(false);
99-
}, []);
98+
const hideTooltip = useCallback(() => setIsVisible(false), []);
10099

101100
const handleClickAway = useCallback((event: MouseEvent) => {
102-
if (
103-
btnRef.current &&
104-
!btnRef.current.contains(event.target as Node)
105-
) {
106-
setIsVisible(false);
107-
}
101+
if (btnRef.current?.contains(event.target as Node)) return;
102+
setIsVisible(false);
108103
}, []);
109104

110105
const handleKeyDown = useCallback((event: KeyboardEvent) => {
@@ -123,55 +118,45 @@ export const ProfileInfoTooltip: FC<ProfileInfoTooltipProps> = ({ profile, class
123118
};
124119
}, [isVisible, handleClickAway, handleKeyDown]);
125120

126-
const portalContainer = useMemo(() => getTooltipPortalContainer(), []);
127-
128-
const tooltip = isVisible && tooltipPos
129-
? createPortal(
130-
<div
131-
id={`tooltip-${profile.Id}`}
132-
role="tooltip"
133-
className={classNames(
134-
"fixed z-[9999] px-3 py-2 text-xs font-medium bg-white border border-gray-200 rounded-lg shadow-lg",
135-
"dark:bg-[#2C2F33] dark:border-white/20 dark:text-gray-200",
136-
"min-w-[180px]",
137-
"animate-fade"
138-
)}
139-
style={{
140-
top: tooltipPos.top,
141-
left: tooltipPos.left,
142-
transform: "translateY(-50%)",
143-
}}
144-
>
145-
<div className="space-y-1">
146-
{port !== null && (
147-
<div className="flex justify-between">
148-
<span className="text-gray-600 dark:text-gray-400">Port:</span>
149-
<span className={ClassNames.Text}>{port}</span>
150-
</div>
151-
)}
152-
{lastAccessed !== null && (
153-
<div className="flex justify-between">
154-
<span className="text-gray-600 dark:text-gray-400">Last Logged In:&nbsp;</span>
155-
<span className={ClassNames.Text}>{lastAccessed}</span>
156-
</div>
157-
)}
121+
const portalContainer = useMemo(getTooltipPortalContainer, []);
122+
123+
const tooltip = isVisible && tooltipPos && createPortal(
124+
<div
125+
id={`tooltip-${profile.Id}`}
126+
role="tooltip"
127+
className={TOOLTIP_CLASSES.container}
128+
style={{
129+
top: tooltipPos.top,
130+
left: tooltipPos.left,
131+
transform: "translateY(-50%)",
132+
}}
133+
>
134+
<div className="space-y-1">
135+
{port && (
136+
<div className="flex justify-between">
137+
<span className="text-gray-600 dark:text-gray-400">Port:</span>
138+
<span className={ClassNames.Text}>{port}</span>
158139
</div>
159-
<div
160-
className="absolute top-1/2 left-0 -translate-x-full -translate-y-1/2"
161-
style={{}}
162-
>
163-
<div className="w-0 h-0 border-t-4 border-b-4 border-r-4 border-t-transparent border-b-transparent border-r-gray-200 dark:border-r-white/20"></div>
140+
)}
141+
{lastAccessed && (
142+
<div className="flex justify-between">
143+
<span className="text-gray-600 dark:text-gray-400">Last Logged In:&nbsp;</span>
144+
<span className={ClassNames.Text}>{lastAccessed}</span>
164145
</div>
165-
</div>,
166-
portalContainer
167-
)
168-
: null;
146+
)}
147+
</div>
148+
<div className="absolute top-1/2 left-0 -translate-x-full -translate-y-1/2">
149+
<div className="w-0 h-0 border-t-4 border-b-4 border-r-4 border-t-transparent border-b-transparent border-r-gray-200 dark:border-r-white/20" />
150+
</div>
151+
</div>,
152+
portalContainer
153+
);
169154

170155
return (
171156
<div className={classNames("relative", className)}>
172157
<button
173158
ref={btnRef}
174-
className="flex items-center justify-center w-4 h-4 text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200 focus:outline-none focus:ring-1 focus:ring-blue-400 focus:ring-offset-2 focus:ring-offset-gray-900 rounded-full transition-colors"
159+
className={TOOLTIP_CLASSES.button}
175160
onClick={isVisible ? hideTooltip : showTooltip}
176161
aria-label={`Profile information for ${profile.Id}`}
177162
aria-describedby={`tooltip-${profile.Id}`}
@@ -185,14 +170,12 @@ export const ProfileInfoTooltip: FC<ProfileInfoTooltipProps> = ({ profile, class
185170
);
186171
};
187172

188-
export function updateProfileLastAccessed(profileId: string): void {
189-
if (!isValidProfileId(profileId)) {
190-
return;
191-
}
173+
export const updateProfileLastAccessed = (profileId: string): void => {
174+
if (!isValidProfileId(profileId)) return;
192175

193176
try {
194177
localStorage.setItem(`whodb_profile_last_accessed_${profileId}`, new Date().toISOString());
195-
} catch (error) {
196-
178+
} catch {
179+
// Silently fail if localStorage is not available
197180
}
198-
}
181+
};

0 commit comments

Comments
 (0)