feat: Add mobile responsive layout, open room access, and admin room management

Mobile Responsive Layout:
- Add useMediaQuery, useIsMobile, useIsTablet, useIsDesktop hooks for device detection
- Create MobileHeader component with hamburger menu and action drawer
- Create BottomToolbar for mobile navigation (Files, Members)
- Create SlidePanel component for full-screen mobile sidebars
- Update RoomDetail.tsx with mobile/desktop conditional rendering
- Update RoomList.tsx with single-column grid and touch-friendly buttons
- Add CSS custom properties for safe areas and touch targets (min 44px)
- Add mobile viewport meta tags for notched devices

Open Room Access:
- All authenticated users can view all rooms (not just their own)
- Users can join active rooms they're not members of
- Add is_member field to room responses
- Update room list API to return all rooms by default

Admin Room Management:
- Add permanent delete functionality for system admins
- Add delete confirmation dialog with room title verification
- Broadcast room deletion via WebSocket to connected users
- Add users search API for adding members

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
egg
2025-12-05 09:12:10 +08:00
parent 1e44a63a8e
commit 1d5d4d447d
48 changed files with 3505 additions and 401 deletions

View File

@@ -0,0 +1,52 @@
"""User management API endpoints
Provides:
- GET /api/users/search - Search users by name or email
"""
from fastapi import APIRouter, Depends, HTTPException, status, Query
from sqlalchemy.orm import Session
from typing import List
from pydantic import BaseModel
from app.core.database import get_db
from app.modules.auth import get_current_user
from app.modules.auth.services.user_service import search_users
router = APIRouter(prefix="/api/users", tags=["Users"])
class UserSearchResult(BaseModel):
"""User search result"""
user_id: str
display_name: str
class Config:
from_attributes = True
@router.get("/search", response_model=List[UserSearchResult])
async def search_users_endpoint(
q: str = Query(..., min_length=1, description="Search query (name or email)"),
db: Session = Depends(get_db),
current_user: dict = Depends(get_current_user)
):
"""Search users by display_name or email
Returns up to 20 matching users. Requires authentication.
Search is case-insensitive and matches partial strings.
"""
if not q or len(q.strip()) == 0:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="Search query required"
)
users = search_users(db, q.strip(), limit=20)
return [
UserSearchResult(
user_id=user.user_id,
display_name=user.display_name
)
for user in users
]