Files
paperlessmanager/paperless-frontend/src/components/DocumentSearchModal.tsx
T
bjoernpoettker 7076eef57b
Build and Push Multi-Platform Images / build-and-push (push) Successful in 39s
feat: add mobile-responsive layout and card views across all pages
- New useIsMobile hook and MobileCardList component
- AppLayout: hamburger menu + Drawer navigation on mobile
- All list pages (Inbox, Posteingang, Manuell, Mail, Freigabe, Zahlung, TaskLog)
  show card layout on mobile instead of tables
- CSS: responsive modal height, horizontal table scroll, text-size-adjust
- Backend: Agrarmonitor polling fixes, Zahlung service improvements,
  IMAP folder service extended, misc controller fixes

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-14 09:22:58 +02:00

125 lines
3.6 KiB
TypeScript

import { useState, useCallback, useEffect } from 'react';
import { Modal, Input, List, Typography, Space, Pagination, Spin, Button } from 'antd';
import { SearchOutlined, CheckOutlined } from '@ant-design/icons';
import { paperlessApi } from '../api/paperless';
import { getEnv } from '../utils/env';
import { AuthImage } from '../utils/auth-resource';
import dayjs from 'dayjs';
const { Text } = Typography;
interface Props {
open: boolean;
onCancel: () => void;
onSelect: (doc: any) => void;
}
export default function DocumentSearchModal({ open, onCancel, onSelect }: Props) {
const [loading, setLoading] = useState(false);
const [search, setSearch] = useState('');
const [data, setData] = useState<any[]>([]);
const [total, setTotal] = useState(0);
const [page, setPage] = useState(1);
const [pageSize] = useState(10);
const load = useCallback(async (q: string, p: number) => {
setLoading(true);
try {
const response = await paperlessApi.searchDocuments({
search: q,
page: p,
pageSize: pageSize,
});
setData(response.results);
setTotal(response.count);
} catch (e) {
console.error("Error searching documents", e);
} finally {
setLoading(false);
}
}, [pageSize]);
useEffect(() => {
if (open) {
load(search, page);
}
}, [open, page, load]); // We don't trigger on search immediately to allow 'Search' button or Enter
const handleSearch = (val: string) => {
setSearch(val);
setPage(1);
load(val, 1);
};
return (
<Modal
title="Dokument suchen"
open={open}
onCancel={onCancel}
footer={null}
width={{ xs: '100vw', md: 800 }}
style={{ top: 50 }}
>
<div style={{ marginBottom: 16 }}>
<Input.Search
placeholder="Titel oder Inhalt suchen..."
enterButton={<SearchOutlined />}
onSearch={handleSearch}
loading={loading}
allowClear
/>
</div>
<Spin spinning={loading}>
<List
itemLayout="horizontal"
dataSource={data}
renderItem={(doc) => (
<List.Item
actions={[
<Button
key="select"
type="primary"
icon={<CheckOutlined />}
onClick={() => onSelect(doc)}
>
Auswählen
</Button>
]}
>
<List.Item.Meta
avatar={
<AuthImage
src={`${getEnv('VITE_API_URL')}/api/paperless/inbox/preview/${doc.id}`}
width={80}
height={110}
style={{ objectFit: 'cover', borderRadius: 4, border: '1px solid #f0f0f0' }}
/>
}
title={doc.title}
description={
<Space direction="vertical" size={0}>
<Text type="secondary" style={{ fontSize: 12 }}>ID: {doc.id} | ASN: {doc.archive_serial_number || 'Keine'}</Text>
<Text type="secondary" style={{ fontSize: 12 }}>Erstellt: {dayjs(doc.created).format('DD.MM.YYYY')}</Text>
</Space>
}
/>
</List.Item>
)}
/>
{total > pageSize && (
<div style={{ marginTop: 16, textAlign: 'right' }}>
<Pagination
current={page}
pageSize={pageSize}
total={total}
onChange={(p) => setPage(p)}
size="small"
/>
</div>
)}
</Spin>
</Modal>
);
}