diff --git a/src/Components/Profile/ItemFunctions.spec.tsx b/src/Components/Profile/ItemFunctions.spec.tsx index a36498c5..70ebef02 100644 --- a/src/Components/Profile/ItemFunctions.spec.tsx +++ b/src/Components/Profile/ItemFunctions.spec.tsx @@ -2,6 +2,8 @@ import { describe, it, expect, vi } from 'vitest' import { linkItem } from './itemFunctions' +import type { Item } from '#types/Item' + const toastErrorMock: (t: string) => void = vi.fn() const toastSuccessMock: (t: string) => void = vi.fn() @@ -14,8 +16,45 @@ vi.mock('react-toastify', () => ({ describe('linkItem', () => { const id = 'some-id' - let updateApi: () => void = vi.fn() - const item = { layer: { api: { updateItem: () => updateApi() } } } + let updateApi: (item: Partial) => Promise = vi.fn() + const item: Item = { + layer: { + api: { + updateItem: (item) => updateApi(item), + getItems: vi.fn(), + }, + name: '', + menuIcon: '', + menuColor: '', + menuText: '', + markerIcon: { + image: '', + }, + markerShape: 'square', + markerDefaultColor: '', + itemType: { + name: 'Test Item Type', + show_name_input: true, + show_profile_button: false, + show_start_end: true, + show_start_end_input: true, + show_text: true, + show_text_input: true, + custom_text: 'This is a custom text for the item type.', + profileTemplate: [ + { collection: 'users', id: null, item: {} }, + { collection: 'posts', id: '123', item: {} }, + ], + offers_and_needs: true, + icon_as_labels: {}, + relations: true, + template: 'default', + questlog: false, + }, + }, + id: '', + name: '', + } const updateItem = vi.fn() beforeEach(() => { diff --git a/src/Components/Profile/ProfileForm.tsx b/src/Components/Profile/ProfileForm.tsx index a1d773e2..077741df 100644 --- a/src/Components/Profile/ProfileForm.tsx +++ b/src/Components/Profile/ProfileForm.tsx @@ -1,6 +1,5 @@ /* eslint-disable @typescript-eslint/restrict-template-expressions */ /* eslint-disable @typescript-eslint/no-unnecessary-condition */ -/* eslint-disable @typescript-eslint/no-unsafe-argument */ import { useEffect, useState } from 'react' import { useLocation, useNavigate } from 'react-router-dom' import { toast } from 'react-toastify' @@ -200,8 +199,8 @@ export function ProfileForm() { state={state} setState={setState} updatePermission={updatePermission} - linkItem={(id) => linkItem(id, item, updateItem)} - unlinkItem={(id) => unlinkItem(id, item, updateItem)} + linkItem={(id: string) => linkItem(id, item, updateItem)} + unlinkItem={(id: string) => unlinkItem(id, item, updateItem)} setUrlParams={setUrlParams} > )} diff --git a/src/Components/Profile/Subcomponents/GalleryForm.tsx b/src/Components/Profile/Subcomponents/GalleryForm.tsx index 76659a38..576c9639 100644 --- a/src/Components/Profile/Subcomponents/GalleryForm.tsx +++ b/src/Components/Profile/Subcomponents/GalleryForm.tsx @@ -1,3 +1,4 @@ +import { useState } from 'react' import { useDropzone } from 'react-dropzone' import { useAppState } from '#components/AppShell/hooks/useAppState' @@ -12,7 +13,11 @@ interface Props { export const GalleryForm = ({ state, setState }: Props) => { const appState = useAppState() + const [isUploading, setUploading] = useState(false) + const upload = async (acceptedFiles: File[]) => { + setUploading(true) + const assets = await Promise.all( acceptedFiles.map(async (file) => { return appState.assetsApi.upload(file, 'gallery') @@ -22,11 +27,13 @@ export const GalleryForm = ({ state, setState }: Props) => { const newGalleryItems = assets.map((asset) => ({ directus_files_id: { id: asset.id, - width: 600, // TODO determine - height: 400, // TODO determine + width: 600, // TODO map to ids only + height: 400, }, })) + setUploading(false) + setState((prevState) => ({ ...prevState, gallery: [...prevState.gallery, ...newGalleryItems], @@ -36,6 +43,9 @@ export const GalleryForm = ({ state, setState }: Props) => { const { getRootProps, getInputProps } = useDropzone({ // eslint-disable-next-line @typescript-eslint/no-misused-promises onDrop: upload, + accept: { + 'image/jpeg': [], + }, }) const images = state.gallery.map((i, j) => ({ @@ -62,6 +72,8 @@ export const GalleryForm = ({ state, setState }: Props) => { Drop here + {isUploading &&
Uploading...
} + {images.map((image, index) => (
{ - const newRelations = item.relations || [] +export const linkItem = async (id: string, item: Item, updateItem) => { + const newRelations = item.relations ?? [] newRelations?.push({ items_id: item.id, related_items_id: id }) const updatedItem = { id: item.id, relations: newRelations } @@ -96,7 +97,7 @@ export const linkItem = async (id: string, item, updateItem) => { } } -export const unlinkItem = async (id: string, item, updateItem) => { +export const unlinkItem = async (id: string, item: Item, updateItem) => { const newRelations = item.relations?.filter((r) => r.related_items_id !== id) const updatedItem = { id: item.id, relations: newRelations } @@ -116,7 +117,7 @@ export const unlinkItem = async (id: string, item, updateItem) => { export const handleDelete = async ( event: React.MouseEvent, - item, + item: Item, setLoading, removeItem, map, @@ -144,8 +145,8 @@ export const handleDelete = async ( } export const onUpdateItem = async ( - state, - item, + state: FormState, + item: Item, tags, addTag, setLoading, @@ -159,19 +160,20 @@ export const onUpdateItem = async ( const offerUpdates: any[] = [] // check for new offers - await state.offers?.map((o) => { + state.offers?.map((o) => { const existingOffer = item?.offers?.find((t) => t.tags_id === o.id) - existingOffer && offerUpdates.push(existingOffer.id) - if (!existingOffer && !tags.some((t) => t.id === o.id)) addTag({ ...o, offer_or_need: true }) + existingOffer && offerUpdates.push(existingOffer.tags_id) + if (!existingOffer && !tags.some((t: { id: string }) => t.id === o.id)) + addTag({ ...o, offer_or_need: true }) !existingOffer && offerUpdates.push({ items_id: item?.id, tags_id: o.id }) return null }) const needsUpdates: any[] = [] - await state.needs?.map((n) => { + state.needs?.map((n) => { const existingNeed = item?.needs?.find((t) => t.tags_id === n.id) - existingNeed && needsUpdates.push(existingNeed.id) + existingNeed && needsUpdates.push(existingNeed.tags_id) !existingNeed && needsUpdates.push({ items_id: item?.id, tags_id: n.id }) !existingNeed && !tags.some((t) => t.id === n.id) && addTag({ ...n, offer_or_need: true }) return null @@ -197,6 +199,7 @@ export const onUpdateItem = async ( ...(state.offers.length > 0 && { offers: offerUpdates }), ...(state.needs.length > 0 && { needs: needsUpdates }), ...(state.openCollectiveSlug && { openCollectiveSlug: state.openCollectiveSlug }), + gallery: state.gallery, } const offersState: any[] = [] @@ -216,7 +219,7 @@ export const onUpdateItem = async ( setLoading(true) - await state.text + state.text .toLocaleLowerCase() .match(hashTagRegex) ?.map((tag) => { @@ -234,7 +237,7 @@ export const onUpdateItem = async ( await sleep(200) if (!item.new) { - item?.layer?.api?.updateItem && + await (item?.layer?.api?.updateItem && toast .promise(item?.layer?.api?.updateItem(changedItem), { pending: 'updating Item ...', @@ -251,10 +254,10 @@ export const onUpdateItem = async ( setLoading(false) navigate(`/item/${item.id}${params && '?' + params}`) return null - }) + })) } else { item.new = false - item.layer?.api?.createItem && + await (item.layer?.api?.createItem && toast .promise(item.layer?.api?.createItem(changedItem), { pending: 'updating Item ...', @@ -280,6 +283,6 @@ export const onUpdateItem = async ( setLoading(false) navigate(`/${params && '?' + params}`) return null - }) + })) } }