chore: add all the code from original repo

This commit is contained in:
Riccardo
2024-05-23 16:55:29 +02:00
parent d8f9a215eb
commit 85d66215a7
66 changed files with 16668 additions and 122 deletions

View File

@@ -0,0 +1,202 @@
import { ProfilesAction } from '@/components/Settings/Profiles/actions/ProfilesAction';
import { ProfileContext } from '@/contexts/ProfileContext';
import {
Box,
Button,
MenuItem,
Paper,
Select,
SelectChangeEvent,
Stack,
Table,
TableBody,
TableCell,
TableHead,
TableRow
} from '@mui/material';
import { nanoid } from 'nanoid';
import { useCallback, useContext, useEffect, useRef, useState } from 'react';
import { Item, Items, Profiles } from '../../../../data/types';
import CreateItemDialog from '../CreateItem/CreateItemDialog';
import ItemDialog from '../ItemDialog/ItemDialog';
import { ItemsTableAction } from './actions/ItemsTableAction';
import ItemsTableRow from './ItemsTableRow';
export default function ItemsTable() {
const [items, setItems] = useState<Items>([]);
const [take, setTake] = useState<number>(20);
const tableRef = useRef<HTMLDivElement>(null);
const [openCreateDialog, setOpenCreateDialog] = useState(false);
const [openItemDialog, setOpenItemDialog] = useState(false);
const [formKey, setFormKey] = useState(() => nanoid());
const [profiles, setProfiles] = useState<Profiles>([]);
const { profile, setProfile } = useContext(ProfileContext);
const [currentItem, setCurrentItem] = useState<Item | null>(null);
const handleUpdateProfiles = useCallback(async () => {
const updatedProfiles = await ProfilesAction();
setProfiles(updatedProfiles);
}, []);
useEffect(() => {
handleUpdateProfiles();
}, [handleUpdateProfiles]);
const handleUpdateItems = useCallback(
async (id: string) => {
try {
const updatedItems = await ItemsTableAction({
take,
profile: id
});
setItems(updatedItems);
} catch (error) {
console.error("Couldn't fetch items.");
}
},
[take]
);
const handleFetchItems = useCallback(
(event: SelectChangeEvent<string>) => {
handleUpdateItems(event.target.value);
setFormKey(nanoid());
setProfile(event.target.value);
},
[handleUpdateItems, setProfile]
);
useEffect(() => {
if (profile) {
handleUpdateItems(profile);
setFormKey(nanoid());
}
}, [profile, handleUpdateItems]);
useEffect(() => {
const handleScroll = (event: Event) => {
const target = event.target as HTMLDivElement;
const bottom =
target.scrollHeight - target.scrollTop === target.clientHeight;
if (bottom) {
setTake((prevTake) => prevTake + 20);
}
};
const tableElement = tableRef.current;
if (tableElement) {
tableElement.addEventListener('scroll', handleScroll);
return () => {
tableElement.removeEventListener('scroll', handleScroll);
};
}
}, [take]);
const handleCreateItemDialog = () => {
setOpenCreateDialog(true);
};
const handleCloseCreateDialog = async (created: boolean) => {
setFormKey(nanoid());
setOpenCreateDialog(false);
if (created) {
const updatedItems = await ItemsTableAction({
take,
profile
});
setItems(updatedItems);
}
};
const handleOpenItemDialog = (item: Item) => {
setCurrentItem(item);
setOpenItemDialog(true);
};
const handleCloseItemDialog = async () => {
setOpenItemDialog(false);
};
return (
<Paper sx={{ width: '100%' }}>
<Stack direction="row" spacing={2} padding={2}>
{profiles.length > 0 && (
<Select
labelId="profile-label"
sx={{ width: '200px' }}
onChange={handleFetchItems}
value={profile ?? ''}
>
{profiles.map((profile) => (
<MenuItem key={profile.id} value={profile.id}>
{profile.name}
</MenuItem>
))}
</Select>
)}
<Button
variant="outlined"
color="primary"
type="submit"
onClick={handleCreateItemDialog}
sx={{ width: '200px' }}
>
Create Item
</Button>
</Stack>
<Box
sx={{
height: 'calc(100vh - 50px)',
overflowY: 'scroll',
padding: 2,
paddingTop: 0
}}
ref={tableRef}
>
<Table
stickyHeader
sx={{
width: '100%'
}}
>
<TableHead>
<TableRow sx={{ '& th': { textAlign: 'center' } }}>
<TableCell>Name</TableCell>
<TableCell>Description</TableCell>
<TableCell>Price</TableCell>
<TableCell>Currency</TableCell>
<TableCell>Tag</TableCell>
<TableCell>Date</TableCell>
</TableRow>
</TableHead>
<TableBody>
{items &&
items.map((item) => (
<ItemsTableRow
key={item.id}
item={item}
onClick={handleOpenItemDialog}
/>
))}
</TableBody>
</Table>
</Box>
{currentItem && (
<ItemDialog
item={currentItem}
open={openItemDialog}
handleClose={handleCloseItemDialog}
/>
)}
<CreateItemDialog
key={formKey}
open={openCreateDialog}
close={handleCloseCreateDialog}
profile={profile}
/>
</Paper>
);
}

View File

@@ -0,0 +1,26 @@
import { TableCell, TableRow } from '@mui/material';
import { Item } from '../../../../data/types';
interface ItemsTableRowProps {
item: Item;
onClick: (item: Item) => void;
}
export default function ItemsTableRow({ item, onClick }: ItemsTableRowProps) {
return (
<TableRow
sx={{ '& td': { textAlign: 'center' } }}
key={item.id}
onClick={() => onClick(item)}
>
<TableCell>{item.name}</TableCell>
<TableCell>{item.description}</TableCell>
<TableCell>{Number(item.price).toFixed(2)}</TableCell>
<TableCell>{item.currency}</TableCell>
<TableCell>{item.tag}</TableCell>
<TableCell>
{item.createdAt && new Date(item.createdAt).toLocaleDateString()}
</TableCell>
</TableRow>
);
}

View File

@@ -0,0 +1,28 @@
'use server';
import { z } from 'zod';
import { ItemComment } from '../../../../data/types';
import prisma from '../../../../prisma/prisma';
export async function ItemsTableRowAction(id: string) {
const validatedId = z.string().safeParse(id);
if (!validatedId.success) {
throw new Error('Bad request');
}
try {
const itemWithComments = await prisma.item.findFirstOrThrow({
where: {
id: validatedId.data
},
include: {
ItemComment: true
}
});
return itemWithComments.ItemComment as ItemComment[];
} catch (error) {
throw new Error('Failed to find item comments');
}
}

View File

@@ -0,0 +1,48 @@
'use server';
import { Items } from '../../../../../data/types';
import prisma from '../../../../../prisma/prisma';
interface ItemsTableActionProps {
take: number;
profile: string | undefined;
}
export async function ItemsTableAction({
take,
profile
}: ItemsTableActionProps) {
if (!profile) {
return [] as Items;
}
try {
const items = await prisma.item.findMany({
where: {
profileId: profile
},
orderBy: {
createdAt: 'desc'
},
include: {
Tag: {
select: {
name: true
}
}
},
take
});
const itemsWithTag = items.map((item) => {
return {
...item,
tag: item?.Tag?.name
};
});
return itemsWithTag as Items;
} catch (error) {
throw new Error('Failed to find items');
}
}