({item, onSave}: {item?: Plant | null; onSave: (item: Plant) => void})
| 620 | } |
| 621 | |
| 622 | function PlantDialog({item, onSave}: {item?: Plant | null; onSave: (item: Plant) => void}) { |
| 623 | let [droppedImage, setDroppedImage] = useState(item?.default_image?.thumbnail); |
| 624 | return ( |
| 625 | <Dialog className="outline outline-0 relative"> |
| 626 | {({close}) => ( |
| 627 | <> |
| 628 | <Heading |
| 629 | slot="title" |
| 630 | className="text-2xl font-semibold leading-6 my-0 text-neutral-700 dark:text-neutral-300"> |
| 631 | {item ? 'Edit Plant' : 'Add Plant'} |
| 632 | </Heading> |
| 633 | <Form |
| 634 | onSubmit={e => { |
| 635 | e.preventDefault(); |
| 636 | close(); |
| 637 | let data = Object.fromEntries(new FormData(e.currentTarget)) as any; |
| 638 | data.sunlight = [data.sunlight]; |
| 639 | data.scientific_name = [data.scientific_name]; |
| 640 | data.default_image = {thumbnail: data.image}; |
| 641 | data.id = item?.id || Date.now(); |
| 642 | data.isFavorite = item?.isFavorite || false; |
| 643 | onSave(data); |
| 644 | }} |
| 645 | className="mt-6 flex flex-col gap-3"> |
| 646 | <div className="flex gap-4"> |
| 647 | <DropZone |
| 648 | getDropOperation={types => |
| 649 | types.has('image/jpeg') || types.has('image/png') ? 'copy' : 'cancel' |
| 650 | } |
| 651 | onDrop={async e => { |
| 652 | let item = e.items |
| 653 | .filter(isFileDropItem) |
| 654 | .find(item => item.type === 'image/jpeg' || item.type === 'image/png'); |
| 655 | if (item) { |
| 656 | setDroppedImage(URL.createObjectURL(await item.getFile())); |
| 657 | } |
| 658 | }} |
| 659 | className="w-24 sm:w-32 p-2 box-border flex items-center justify-center shrink-0 border-2 border-neutral-400 border-dashed rounded-xl text-neutral-500 dark:text-neutral-300 focus-visible:border-blue-600 forced-colors:focus-visible:border-[Highlight] focus-visible:border-solid drop-target:border-blue-600 forced-colors:drop-target:border-[Highlight] drop-target:border-solid drop-target:bg-blue-200 dark:drop-target:bg-blue-800/60 drop-target:text-blue-600 dark:drop-target:text-blue-300"> |
| 660 | {droppedImage ? ( |
| 661 | <img |
| 662 | alt="" |
| 663 | src={droppedImage} |
| 664 | className="w-full h-full object-contain aspect-square" |
| 665 | /> |
| 666 | ) : ( |
| 667 | <Text slot="label" className="italic text-sm text-center"> |
| 668 | Drop or paste image here |
| 669 | </Text> |
| 670 | )} |
| 671 | <input type="hidden" name="image" value={droppedImage} /> |
| 672 | </DropZone> |
| 673 | <div className="flex flex-col gap-3 flex-1 min-w-0"> |
| 674 | <ComboBox |
| 675 | label="Common Name" |
| 676 | placeholder="Enter plant name" |
| 677 | name="common_name" |
| 678 | isRequired |
| 679 | items={plants} |
nothing calls this directly
no test coverage detected