fix(courses): course cover image not saved on create/edit
The admin course form sent a stray upload id (imageId/uploadId) that didn't match any field the API accepts; the API expects cover_media_id with the media id returned from the upload endpoint. Also switch course displays to the coverUrl field the API actually returns.
This commit is contained in:
@@ -1,8 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="course-item">
|
<div class="course-item">
|
||||||
<div class="course-item__main">
|
<div class="course-item__main">
|
||||||
<div v-if="course.image" class="course-item__image">
|
<div v-if="course.coverUrl" class="course-item__image">
|
||||||
<img :src="course.image" :alt="course.title" />
|
<img :src="course.coverUrl" :alt="course.title" />
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="course-item__image course-item__image--placeholder">
|
<div v-else class="course-item__image course-item__image--placeholder">
|
||||||
<SvgIcon name="book" :size="22" color="#bcbcbc" />
|
<SvgIcon name="book" :size="22" color="#bcbcbc" />
|
||||||
@@ -30,14 +30,13 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="course-item__actions">
|
||||||
<div v-if="!isActive" class="course-item__status">
|
<div v-if="!isActive" class="course-item__status">
|
||||||
<span class="course-item__status-badge">
|
<span class="course-item__status-badge">
|
||||||
<span class="course-item__status-dot" />
|
<span class="course-item__status-dot" />
|
||||||
غیرفعال
|
غیرفعال
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="course-item__actions">
|
|
||||||
<ToggleSwitch
|
<ToggleSwitch
|
||||||
:model-value="!!isActive"
|
:model-value="!!isActive"
|
||||||
@update:model-value="emit('change-status', { id: course.id, isActive: !isActive })"
|
@update:model-value="emit('change-status', { id: course.id, isActive: !isActive })"
|
||||||
@@ -192,10 +191,6 @@ const isActive = computed(() => props.course.isActive ?? false)
|
|||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__status {
|
|
||||||
flex: 0 0 auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__status-badge {
|
&__status-badge {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -217,6 +212,7 @@ const isActive = computed(() => props.course.isActive ?? false)
|
|||||||
|
|
||||||
&__actions {
|
&__actions {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 0.375rem;
|
gap: 0.375rem;
|
||||||
|
|||||||
@@ -154,7 +154,7 @@ const form = ref({
|
|||||||
templateId: '',
|
templateId: '',
|
||||||
title: '',
|
title: '',
|
||||||
capacity: '',
|
capacity: '',
|
||||||
imageId: null,
|
coverMediaId: null,
|
||||||
isActive: false,
|
isActive: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -212,10 +212,10 @@ watch(existingCourse, (course) => {
|
|||||||
templateId: '',
|
templateId: '',
|
||||||
title: course.title || '',
|
title: course.title || '',
|
||||||
capacity: course.capacity ?? '',
|
capacity: course.capacity ?? '',
|
||||||
imageId: course.imageId || null,
|
coverMediaId: course.coverMediaId || null,
|
||||||
isActive: course.isActive ?? false,
|
isActive: course.isActive ?? false,
|
||||||
}
|
}
|
||||||
if (course.image) image.value = { url: course.image }
|
if (course.coverUrl) image.value = { url: course.coverUrl }
|
||||||
})
|
})
|
||||||
|
|
||||||
const uploadMutation = useUploadMediaMutation()
|
const uploadMutation = useUploadMediaMutation()
|
||||||
@@ -225,8 +225,8 @@ const onImageCropped = async (file) => {
|
|||||||
const formData = objectToFormData({ file, purpose: 'cover', context: 'course' })
|
const formData = objectToFormData({ file, purpose: 'cover', context: 'course' })
|
||||||
const response = await uploadMutation.mutateAsync(formData)
|
const response = await uploadMutation.mutateAsync(formData)
|
||||||
const payload = response?.data ?? response
|
const payload = response?.data ?? response
|
||||||
image.value = { url: payload?.url, uploadId: payload?.uploadId, ...payload }
|
image.value = { url: payload?.url, ...payload }
|
||||||
form.value.imageId = payload?.uploadId || payload?.id
|
form.value.coverMediaId = payload?.id
|
||||||
} catch {
|
} catch {
|
||||||
/* handled globally */
|
/* handled globally */
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
<template v-else-if="course">
|
<template v-else-if="course">
|
||||||
<div class="course-details__hero">
|
<div class="course-details__hero">
|
||||||
<div class="course-details__image">
|
<div class="course-details__image">
|
||||||
<img v-if="course.image" :src="course.image" :alt="course.title" />
|
<img v-if="course.coverUrl" :src="course.coverUrl" :alt="course.title" />
|
||||||
<SvgIcon v-else name="book" :size="32" color="#bcbcbc" />
|
<SvgIcon v-else name="book" :size="32" color="#bcbcbc" />
|
||||||
</div>
|
</div>
|
||||||
<div class="course-details__grid">
|
<div class="course-details__grid">
|
||||||
|
|||||||
@@ -24,6 +24,6 @@ export const offeredCourseSchema = object().shape({
|
|||||||
.required()
|
.required()
|
||||||
.integer('ظرفیت باید عدد صحیح باشد')
|
.integer('ظرفیت باید عدد صحیح باشد')
|
||||||
.min(1, 'ظرفیت باید حداقل ۱ نفر باشد'),
|
.min(1, 'ظرفیت باید حداقل ۱ نفر باشد'),
|
||||||
imageId: string().nullable().notRequired(),
|
coverMediaId: number().typeError('شناسه تصویر دوره باید عدد باشد').nullable().notRequired(),
|
||||||
isActive: boolean().nullable().notRequired(),
|
isActive: boolean().nullable().notRequired(),
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="course-item">
|
<div class="course-item">
|
||||||
<div class="course-item__main">
|
<div class="course-item__main">
|
||||||
<div v-if="course.image" class="course-item__image">
|
<div v-if="course.coverUrl" class="course-item__image">
|
||||||
<img :src="course.image" :alt="course.title" />
|
<img :src="course.coverUrl" :alt="course.title" />
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="course-item__image course-item__image--placeholder">
|
<div v-else class="course-item__image course-item__image--placeholder">
|
||||||
<SvgIcon name="book" :size="22" color="#bcbcbc" />
|
<SvgIcon name="book" :size="22" color="#bcbcbc" />
|
||||||
|
|||||||
Reference in New Issue
Block a user