94 lines
4.8 KiB
Markdown
94 lines
4.8 KiB
Markdown
# To AI Agent: Fix Mobile Dropdown Displacement and Eliminate `.filter` Array Runtime Crashes
|
|
|
|
## 1. Context & Identified Bugs
|
|
During Android Simulator testing, the frontend app encounters three critical layout and runtime execution failures:
|
|
1. **Dropdown Menu Displacement:** The profile/avatar menu container gets forced down to the extreme bottom of the viewport instead of floating as an absolute element directly beneath the user's top-bar avatar anchor.
|
|
2. **`Uncaught TypeError: g.filter is not a function`:** Triggering the Friend List components crashes the interface into a blank white screen.
|
|
3. **`Error fetching connections: TypeError: (intermediate value).filter is not a function`:** Opening the Live Chat view crashes identical array loops.
|
|
- *Root Cause for 2 & 3:* The API response payload from the backend server is **not returning a clean primitive Array**. It returns an object wrapper (e.g., `{ success: true, data: [...] }`) or `undefined`/`null` due to connection timing gaps. Invoking `.filter()` on a non-array instantly kills the React rendering thread.
|
|
|
|
---
|
|
|
|
## 2. Refactoring Blueprint
|
|
|
|
### Step 1: Fix Dropdown Positioning Context (`MapProfileDropdown.tsx`)
|
|
On desktop, absolute drop panels function normally. However, on mobile viewports or custom wrappers, they lose anchoring. We must force the container component to lock its coordinate space relative to the top bar element using modern CSS constraints:
|
|
|
|
```jsx
|
|
{/* ✅ RESPONSIVE REFACTOR: Force absolute rendering locked beneath the profile button context */}
|
|
<div
|
|
className="absolute right-0 top-14 w-[280px] bg-slate-900/95 backdrop-blur-md border border-slate-800 rounded-2xl p-2 shadow-2xl flex flex-col space-y-0.5 text-xs text-slate-200 z-[999999]"
|
|
style={{
|
|
maxHeight: '75vh',
|
|
overflowY: 'auto',
|
|
boxShadow: '0 20px 25px -5px rgba(0, 0, 0, 0.6)'
|
|
}}
|
|
>
|
|
{/* Menu option items: Tạo tour, Hành trình của tôi, Thư viện ảnh... */}
|
|
</div>
|
|
|
|
### Step 2: Enforce Defensive Array Check on Friend List Loop (FriendsManagerModal.tsx)
|
|
Locate where the system handles friend collections. Implement an explicit array layout typecheck validation using Array.isArray() before doing any mutation logic:
|
|
|
|
// ❌ OLD ERROR-PRONE PATTERN:
|
|
// const activeFriends = data.filter(f => f.status === 'active');
|
|
|
|
// ✅ NEW IMPERATIVE PROTECTION:
|
|
const [friendsList, setFriendsList] = useState<any[]>([]);
|
|
|
|
useEffect(() => {
|
|
api.get('/friends/connections')
|
|
.then((res) => {
|
|
const payload = res.data;
|
|
|
|
// Defensively parse and normalize the input shape
|
|
if (payload && Array.isArray(payload)) {
|
|
setFriendsList(payload);
|
|
} else if (payload && Array.isArray(payload.data)) {
|
|
setFriendsList(payload.data); // Support nested response architectures safely
|
|
} else {
|
|
console.error("⚠️ Backend returned non-array structure:", payload);
|
|
setFriendsList([]); // Default fallback to shield downstream loops
|
|
}
|
|
})
|
|
.catch((err) => {
|
|
console.error("Error reading friends list data stream:", err);
|
|
setFriendsList([]);
|
|
});
|
|
}, []);
|
|
|
|
// Safely filter verified arrays exclusively
|
|
const activeFriends = Array.isArray(friendsList)
|
|
? friendsList.filter((f: any) => f && f.status === 'active')
|
|
: [];
|
|
|
|
### Step 3: Secure Live Chat Target Connections Handler (LiveChatModal.tsx)
|
|
Apply the exact same defensive architecture inside your real-time chat sync queries or global context connection monitors:
|
|
|
|
const fetchUserConnections = async () => {
|
|
try {
|
|
const response = await api.get('/chat/connections');
|
|
const responseBody = response.data;
|
|
|
|
// Check array schema context explicitly
|
|
const verifiedConnections = Array.isArray(responseBody)
|
|
? responseBody
|
|
: (responseBody && Array.isArray(responseBody.connections) ? responseBody.connections : []);
|
|
|
|
/* ✅ CRITICAL SEPARATION: Running filter only on verified array collections */
|
|
const onlineConnections = verifiedConnections.filter((conn: any) => conn && conn.isOnline === true);
|
|
|
|
setConnections(verifiedConnections);
|
|
|
|
} catch (error) {
|
|
console.error("[LiveChatModal] Runtime error fetching message feeds intercepted gracefully:", error);
|
|
setConnections([]); // Initialize to fallback empty context
|
|
}
|
|
};
|
|
|
|
## 3. Automated Verification Checklist for AI Agent
|
|
[ ] Dropdown Anchor Alignment: Confirm the avatar profile drawer panel renders right under the top-bar avatar, leaving the bottom interaction tools untouched.
|
|
|
|
[ ] White Screen Eradication: Mock an empty server exception response (500 Internal Error). Verify the client component stays functional, logs the incident, and updates the empty UI state without crashing.
|
|
|
|
[ ] Global Code Polish Check: Scan the repository to ensure no raw .filter() methods are executed directly against fetched network streams without preceding type guards. |