chore: add all the code from original repo
This commit is contained in:
68
app/components/Dashboard/CreateItem/CreateItemDialog.tsx
Normal file
68
app/components/Dashboard/CreateItem/CreateItemDialog.tsx
Normal file
@@ -0,0 +1,68 @@
|
||||
import { TagsAction } from '@/components/Settings/Tags/actions/TagsAction';
|
||||
import { Button, Dialog, DialogContent, DialogTitle } from '@mui/material';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useFormState } from 'react-dom';
|
||||
import { Tags } from '../../../../data/types';
|
||||
import { CreateItemAction } from './actions/CreateItemAction';
|
||||
import { CreateItemForm } from './CreateItemForm';
|
||||
|
||||
interface CreateItemProps {
|
||||
open: boolean;
|
||||
close: (created: boolean) => void;
|
||||
profile: string | undefined;
|
||||
}
|
||||
|
||||
export default function CreateItemDialog({
|
||||
open,
|
||||
close,
|
||||
profile
|
||||
}: CreateItemProps) {
|
||||
const [tags, setTags] = useState<Tags>([]);
|
||||
|
||||
const [formState, formAction] = useFormState(CreateItemAction, {
|
||||
open: true,
|
||||
profile
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
const updateTags = async () => {
|
||||
if (profile) {
|
||||
try {
|
||||
const updatedTags = await TagsAction({ selectedProfile: profile });
|
||||
setTags(updatedTags);
|
||||
} catch (error) {
|
||||
console.error("Couldn't fetch tags.");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
updateTags();
|
||||
}, [profile]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!formState.open) {
|
||||
close(true);
|
||||
}
|
||||
}, [open, close, formState]);
|
||||
|
||||
const handleClose = async () => {
|
||||
close(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<Dialog open={open} onClose={handleClose}>
|
||||
<DialogTitle sx={{ alignSelf: 'center' }}>Create a new item</DialogTitle>
|
||||
<DialogContent sx={{ width: '400px' }}>
|
||||
<CreateItemForm profile={profile} formAction={formAction} tags={tags} />
|
||||
<Button
|
||||
variant="outlined"
|
||||
color="primary"
|
||||
fullWidth
|
||||
onClick={handleClose}
|
||||
>
|
||||
Close
|
||||
</Button>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
89
app/components/Dashboard/CreateItem/CreateItemForm.tsx
Normal file
89
app/components/Dashboard/CreateItem/CreateItemForm.tsx
Normal file
@@ -0,0 +1,89 @@
|
||||
import { CreateButton } from '@/components/UI/CreateButton';
|
||||
import {
|
||||
Checkbox,
|
||||
FormControl,
|
||||
FormControlLabel,
|
||||
InputLabel,
|
||||
MenuItem,
|
||||
Select,
|
||||
SelectChangeEvent,
|
||||
Stack,
|
||||
TextField
|
||||
} from '@mui/material';
|
||||
import { Currency } from '@prisma/client';
|
||||
import { useState } from 'react';
|
||||
import { Tag } from '../../../../data/types';
|
||||
|
||||
interface CreateItemProps {
|
||||
profile: string | undefined;
|
||||
formAction: (payload: FormData) => void;
|
||||
tags: Tag[];
|
||||
}
|
||||
|
||||
export function CreateItemForm({ profile, formAction, tags }: CreateItemProps) {
|
||||
const [selectedTag, setSelectedTag] = useState('');
|
||||
|
||||
const handleTagChange = (event: SelectChangeEvent<string>) => {
|
||||
setSelectedTag(event.target.value as string);
|
||||
};
|
||||
|
||||
return (
|
||||
<form action={formAction}>
|
||||
<Stack spacing={2} my={2}>
|
||||
<TextField name="name" label="Item" variant="outlined" required />
|
||||
<TextField name="description" label="Description" variant="outlined" />
|
||||
<TextField
|
||||
name="price"
|
||||
label="Price"
|
||||
variant="outlined"
|
||||
required
|
||||
type="number"
|
||||
inputProps={{ defaultValue: 0, step: 0.01, min: 0 }}
|
||||
/>
|
||||
<FormControl variant="outlined">
|
||||
<InputLabel id="currency-label">Currency</InputLabel>
|
||||
<Select
|
||||
name="currency"
|
||||
label="Currency"
|
||||
labelId="currency-label"
|
||||
value={Currency.DKK}
|
||||
>
|
||||
{Object.values(Currency).map((value) => (
|
||||
<MenuItem key={value} value={value}>
|
||||
{value}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
{profile && (
|
||||
<FormControl variant="outlined">
|
||||
<InputLabel id="tag-label">Tag</InputLabel>
|
||||
<Select
|
||||
name="tag"
|
||||
label="Tag"
|
||||
labelId="tag-label"
|
||||
value={selectedTag} // Use the state here
|
||||
onChange={handleTagChange}
|
||||
>
|
||||
{tags.map((tag) => (
|
||||
<MenuItem key={tag.id} value={tag.id}>
|
||||
{tag.name}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
)}
|
||||
<TextField name="body" label="Comment" variant="outlined" />
|
||||
<TextField
|
||||
name="score"
|
||||
label="Score"
|
||||
variant="outlined"
|
||||
type="number"
|
||||
inputProps={{ step: 1, min: 0, max: 10 }}
|
||||
/>
|
||||
<FormControlLabel control={<Checkbox name="regret" />} label="Regret" />
|
||||
<CreateButton />
|
||||
</Stack>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
'use server';
|
||||
|
||||
import { nanoid } from 'nanoid';
|
||||
import { initializeUser } from '../../../../../data/initializeUser';
|
||||
import { CreateItemFormSchema } from '../../../../../data/types';
|
||||
import prisma from '../../../../../prisma/prisma';
|
||||
|
||||
interface CreateItemActionProps {
|
||||
open: boolean;
|
||||
profile?: string;
|
||||
error?: string;
|
||||
}
|
||||
|
||||
export async function CreateItemAction(
|
||||
{ profile }: CreateItemActionProps,
|
||||
formData: FormData
|
||||
) {
|
||||
await initializeUser();
|
||||
|
||||
const profileId = profile ?? (await prisma.profile.findFirst())?.id;
|
||||
|
||||
const formDataObj = Object.fromEntries(formData.entries());
|
||||
|
||||
const validatedBody = CreateItemFormSchema.safeParse(formDataObj);
|
||||
|
||||
if (!validatedBody.success || !profileId) {
|
||||
throw new Error('Bad request');
|
||||
}
|
||||
|
||||
const { name, description, price, currency, tag, body, score, regret } =
|
||||
validatedBody.data;
|
||||
|
||||
const newId = nanoid();
|
||||
|
||||
try {
|
||||
await prisma.$transaction([
|
||||
prisma.item.create({
|
||||
data: {
|
||||
id: newId,
|
||||
name,
|
||||
description,
|
||||
price,
|
||||
currency,
|
||||
Profile: {
|
||||
connect: {
|
||||
id: profileId
|
||||
}
|
||||
},
|
||||
Tag: tag
|
||||
? {
|
||||
connect: {
|
||||
id: tag
|
||||
}
|
||||
}
|
||||
: undefined
|
||||
}
|
||||
}),
|
||||
prisma.itemComment.create({
|
||||
data: {
|
||||
body,
|
||||
score,
|
||||
regret,
|
||||
Item: {
|
||||
connect: {
|
||||
id: newId
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
]);
|
||||
} catch (error) {
|
||||
throw new Error(`Failed to create item`);
|
||||
}
|
||||
|
||||
return { open: false, profile: profileId };
|
||||
}
|
||||
Reference in New Issue
Block a user