mirror of
https://github.com/utopia-os/utopia-ui.git
synced 2026-04-05 09:05:27 +00:00
Make gallery upload work; improve typing
This commit is contained in:
parent
6a68300cea
commit
b87a12a1d8
@ -2,6 +2,8 @@ import { describe, it, expect, vi } from 'vitest'
|
|||||||
|
|
||||||
import { linkItem } from './itemFunctions'
|
import { linkItem } from './itemFunctions'
|
||||||
|
|
||||||
|
import type { Item } from '#types/Item'
|
||||||
|
|
||||||
const toastErrorMock: (t: string) => void = vi.fn()
|
const toastErrorMock: (t: string) => void = vi.fn()
|
||||||
const toastSuccessMock: (t: string) => void = vi.fn()
|
const toastSuccessMock: (t: string) => void = vi.fn()
|
||||||
|
|
||||||
@ -14,8 +16,45 @@ vi.mock('react-toastify', () => ({
|
|||||||
|
|
||||||
describe('linkItem', () => {
|
describe('linkItem', () => {
|
||||||
const id = 'some-id'
|
const id = 'some-id'
|
||||||
let updateApi: () => void = vi.fn()
|
let updateApi: (item: Partial<Item>) => Promise<Item> = vi.fn()
|
||||||
const item = { layer: { api: { updateItem: () => updateApi() } } }
|
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()
|
const updateItem = vi.fn()
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
/* eslint-disable @typescript-eslint/restrict-template-expressions */
|
/* eslint-disable @typescript-eslint/restrict-template-expressions */
|
||||||
/* eslint-disable @typescript-eslint/no-unnecessary-condition */
|
/* eslint-disable @typescript-eslint/no-unnecessary-condition */
|
||||||
/* eslint-disable @typescript-eslint/no-unsafe-argument */
|
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
import { useLocation, useNavigate } from 'react-router-dom'
|
import { useLocation, useNavigate } from 'react-router-dom'
|
||||||
import { toast } from 'react-toastify'
|
import { toast } from 'react-toastify'
|
||||||
@ -200,8 +199,8 @@ export function ProfileForm() {
|
|||||||
state={state}
|
state={state}
|
||||||
setState={setState}
|
setState={setState}
|
||||||
updatePermission={updatePermission}
|
updatePermission={updatePermission}
|
||||||
linkItem={(id) => linkItem(id, item, updateItem)}
|
linkItem={(id: string) => linkItem(id, item, updateItem)}
|
||||||
unlinkItem={(id) => unlinkItem(id, item, updateItem)}
|
unlinkItem={(id: string) => unlinkItem(id, item, updateItem)}
|
||||||
setUrlParams={setUrlParams}
|
setUrlParams={setUrlParams}
|
||||||
></TabsForm>
|
></TabsForm>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
import { useState } from 'react'
|
||||||
import { useDropzone } from 'react-dropzone'
|
import { useDropzone } from 'react-dropzone'
|
||||||
|
|
||||||
import { useAppState } from '#components/AppShell/hooks/useAppState'
|
import { useAppState } from '#components/AppShell/hooks/useAppState'
|
||||||
@ -12,7 +13,11 @@ interface Props {
|
|||||||
export const GalleryForm = ({ state, setState }: Props) => {
|
export const GalleryForm = ({ state, setState }: Props) => {
|
||||||
const appState = useAppState()
|
const appState = useAppState()
|
||||||
|
|
||||||
|
const [isUploading, setUploading] = useState(false)
|
||||||
|
|
||||||
const upload = async (acceptedFiles: File[]) => {
|
const upload = async (acceptedFiles: File[]) => {
|
||||||
|
setUploading(true)
|
||||||
|
|
||||||
const assets = await Promise.all(
|
const assets = await Promise.all(
|
||||||
acceptedFiles.map(async (file) => {
|
acceptedFiles.map(async (file) => {
|
||||||
return appState.assetsApi.upload(file, 'gallery')
|
return appState.assetsApi.upload(file, 'gallery')
|
||||||
@ -22,11 +27,13 @@ export const GalleryForm = ({ state, setState }: Props) => {
|
|||||||
const newGalleryItems = assets.map((asset) => ({
|
const newGalleryItems = assets.map((asset) => ({
|
||||||
directus_files_id: {
|
directus_files_id: {
|
||||||
id: asset.id,
|
id: asset.id,
|
||||||
width: 600, // TODO determine
|
width: 600, // TODO map to ids only
|
||||||
height: 400, // TODO determine
|
height: 400,
|
||||||
},
|
},
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
setUploading(false)
|
||||||
|
|
||||||
setState((prevState) => ({
|
setState((prevState) => ({
|
||||||
...prevState,
|
...prevState,
|
||||||
gallery: [...prevState.gallery, ...newGalleryItems],
|
gallery: [...prevState.gallery, ...newGalleryItems],
|
||||||
@ -36,6 +43,9 @@ export const GalleryForm = ({ state, setState }: Props) => {
|
|||||||
const { getRootProps, getInputProps } = useDropzone({
|
const { getRootProps, getInputProps } = useDropzone({
|
||||||
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||||
onDrop: upload,
|
onDrop: upload,
|
||||||
|
accept: {
|
||||||
|
'image/jpeg': [],
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const images = state.gallery.map((i, j) => ({
|
const images = state.gallery.map((i, j) => ({
|
||||||
@ -62,6 +72,8 @@ export const GalleryForm = ({ state, setState }: Props) => {
|
|||||||
Drop here
|
Drop here
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{isUploading && <div className='tw:mt-2 tw:text-gray-500'>Uploading...</div>}
|
||||||
|
|
||||||
{images.map((image, index) => (
|
{images.map((image, index) => (
|
||||||
<div key={index} className='tw:mb-2'>
|
<div key={index} className='tw:mb-2'>
|
||||||
<img
|
<img
|
||||||
|
|||||||
@ -15,6 +15,7 @@ import { encodeTag } from '#utils/FormatTags'
|
|||||||
import { hashTagRegex } from '#utils/HashTagRegex'
|
import { hashTagRegex } from '#utils/HashTagRegex'
|
||||||
import { randomColor } from '#utils/RandomColor'
|
import { randomColor } from '#utils/RandomColor'
|
||||||
|
|
||||||
|
import type { FormState } from '#types/FormState'
|
||||||
import type { Item } from '#types/Item'
|
import type { Item } from '#types/Item'
|
||||||
|
|
||||||
// eslint-disable-next-line promise/avoid-new
|
// eslint-disable-next-line promise/avoid-new
|
||||||
@ -77,8 +78,8 @@ export const submitNewItem = async (
|
|||||||
setAddItemPopupType('')
|
setAddItemPopupType('')
|
||||||
}
|
}
|
||||||
|
|
||||||
export const linkItem = async (id: string, item, updateItem) => {
|
export const linkItem = async (id: string, item: Item, updateItem) => {
|
||||||
const newRelations = item.relations || []
|
const newRelations = item.relations ?? []
|
||||||
newRelations?.push({ items_id: item.id, related_items_id: id })
|
newRelations?.push({ items_id: item.id, related_items_id: id })
|
||||||
const updatedItem = { id: item.id, relations: newRelations }
|
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 newRelations = item.relations?.filter((r) => r.related_items_id !== id)
|
||||||
const updatedItem = { id: item.id, relations: newRelations }
|
const updatedItem = { id: item.id, relations: newRelations }
|
||||||
|
|
||||||
@ -116,7 +117,7 @@ export const unlinkItem = async (id: string, item, updateItem) => {
|
|||||||
|
|
||||||
export const handleDelete = async (
|
export const handleDelete = async (
|
||||||
event: React.MouseEvent<HTMLElement>,
|
event: React.MouseEvent<HTMLElement>,
|
||||||
item,
|
item: Item,
|
||||||
setLoading,
|
setLoading,
|
||||||
removeItem,
|
removeItem,
|
||||||
map,
|
map,
|
||||||
@ -144,8 +145,8 @@ export const handleDelete = async (
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const onUpdateItem = async (
|
export const onUpdateItem = async (
|
||||||
state,
|
state: FormState,
|
||||||
item,
|
item: Item,
|
||||||
tags,
|
tags,
|
||||||
addTag,
|
addTag,
|
||||||
setLoading,
|
setLoading,
|
||||||
@ -159,19 +160,20 @@ export const onUpdateItem = async (
|
|||||||
|
|
||||||
const offerUpdates: any[] = []
|
const offerUpdates: any[] = []
|
||||||
// check for new offers
|
// check for new offers
|
||||||
await state.offers?.map((o) => {
|
state.offers?.map((o) => {
|
||||||
const existingOffer = item?.offers?.find((t) => t.tags_id === o.id)
|
const existingOffer = item?.offers?.find((t) => t.tags_id === o.id)
|
||||||
existingOffer && offerUpdates.push(existingOffer.id)
|
existingOffer && offerUpdates.push(existingOffer.tags_id)
|
||||||
if (!existingOffer && !tags.some((t) => t.id === o.id)) addTag({ ...o, offer_or_need: true })
|
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 })
|
!existingOffer && offerUpdates.push({ items_id: item?.id, tags_id: o.id })
|
||||||
return null
|
return null
|
||||||
})
|
})
|
||||||
|
|
||||||
const needsUpdates: any[] = []
|
const needsUpdates: any[] = []
|
||||||
|
|
||||||
await state.needs?.map((n) => {
|
state.needs?.map((n) => {
|
||||||
const existingNeed = item?.needs?.find((t) => t.tags_id === n.id)
|
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 && needsUpdates.push({ items_id: item?.id, tags_id: n.id })
|
||||||
!existingNeed && !tags.some((t) => t.id === n.id) && addTag({ ...n, offer_or_need: true })
|
!existingNeed && !tags.some((t) => t.id === n.id) && addTag({ ...n, offer_or_need: true })
|
||||||
return null
|
return null
|
||||||
@ -197,6 +199,7 @@ export const onUpdateItem = async (
|
|||||||
...(state.offers.length > 0 && { offers: offerUpdates }),
|
...(state.offers.length > 0 && { offers: offerUpdates }),
|
||||||
...(state.needs.length > 0 && { needs: needsUpdates }),
|
...(state.needs.length > 0 && { needs: needsUpdates }),
|
||||||
...(state.openCollectiveSlug && { openCollectiveSlug: state.openCollectiveSlug }),
|
...(state.openCollectiveSlug && { openCollectiveSlug: state.openCollectiveSlug }),
|
||||||
|
gallery: state.gallery,
|
||||||
}
|
}
|
||||||
|
|
||||||
const offersState: any[] = []
|
const offersState: any[] = []
|
||||||
@ -216,7 +219,7 @@ export const onUpdateItem = async (
|
|||||||
|
|
||||||
setLoading(true)
|
setLoading(true)
|
||||||
|
|
||||||
await state.text
|
state.text
|
||||||
.toLocaleLowerCase()
|
.toLocaleLowerCase()
|
||||||
.match(hashTagRegex)
|
.match(hashTagRegex)
|
||||||
?.map((tag) => {
|
?.map((tag) => {
|
||||||
@ -234,7 +237,7 @@ export const onUpdateItem = async (
|
|||||||
await sleep(200)
|
await sleep(200)
|
||||||
|
|
||||||
if (!item.new) {
|
if (!item.new) {
|
||||||
item?.layer?.api?.updateItem &&
|
await (item?.layer?.api?.updateItem &&
|
||||||
toast
|
toast
|
||||||
.promise(item?.layer?.api?.updateItem(changedItem), {
|
.promise(item?.layer?.api?.updateItem(changedItem), {
|
||||||
pending: 'updating Item ...',
|
pending: 'updating Item ...',
|
||||||
@ -251,10 +254,10 @@ export const onUpdateItem = async (
|
|||||||
setLoading(false)
|
setLoading(false)
|
||||||
navigate(`/item/${item.id}${params && '?' + params}`)
|
navigate(`/item/${item.id}${params && '?' + params}`)
|
||||||
return null
|
return null
|
||||||
})
|
}))
|
||||||
} else {
|
} else {
|
||||||
item.new = false
|
item.new = false
|
||||||
item.layer?.api?.createItem &&
|
await (item.layer?.api?.createItem &&
|
||||||
toast
|
toast
|
||||||
.promise(item.layer?.api?.createItem(changedItem), {
|
.promise(item.layer?.api?.createItem(changedItem), {
|
||||||
pending: 'updating Item ...',
|
pending: 'updating Item ...',
|
||||||
@ -280,6 +283,6 @@ export const onUpdateItem = async (
|
|||||||
setLoading(false)
|
setLoading(false)
|
||||||
navigate(`/${params && '?' + params}`)
|
navigate(`/${params && '?' + params}`)
|
||||||
return null
|
return null
|
||||||
})
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user