N-FIN-33: dialogs become drawer on small screens (#39)

Resolves #33
This commit is contained in:
Markus Thielker 2024-03-17 01:25:30 +01:00 committed by GitHub
commit 62d6290cf0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 169 additions and 62 deletions

View file

@ -23,6 +23,8 @@ import {
} from '@/components/ui/alert-dialog'; } from '@/components/ui/alert-dialog';
import { categoryFormSchema } from '@/lib/form-schemas/categoryFormSchema'; import { categoryFormSchema } from '@/lib/form-schemas/categoryFormSchema';
import CategoryForm from '@/components/form/categoryForm'; import CategoryForm from '@/components/form/categoryForm';
import { useMediaQuery } from '@/lib/hooks/useMediaQuery';
import { Drawer, DrawerContent, DrawerHeader, DrawerTitle, DrawerTrigger } from '@/components/ui/drawer';
export default function CategoryPageClientContent({categories, onSubmit, onDelete, className}: { export default function CategoryPageClientContent({categories, onSubmit, onDelete, className}: {
categories: Category[], categories: Category[],
@ -31,6 +33,7 @@ export default function CategoryPageClientContent({categories, onSubmit, onDelet
className: string, className: string,
}) { }) {
const isDesktop = useMediaQuery('(min-width: 768px)');
const router = useRouter(); const router = useRouter();
const [isEditDialogOpen, setIsEditDialogOpen] = useState(false); const [isEditDialogOpen, setIsEditDialogOpen] = useState(false);
@ -97,26 +100,51 @@ export default function CategoryPageClientContent({categories, onSubmit, onDelet
<p className="text-3xl font-semibold">Categories</p> <p className="text-3xl font-semibold">Categories</p>
{/* Edit dialog */} {/* Edit dialog */}
<Dialog open={isEditDialogOpen} onOpenChange={setIsEditDialogOpen}> {
<DialogTrigger asChild> isDesktop ? (
<Button <Dialog open={isEditDialogOpen} onOpenChange={setIsEditDialogOpen}>
onClick={() => { <DialogTrigger asChild>
setSelectedCategory(undefined); <Button
setIsEditDialogOpen(true); onClick={() => {
}}> setSelectedCategory(undefined);
Create Category setIsEditDialogOpen(true);
</Button> }}>
</DialogTrigger> Create Category
<DialogContent> </Button>
<DialogHeader> </DialogTrigger>
<DialogTitle>{selectedCategory?.id ? 'Update Category' : 'Create Category'}</DialogTitle> <DialogContent>
</DialogHeader> <DialogHeader>
<CategoryForm <DialogTitle>{selectedCategory?.id ? 'Update Category' : 'Create Category'}</DialogTitle>
value={selectedCategory} </DialogHeader>
onSubmit={handleSubmit} <CategoryForm
className="flex flex-row space-x-4 py-4"/> value={selectedCategory}
</DialogContent> onSubmit={handleSubmit}
</Dialog> className="flex flex-row space-x-4 py-4"/>
</DialogContent>
</Dialog>
) : (
<Drawer open={isEditDialogOpen} onOpenChange={setIsEditDialogOpen}>
<DrawerTrigger asChild>
<Button
onClick={() => {
setSelectedCategory(undefined);
setIsEditDialogOpen(true);
}}>
Create Category
</Button>
</DrawerTrigger>
<DrawerContent className="p-4">
<DrawerHeader>
<DrawerTitle>{selectedCategory?.id ? 'Update Category' : 'Create Category'}</DrawerTitle>
</DrawerHeader>
<CategoryForm
value={selectedCategory}
onSubmit={handleSubmit}
className="flex flex-row space-x-4 py-4"/>
</DrawerContent>
</Drawer>
)
}
</div> </div>
{/* Data Table */} {/* Data Table */}

View file

@ -24,6 +24,8 @@ import {
AlertDialogFooter, AlertDialogFooter,
AlertDialogHeader, AlertDialogHeader,
} from '@/components/ui/alert-dialog'; } from '@/components/ui/alert-dialog';
import { useMediaQuery } from '@/lib/hooks/useMediaQuery';
import { Drawer, DrawerContent, DrawerHeader, DrawerTitle, DrawerTrigger } from '@/components/ui/drawer';
export default function EntityPageClientContent({entities, onSubmit, onDelete, className}: { export default function EntityPageClientContent({entities, onSubmit, onDelete, className}: {
entities: Entity[], entities: Entity[],
@ -32,6 +34,7 @@ export default function EntityPageClientContent({entities, onSubmit, onDelete, c
className: string, className: string,
}) { }) {
const isDesktop = useMediaQuery('(min-width: 768px)');
const router = useRouter(); const router = useRouter();
const [isEditDialogOpen, setIsEditDialogOpen] = useState(false); const [isEditDialogOpen, setIsEditDialogOpen] = useState(false);
@ -125,26 +128,51 @@ export default function EntityPageClientContent({entities, onSubmit, onDelete, c
<p className="text-3xl font-semibold">Entities</p> <p className="text-3xl font-semibold">Entities</p>
{/* Edit dialog */} {/* Edit dialog */}
<Dialog open={isEditDialogOpen} onOpenChange={setIsEditDialogOpen}> {
<DialogTrigger asChild> isDesktop ? (
<Button <Dialog open={isEditDialogOpen} onOpenChange={setIsEditDialogOpen}>
onClick={() => { <DialogTrigger asChild>
setSelectedEntity(undefined); <Button
setIsEditDialogOpen(true); onClick={() => {
}}> setSelectedEntity(undefined);
Create Entity setIsEditDialogOpen(true);
</Button> }}>
</DialogTrigger> Create Entity
<DialogContent> </Button>
<DialogHeader> </DialogTrigger>
<DialogTitle>{selectedEntity?.id ? 'Update Entity' : 'Create Entity'}</DialogTitle> <DialogContent>
</DialogHeader> <DialogHeader>
<EntityForm <DialogTitle>{selectedEntity?.id ? 'Update Entity' : 'Create Entity'}</DialogTitle>
value={selectedEntity} </DialogHeader>
onSubmit={handleSubmit} <EntityForm
className="grid grid-cols-1 md:grid-cols-2 gap-4 py-4"/> value={selectedEntity}
</DialogContent> onSubmit={handleSubmit}
</Dialog> className="grid grid-cols-1 md:grid-cols-2 gap-4 py-4"/>
</DialogContent>
</Dialog>
) : (
<Drawer open={isEditDialogOpen} onOpenChange={setIsEditDialogOpen}>
<DrawerTrigger asChild>
<Button
onClick={() => {
setSelectedEntity(undefined);
setIsEditDialogOpen(true);
}}>
Create Entity
</Button>
</DrawerTrigger>
<DrawerContent className="p-4">
<DrawerHeader>
<DrawerTitle>{selectedEntity?.id ? 'Update Entity' : 'Create Entity'}</DrawerTitle>
</DrawerHeader>
<EntityForm
value={selectedEntity}
onSubmit={handleSubmit}
className="grid grid-cols-1 md:grid-cols-2 gap-4 py-4"/>
</DrawerContent>
</Drawer>
)
}
</div> </div>
{/* Filter input */} {/* Filter input */}

View file

@ -23,6 +23,8 @@ import { paymentFormSchema } from '@/lib/form-schemas/paymentFormSchema';
import { Category, Entity, Payment } from '@prisma/client'; import { Category, Entity, Payment } from '@prisma/client';
import PaymentForm from '@/components/form/paymentForm'; import PaymentForm from '@/components/form/paymentForm';
import { columns } from '@/app/payments/columns'; import { columns } from '@/app/payments/columns';
import { Drawer, DrawerContent, DrawerHeader, DrawerTitle, DrawerTrigger } from '@/components/ui/drawer';
import { useMediaQuery } from '@/lib/hooks/useMediaQuery';
export default function PaymentPageClientContent({ export default function PaymentPageClientContent({
payments, payments,
@ -40,6 +42,7 @@ export default function PaymentPageClientContent({
className: string, className: string,
}) { }) {
const isDesktop = useMediaQuery('(min-width: 768px)');
const router = useRouter(); const router = useRouter();
const [isEditDialogOpen, setIsEditDialogOpen] = useState(false); const [isEditDialogOpen, setIsEditDialogOpen] = useState(false);
@ -106,28 +109,55 @@ export default function PaymentPageClientContent({
<p className="text-3xl font-semibold">Payments</p> <p className="text-3xl font-semibold">Payments</p>
{/* Edit dialog */} {/* Edit dialog */}
<Dialog open={isEditDialogOpen} onOpenChange={setIsEditDialogOpen}> {
<DialogTrigger asChild> isDesktop ? (
<Button <Dialog open={isEditDialogOpen} onOpenChange={setIsEditDialogOpen}>
onClick={() => { <DialogTrigger asChild>
setSelectedPayment(undefined); <Button
setIsEditDialogOpen(true); onClick={() => {
}}> setSelectedPayment(undefined);
Create Payment setIsEditDialogOpen(true);
</Button> }}>
</DialogTrigger> Create Payment
<DialogContent> </Button>
<DialogHeader> </DialogTrigger>
<DialogTitle>{selectedPayment?.id ? 'Update Payment' : 'Create Payment'}</DialogTitle> <DialogContent>
</DialogHeader> <DialogHeader>
<PaymentForm <DialogTitle>{selectedPayment?.id ? 'Update Payment' : 'Create Payment'}</DialogTitle>
value={selectedPayment} </DialogHeader>
entities={entities} <PaymentForm
categories={categories} value={selectedPayment}
onSubmit={handleSubmit} entities={entities}
className="grid grid-cols-1 md:grid-cols-2 gap-4 py-4"/> categories={categories}
</DialogContent> onSubmit={handleSubmit}
</Dialog> className="grid grid-cols-1 md:grid-cols-2 gap-4 py-4"/>
</DialogContent>
</Dialog>
) : (
<Drawer open={isEditDialogOpen} onOpenChange={setIsEditDialogOpen}>
<DrawerTrigger asChild>
<Button
onClick={() => {
setSelectedPayment(undefined);
setIsEditDialogOpen(true);
}}>
Create Payment
</Button>
</DrawerTrigger>
<DrawerContent className="p-4">
<DrawerHeader>
<DrawerTitle>{selectedPayment?.id ? 'Update Payment' : 'Create Payment'}</DrawerTitle>
</DrawerHeader>
<PaymentForm
value={selectedPayment}
entities={entities}
categories={categories}
onSubmit={handleSubmit}
className="grid grid-cols-1 md:grid-cols-2 gap-4 py-4"/>
</DrawerContent>
</Drawer>
)
}
</div> </div>
{/* Data Table */} {/* Data Table */}

View file

@ -0,0 +1,21 @@
'use client';
import { useEffect, useState } from 'react';
export function useMediaQuery(mq: string) {
const [matches, setMatch] = useState(
() => typeof window !== 'undefined' ? window.matchMedia(mq).matches : false,
);
useEffect(() => {
if (typeof window !== 'undefined') {
const mql = window.matchMedia(mq);
const listener = (e: any) => setMatch(e.matches);
mql.addEventListener('change', listener);
return () => mql.removeEventListener('change', listener);
}
}, [mq]);
return matches;
}