diff --git a/src/api/merchImages.js b/src/api/merchImages.js new file mode 100644 index 0000000..93d9b6d --- /dev/null +++ b/src/api/merchImages.js @@ -0,0 +1,78 @@ +import { apiClient } from '@/services/apiClient.js' + +export const useMerchImagesApi = () => { + const uploadImage = async (uuid, file) => { + const formData = new FormData() + formData.append('file', file) + formData.append('imageType', 'all') + + try { + const response = await apiClient.post(`/merch/images/${uuid}`, formData) + + if (response.status !== 200) { + throw new Error(`Upload failed: ${response.status}`) + } + + return response.data + } catch (error) { + console.error('Upload failed:', error) + throw error + } + } + + const cachedImages = new Map() // Map + const getImageUrl = async (uuid, type) => { + try { + const response = await apiClient.get(`/merch/images/${uuid}`, { type }) + + if (response.status !== 200) { + throw new Error(`Get image failed: ${response.status}`) + } + + const { link, ETag } = response.data + + if (cachedImages.has(uuid) && cachedImages.get(uuid).etag === ETag) { + return cachedImages.get(uuid) + } + + const res = await fetch(link) + if (!res.ok) throw new Error(`Failed to load image: ${res.status}`) + + const blob = await res.blob() + const imgUrl = URL.createObjectURL(blob) + + cachedImages.set(uuid, { imgUrl, etag: ETag }) + return { imgUrl, etag: ETag } + + } catch (error) { + console.error('Get image failed:', error) + throw error + } + } + + const deleteImage = async (uuid) => { + try { + const response = await apiClient.delete(`/merch/images/${uuid}`) + if (response.status !== 200) { + throw new Error(`Delete failed: ${response.status}`) + } + + if (cachedImages.has(uuid)) { + const cached = cachedImages.get(uuid) + if (cached.imgUrl?.startsWith('blob:')) URL.revokeObjectURL(cached.imgUrl) + cachedImages.delete(uuid) + } + + return true + } catch (error) { + console.error('Delete image failed:', error) + throw error + } + } + + return { + uploadImage, + getImageUrl, + deleteImage, + } +} diff --git a/src/components/icons/BoxIcon.vue b/src/components/icons/BoxIcon.vue index 7dc1b16..e3083f1 100644 --- a/src/components/icons/BoxIcon.vue +++ b/src/components/icons/BoxIcon.vue @@ -1,13 +1,12 @@ @@ -52,6 +82,13 @@ defineProps({ overflow: hidden; } +.thumbnail { + width: 100%; + height: auto; + max-width: 80%; + object-fit: contain; +} + .cover-wrapper :deep(svg) { width: 100%; height: auto; diff --git a/src/views/DetailsView.vue b/src/views/DetailsView.vue index 1c54897..71d6f62 100644 --- a/src/views/DetailsView.vue +++ b/src/views/DetailsView.vue @@ -7,6 +7,7 @@ import ChartBlock from '@/components/ChartBlock.vue' import { useChartsApi } from '@/api/charts.js' import EditLink from '@/views/DetailsView/EditLink.vue' import CopyToClipboard from '@/components/CopyToClipboard.vue' +import DetailsViewImages from '@/views/DetailsView/DetailsViewImages.vue' const { getMerchDetails, deleteMerch } = useMerchApi() const { getDistinctPrices } = useChartsApi() @@ -102,8 +103,13 @@ onMounted(() => {
Error: {{ error }}
Main -

Uuid: {{ merchDetails.merch_uuid }}

-

Name: {{ merchDetails.name }}

+
+
+

Uuid: {{ merchDetails.merch_uuid }}

+

Name: {{ merchDetails.name }}

+
+ +
Prices @@ -131,7 +137,9 @@ onMounted(() => { @@ -164,7 +172,9 @@ onMounted(() => { @@ -195,4 +205,11 @@ onMounted(() => { - + diff --git a/src/views/DetailsView/DetailsViewImages.vue b/src/views/DetailsView/DetailsViewImages.vue new file mode 100644 index 0000000..db724f4 --- /dev/null +++ b/src/views/DetailsView/DetailsViewImages.vue @@ -0,0 +1,180 @@ + + + + +