Commit 40356211 authored by Mahmoud Aglan's avatar Mahmoud Aglan

fix: friends tab navigation + full friends system upgrade

- Fix: clicking friends tab now always shows friends scene (not
  notifications). Tab click resets to root when already active.
- Friends list: sorted online-first, shows count, retry on error
- Pending requests: fetches requester profiles (name, avatar, level)
  instead of showing raw UUIDs
- Search: searches both username and display_name, debounced input
- Online tab: auto-refreshes every 15s
- Activity feed: timeAgo formatting, action icons
- API: added 'profiles' action for batch profile lookups, search
  now matches display_name too
Co-Authored-By: 's avatarClaude Opus 4.6 <noreply@anthropic.com>
parent d2ec1d78
......@@ -62,14 +62,25 @@ if ($method === 'GET') {
if (strlen($query) < 2) jsonError('Query too short');
$results = $db->get('profiles', [
'username' => 'ilike.*' . $query . '*',
'or' => "(username.ilike.*{$query}*,display_name.ilike.*{$query}*)",
'id' => 'neq.' . $userId,
'select' => 'id,username,display_name,avatar_url,level,is_online',
'limit' => 10
'limit' => 15
]);
jsonResponse(['players' => is_array($results) && !isset($results['error']) ? $results : []]);
}
if ($action === 'profiles') {
$ids = $_GET['ids'] ?? '';
if (!$ids) jsonResponse(['profiles' => []]);
$idList = implode(',', array_map('trim', explode(',', $ids)));
$profiles = $db->get('profiles', [
'id' => "in.({$idList})",
'select' => 'id,username,display_name,avatar_url,level,is_online'
]);
jsonResponse(['profiles' => is_array($profiles) && !isset($profiles['error']) ? $profiles : []]);
}
}
if ($method === 'POST') {
......
......@@ -98,7 +98,8 @@ function renderTabBar() {
const item = e.target.closest('.tab-item');
if (!item) return;
const world = item.dataset.world;
scene.switchWorld(world);
const isAlreadyActive = item.classList.contains('active');
scene.switchWorld(world, isAlreadyActive);
});
document.body.appendChild(tabBar);
......
......@@ -26,15 +26,19 @@ export function register(id, mountFn, unmountFn) {
sceneRegistry[id] = { mount: mountFn, unmount: unmountFn };
}
export function switchWorld(world) {
if (!worlds.includes(world) || world === currentWorld) return;
export function switchWorld(world, resetToRoot = false) {
if (!worlds.includes(world)) return;
if (world === currentWorld && !resetToRoot) return;
const prev = currentWorld;
currentWorld = world;
store.set('activeWorld', world);
bus.emit('world:changed', { from: prev, to: world });
const stack = sceneStacks[world];
if (stack.length > 0) {
if (resetToRoot && stack.length > 1) {
sceneStacks[world] = [stack[0]];
renderScene(stack[0]);
} else if (stack.length > 0) {
renderScene(stack[stack.length - 1]);
}
}
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment