feat(pwa): better PWA detection

This commit is contained in:
aaldebs99 2025-12-12 00:36:42 +00:00
parent 0df61038a8
commit 3a18e17ece
2 changed files with 63 additions and 22 deletions

View File

@ -46,6 +46,8 @@ import GlobalSearchBar from '../GlobalSearchBar';
import ThemeToggle from '../ThemeToggle/ThemeToggle';
import NotificationPanel from '../Notifications/NotificationPanel';
import LanguageSwitcher from '../LanguageSwitcher';
import BottomNavigation from './BottomNavigation';
import { usePWA } from '../../hooks/usePWA';
import { useTranslation } from 'react-i18next';
const drawerWidth = 280;
@ -80,6 +82,7 @@ const getNavigationItems = (t: (key: string) => string): NavigationItem[] => [
const AppLayout: React.FC<AppLayoutProps> = ({ children }) => {
const theme = useMuiTheme();
const isMobile = useMediaQuery(theme.breakpoints.down('md'));
const isPWA = usePWA();
const [mobileOpen, setMobileOpen] = useState<boolean>(false);
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
const [notificationAnchorEl, setNotificationAnchorEl] = useState<null | HTMLElement>(null);
@ -660,7 +663,11 @@ const AppLayout: React.FC<AppLayoutProps> = ({ children }) => {
}}
>
<Toolbar />
<Box sx={{ p: 3 }}>
<Box sx={{
p: 3,
// Add bottom padding when bottom nav is visible (PWA mode on mobile)
pb: isPWA && isMobile ? 'calc(64px + 24px + env(safe-area-inset-bottom, 0px))' : 3,
}}>
{children}
</Box>
</Box>
@ -670,6 +677,9 @@ const AppLayout: React.FC<AppLayoutProps> = ({ children }) => {
anchorEl={notificationAnchorEl}
onClose={handleNotificationClose}
/>
{/* Bottom Navigation (PWA only) */}
<BottomNavigation />
</Box>
);
};

View File

@ -1,4 +1,4 @@
import React, { useState, useEffect } from 'react';
import React, { useState, useEffect, useCallback, useRef } from 'react';
import { useNavigate } from 'react-router-dom';
import { useTranslation } from 'react-i18next';
import {
@ -108,6 +108,7 @@ const DocumentsPage: React.FC = () => {
const [error, setError] = useState<string | null>(null);
const [viewMode, setViewMode] = useState<ViewMode>('grid');
const [searchQuery, setSearchQuery] = useState<string>('');
const [debouncedSearchQuery, setDebouncedSearchQuery] = useState<string>('');
const [sortBy, setSortBy] = useState<SortField>('created_at');
const [sortOrder, setSortOrder] = useState<SortOrder>('desc');
const [ocrFilter, setOcrFilter] = useState<string>('');
@ -140,16 +141,48 @@ const DocumentsPage: React.FC = () => {
const [retryHistoryModalOpen, setRetryHistoryModalOpen] = useState<boolean>(false);
const [selectedDocumentForHistory, setSelectedDocumentForHistory] = useState<string | null>(null);
// Debounce search query to avoid making too many requests
useEffect(() => {
const timer = setTimeout(() => {
setDebouncedSearchQuery(searchQuery);
// Reset to first page when search query changes
if (searchQuery !== debouncedSearchQuery) {
setPagination(prev => ({ ...prev, offset: 0 }));
}
}, 300); // 300ms debounce delay
return () => clearTimeout(timer);
}, [searchQuery]);
useEffect(() => {
fetchDocuments();
fetchLabels();
}, [pagination?.limit, pagination?.offset, ocrFilter]);
}, [pagination?.limit, pagination?.offset, ocrFilter, debouncedSearchQuery]);
const fetchDocuments = async (): Promise<void> => {
if (!pagination) return;
try {
setLoading(true);
// If there's a search query, use the search API to search all documents
if (debouncedSearchQuery.trim()) {
const response = await documentService.enhancedSearch({
query: debouncedSearchQuery.trim(),
limit: pagination.limit,
offset: pagination.offset,
include_snippets: false,
});
setDocuments(response.data.documents || []);
setPagination({
total: response.data.total || 0,
limit: pagination.limit,
offset: pagination.offset,
has_more: (pagination.offset + pagination.limit) < (response.data.total || 0)
});
} else {
// Otherwise, use normal pagination to list recent documents
const response = await documentService.listWithPagination(
pagination.limit,
pagination.offset,
@ -158,6 +191,7 @@ const DocumentsPage: React.FC = () => {
// Backend returns wrapped object with documents and pagination
setDocuments(response.data.documents || []);
setPagination(response.data.pagination || { total: 0, limit: 20, offset: 0, has_more: false });
}
} catch (err) {
setError(t('common.status.error'));
console.error(err);
@ -263,12 +297,9 @@ const DocumentsPage: React.FC = () => {
});
};
const filteredDocuments = (documents || []).filter(doc =>
doc.original_filename.toLowerCase().includes(searchQuery.toLowerCase()) ||
doc.tags.some(tag => tag.toLowerCase().includes(searchQuery.toLowerCase()))
);
const sortedDocuments = [...filteredDocuments].sort((a, b) => {
// No need for client-side filtering anymore - search is done on the server
// When searchQuery is set, documents are already filtered by the server-side search API
const sortedDocuments = [...(documents || [])].sort((a, b) => {
let aValue: any = a[sortBy];
let bValue: any = b[sortBy];