add element upload UI

This commit is contained in:
Yisroel Baum 2026-06-02 10:30:48 +03:00
parent 4292494345
commit a2c3ffad8b
Signed by: yisroelbaum
GPG key ID: 0FA60884F75520A9
3 changed files with 384 additions and 67 deletions

View file

@ -22,9 +22,7 @@ interface ElementResponse {
export interface UpdateElementInput {
title: string
description: string
iconImageUrl: string
richText: string
pdfPath: string
youtubeUrl: string
}
@ -32,6 +30,15 @@ interface UpdateElementResponse {
element: Element
}
interface ElementPatchInput {
title?: string
description?: string
iconImageUrl?: string
richText?: string
pdfPath?: string
youtubeUrl?: string
}
interface ErrorResponse {
error?: string
}
@ -44,6 +51,8 @@ export const useElementsStore = defineStore('elements', () => {
const isLoading = ref(false)
const error = ref<string | null>(null)
const isSaving = ref(false)
const isUploadingIconImage = ref(false)
const isUploadingPdf = ref(false)
const saveError = ref<string | null>(null)
async function fetchElement(elementId: string): Promise<void> {
@ -80,6 +89,22 @@ export const useElementsStore = defineStore('elements', () => {
}
async function updateElement(elementId: string, input: UpdateElementInput): Promise<boolean> {
return await saveElementPatch(elementId, input, 'Could not save element')
}
async function clearElementIconImage(elementId: string): Promise<boolean> {
return await saveElementPatch(elementId, { iconImageUrl: '' }, 'Could not remove icon image')
}
async function clearElementPdf(elementId: string): Promise<boolean> {
return await saveElementPatch(elementId, { pdfPath: '' }, 'Could not remove PDF')
}
async function saveElementPatch(
elementId: string,
input: ElementPatchInput,
failureMessage: string,
): Promise<boolean> {
saveError.value = null
isSaving.value = true
@ -93,46 +118,117 @@ export const useElementsStore = defineStore('elements', () => {
body: JSON.stringify(input),
})
if (response.status === 401) {
saveError.value = 'Please log in again'
return false
}
if (response.status === 404) {
saveError.value = 'Element not found'
return false
}
if (response.status === 400) {
const data: ErrorResponse = await response.json()
saveError.value = data.error ?? 'Could not save element'
return false
}
if (!response.ok) {
saveError.value = 'Could not save element'
return false
}
const data: UpdateElementResponse = await response.json()
element.value = data.element
return true
return await handleElementResponse(response, failureMessage)
} catch {
saveError.value = 'Network error - could not save element'
saveError.value = `Network error - ${failureMessage.toLowerCase()}`
return false
} finally {
isSaving.value = false
}
}
async function uploadElementIconImage(elementId: string, file: File): Promise<boolean> {
saveError.value = null
isUploadingIconImage.value = true
try {
const encodedElementId = encodeURIComponent(elementId)
const elementUrl = `${API_BASE_URL}/api/elements/${encodedElementId}`
const formData = new FormData()
formData.append('iconImage', file)
const response = await fetch(`${elementUrl}/icon-image`, {
method: 'POST',
headers: { Accept: 'application/json' },
credentials: 'include',
body: formData,
})
return await handleElementResponse(response, 'Could not upload icon image')
} catch {
saveError.value = 'Network error - could not upload icon image'
return false
} finally {
isUploadingIconImage.value = false
}
}
async function uploadElementPdf(elementId: string, file: File): Promise<boolean> {
saveError.value = null
isUploadingPdf.value = true
try {
const encodedElementId = encodeURIComponent(elementId)
const elementUrl = `${API_BASE_URL}/api/elements/${encodedElementId}`
const formData = new FormData()
formData.append('pdf', file)
const response = await fetch(`${elementUrl}/pdf`, {
method: 'POST',
headers: { Accept: 'application/json' },
credentials: 'include',
body: formData,
})
return await handleElementResponse(response, 'Could not upload PDF')
} catch {
saveError.value = 'Network error - could not upload PDF'
return false
} finally {
isUploadingPdf.value = false
}
}
async function handleElementResponse(
response: Response,
failureMessage: string,
): Promise<boolean> {
if (response.status === 401) {
saveError.value = 'Please log in again'
return false
}
if (response.status === 404) {
saveError.value = 'Element not found'
return false
}
if (response.status === 400) {
saveError.value = await errorMessage(response, failureMessage)
return false
}
if (!response.ok) {
saveError.value = failureMessage
return false
}
const data: UpdateElementResponse = await response.json()
element.value = data.element
return true
}
async function errorMessage(response: Response, fallbackMessage: string): Promise<string> {
try {
const data: ErrorResponse = await response.json()
return data.error ?? fallbackMessage
} catch {
return fallbackMessage
}
}
return {
element,
childElements,
isLoading,
error,
isSaving,
isUploadingIconImage,
isUploadingPdf,
saveError,
fetchElement,
updateElement,
uploadElementIconImage,
uploadElementPdf,
clearElementIconImage,
clearElementPdf,
}
})