feat: add mobile-responsive layout and card views across all pages
Build and Push Multi-Platform Images / build-and-push (push) Successful in 39s

- 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>
This commit is contained in:
bjoernpoettkerandClaude Sonnet 4.6 committed 2026-07-14 09:22:58 +02:00
1 parent 0765d14d3b
commit 7076eef57b
28 files changed
+1081 -462

No files matched your search

@@ -3,14 +3,17 @@ import { Table, Popover, Button, Space, message, Tooltip, Typography } from 'ant
import { AuthImage } from '../utils/auth-resource';
import { ReloadOutlined } from '@ant-design/icons';
const { Title } = Typography;
const { Title, Text } = Typography;
import dayjs from 'dayjs';
import { posteingangApi } from '../api/posteingang';
import type { PosteingangDocument } from '../api/posteingang';
import DocumentEditModal from '../components/DocumentEditModal';
import { getEnv } from '../utils/env';
import { useIsMobile } from '../hooks/useIsMobile';
import MobileCardList from '../components/MobileCardList';
export default function PosteingangPage() {
const isMobile = useIsMobile();
const [data, setData] = useState<PosteingangDocument[]>([]);
const [loading, setLoading] = useState(false);
const [editModalOpen, setEditModalOpen] = useState(false);
@@ -64,6 +67,11 @@ export default function PosteingangPage() {
/>
);
const getEingangsdatum = (record: PosteingangDocument) => {
const cf = record.customFields?.find((f) => f.field === 9);
return cf?.value ? dayjs(cf.value).format('DD.MM.YYYY') : '-';
};
const columns = [
{
title: 'Vorschau',
@@ -88,10 +96,7 @@ export default function PosteingangPage() {
{
title: 'Eingangsdatum',
key: 'eingangsdatum',
render: (_: any, record: PosteingangDocument) => {
const cf = record.customFields?.find((f) => f.field === 9);
return cf?.value ? dayjs(cf.value).format('DD.MM.YYYY') : '-';
}
render: (_: any, record: PosteingangDocument) => getEingangsdatum(record),
},
{
title: 'Importiert am',
@@ -121,14 +126,46 @@ export default function PosteingangPage() {
</Tooltip>
</Space>
</div>
<Table
columns={columns}
dataSource={data}
rowKey="id"
loading={loading}
pagination={{ pageSize: 20, showSizeChanger: true, showTotal: (t) => `${t} Dokumente` }}
locale={{ emptyText: 'Keine Einträge vorhanden' }}
/>
{isMobile ? (
<MobileCardList<PosteingangDocument>
dataSource={data}
rowKey="id"
loading={loading}
pagination={{ pageSize: 20, showTotal: (t) => `${t} Dokumente` }}
renderCard={(record) => (
<div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
<div style={{ display: 'flex', gap: 12 }}>
<AuthImage
src={`${getEnv('VITE_API_URL')}/api/paperless/inbox/preview/${record.id}`}
width={72}
style={{ border: '1px solid #d9d9d9', objectFit: 'contain', flexShrink: 0 }}
/>
<div style={{ display: 'flex', flexDirection: 'column', gap: 4, minWidth: 0 }}>
<Text strong>{record.title || '—'}</Text>
<Text type="secondary" style={{ fontSize: 13 }}>
Eingangsdatum: {getEingangsdatum(record)}
</Text>
<Text type="secondary" style={{ fontSize: 13 }}>
Importiert am: {dayjs(record.added).format('DD.MM.YYYY HH:mm')}
</Text>
</div>
</div>
<Button type="primary" block onClick={() => handleEdit(record)}>
Bearbeiten
</Button>
</div>
)}
/>
) : (
<Table
columns={columns}
dataSource={data}
rowKey="id"
loading={loading}
pagination={{ pageSize: 20, showSizeChanger: true, showTotal: (t) => `${t} Dokumente` }}
locale={{ emptyText: 'Keine Einträge vorhanden' }}
/>
)}
<DocumentEditModal
documentId={selectedDoc?.id || null}