Files
gamercomp/frontend/src/hooks/useFingerprint.js
T
2026-04-30 02:14:25 +00:00

78 lines
2.0 KiB
JavaScript

import { useState, useEffect } from 'react';
import FingerprintJS from '@fingerprintjs/fingerprintjs';
const FINGERPRINT_KEY = 'gamercomp_device_fp';
// Cache fingerprint in memory and localStorage
let cachedFingerprint = null;
export function useFingerprint() {
const [fingerprint, setFingerprint] = useState(() => {
// Try to get from memory cache first
if (cachedFingerprint) return cachedFingerprint;
// Then from localStorage
const stored = localStorage.getItem(FINGERPRINT_KEY);
if (stored) {
cachedFingerprint = stored;
return stored;
}
return null;
});
const [loading, setLoading] = useState(!fingerprint);
useEffect(() => {
if (fingerprint) {
setLoading(false);
return;
}
let cancelled = false;
async function generateFingerprint() {
try {
const fp = await FingerprintJS.load();
const result = await fp.get();
const visitorId = result.visitorId;
if (!cancelled) {
cachedFingerprint = visitorId;
localStorage.setItem(FINGERPRINT_KEY, visitorId);
setFingerprint(visitorId);
setLoading(false);
}
} catch (err) {
console.error('Failed to generate fingerprint:', err);
if (!cancelled) {
// Generate a fallback random ID
const fallback = 'fb_' + Math.random().toString(36).substring(2) + Date.now().toString(36);
cachedFingerprint = fallback;
localStorage.setItem(FINGERPRINT_KEY, fallback);
setFingerprint(fallback);
setLoading(false);
}
}
}
generateFingerprint();
return () => {
cancelled = true;
};
}, [fingerprint]);
return { fingerprint, loading };
}
// Sync getter for API client
export function getFingerprint() {
if (cachedFingerprint) return cachedFingerprint;
const stored = localStorage.getItem(FINGERPRINT_KEY);
if (stored) {
cachedFingerprint = stored;
return stored;
}
return null;
}
export default useFingerprint;