fix: four bugs in referrals tab from review

- Commission display: use conditional instead of nullish coalescing
  to avoid rendering "default%" (now shows "default" without %)
- loadReferrals: add || [] guard on data.users to prevent crash
- Search debounce: add cancelled flag to prevent stale responses
  overwriting fresher results
- Search dropdown: add loading state to prevent "No users found"
  flash during debounce wait
This commit is contained in:
Fringg
2026-03-29 03:49:49 +03:00
parent e32663f291
commit 63f7fa0a31

View File

@@ -313,6 +313,7 @@ export default function AdminUserDetail() {
const [referrerSearchQuery, setReferrerSearchQuery] = useState(''); const [referrerSearchQuery, setReferrerSearchQuery] = useState('');
const [showReferrerSearch, setShowReferrerSearch] = useState(false); const [showReferrerSearch, setShowReferrerSearch] = useState(false);
const [referrerSearchResults, setReferrerSearchResults] = useState<UserListItem[]>([]); const [referrerSearchResults, setReferrerSearchResults] = useState<UserListItem[]>([]);
const [referrerSearchLoading, setReferrerSearchLoading] = useState(false);
const referrerSearchRef = useRef<HTMLDivElement>(null); const referrerSearchRef = useRef<HTMLDivElement>(null);
// Panel info & node usage // Panel info & node usage
@@ -443,7 +444,7 @@ export default function AdminUserDetail() {
try { try {
setReferralsLoading(true); setReferralsLoading(true);
const data = await adminUsersApi.getReferrals(userId, 0, 50); const data = await adminUsersApi.getReferrals(userId, 0, 50);
setReferrals(data.users); setReferrals(data.users || []);
} catch { } catch {
} finally { } finally {
setReferralsLoading(false); setReferralsLoading(false);
@@ -953,17 +954,29 @@ export default function AdminUserDetail() {
useEffect(() => { useEffect(() => {
if (referrerSearchQuery.length < 2 || !showReferrerSearch) { if (referrerSearchQuery.length < 2 || !showReferrerSearch) {
setReferrerSearchResults([]); setReferrerSearchResults([]);
setReferrerSearchLoading(false);
return; return;
} }
setReferrerSearchLoading(true);
let cancelled = false;
const timer = setTimeout(async () => { const timer = setTimeout(async () => {
try { try {
const data = await adminUsersApi.getUsers({ search: referrerSearchQuery, limit: 10 }); const data = await adminUsersApi.getUsers({ search: referrerSearchQuery, limit: 10 });
setReferrerSearchResults(data.users || []); if (!cancelled) {
setReferrerSearchResults(data.users || []);
setReferrerSearchLoading(false);
}
} catch { } catch {
setReferrerSearchResults([]); if (!cancelled) {
setReferrerSearchResults([]);
setReferrerSearchLoading(false);
}
} }
}, 300); }, 300);
return () => clearTimeout(timer); return () => {
cancelled = true;
clearTimeout(timer);
};
}, [referrerSearchQuery, showReferrerSearch]); }, [referrerSearchQuery, showReferrerSearch]);
// Referrals tab: close search dropdown on click outside // Referrals tab: close search dropdown on click outside
@@ -3064,11 +3077,13 @@ export default function AdminUserDetail() {
)} )}
</div> </div>
)} )}
{referrerSearchQuery.length >= 2 && referrerSearchResults.length === 0 && ( {referrerSearchQuery.length >= 2 &&
<div className="absolute left-0 right-0 top-full z-50 mt-1 rounded-xl border border-dark-700 bg-dark-800 py-4 text-center text-sm text-dark-500 shadow-xl"> !referrerSearchLoading &&
{t('admin.users.detail.referrals.noUsersFound')} referrerSearchResults.length === 0 && (
</div> <div className="absolute left-0 right-0 top-full z-50 mt-1 rounded-xl border border-dark-700 bg-dark-800 py-4 text-center text-sm text-dark-500 shadow-xl">
)} {t('admin.users.detail.referrals.noUsersFound')}
</div>
)}
</div> </div>
) : ( ) : (
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
@@ -3110,7 +3125,9 @@ export default function AdminUserDetail() {
{t('admin.users.detail.referrals.commission')} {t('admin.users.detail.referrals.commission')}
</div> </div>
<div className="mt-1 text-xl font-bold text-dark-100"> <div className="mt-1 text-xl font-bold text-dark-100">
{user.referral.commission_percent ?? t('admin.users.detail.referrals.default')}% {user.referral.commission_percent != null
? `${user.referral.commission_percent}%`
: t('admin.users.detail.referrals.default')}
</div> </div>
</div> </div>
<div className="rounded-xl bg-dark-800/40 p-4"> <div className="rounded-xl bg-dark-800/40 p-4">