Merge branch 'master' of ssh://git.madresebanoo.ir:2222/front-end/banu-front
Deploy banu-front / deploy (push) Successful in 2m0s
Deploy banu-front / deploy (push) Successful in 2m0s
This commit is contained in:
@@ -33,7 +33,7 @@
|
||||
<SelectField
|
||||
v-model="form.teacherId"
|
||||
name="teacherId"
|
||||
label="استاد"
|
||||
label="استاد (اختیاری)"
|
||||
:options="teacherOptions"
|
||||
option-label="name"
|
||||
option-value="id"
|
||||
@@ -251,12 +251,12 @@ watch(
|
||||
{ immediate: true }
|
||||
)
|
||||
|
||||
const uploadMutation = useUploadMediaMutation()
|
||||
const coverUploadMutation = useUploadMediaMutation()
|
||||
|
||||
const onImageCropped = async (file) => {
|
||||
try {
|
||||
const formData = objectToFormData({ file, purpose: 'cover', context: 'course' })
|
||||
const response = await uploadMutation.mutateAsync(formData)
|
||||
const response = await coverUploadMutation.mutateAsync(formData)
|
||||
const payload = response?.data ?? response
|
||||
image.value = { url: payload?.url, ...payload }
|
||||
form.value.coverMediaId = payload?.id
|
||||
@@ -270,15 +270,28 @@ const onImageError = (msg) => toast.error(msg)
|
||||
const addMutation = useAddAdminCourseMutation()
|
||||
const updateMutation = useUpdateAdminCourseMutation()
|
||||
|
||||
const submitting = computed(() => addMutation.isPending.value || updateMutation.isPending.value)
|
||||
const submitting = computed(
|
||||
() =>
|
||||
coverUploadMutation.isPending.value ||
|
||||
addMutation.isPending.value ||
|
||||
updateMutation.isPending.value
|
||||
)
|
||||
|
||||
const onSubmit = async () => {
|
||||
if (coverUploadMutation.isPending.value) {
|
||||
toast.info('لطفاً تا پایان بارگذاری تصویر دوره منتظر بمانید.')
|
||||
return
|
||||
}
|
||||
const { isValid, payload } = await validate(form.value)
|
||||
if (!isValid) return
|
||||
if (isEditMode.value) {
|
||||
await updateMutation.mutateAsync({ id: courseId.value, payload })
|
||||
} else {
|
||||
await addMutation.mutateAsync(payload)
|
||||
try {
|
||||
if (isEditMode.value) {
|
||||
await updateMutation.mutateAsync({ id: courseId.value, payload })
|
||||
} else {
|
||||
await addMutation.mutateAsync(payload)
|
||||
}
|
||||
} catch {
|
||||
return
|
||||
}
|
||||
await queryClient.invalidateQueries({ queryKey: adminCoursesKeys.all })
|
||||
router.push({ name: 'admin-courses' })
|
||||
|
||||
@@ -69,7 +69,12 @@ const courseIcon = gallery.courseIcon
|
||||
const routeTermId = computed(() => (route.params.termId ? Number(route.params.termId) : null))
|
||||
|
||||
const onAdd = () => {
|
||||
router.push({ name: 'admin-add-course' }).catch(() => {})
|
||||
router
|
||||
.push({
|
||||
name: 'admin-add-course',
|
||||
query: routeTermId.value ? { termId: routeTermId.value } : undefined,
|
||||
})
|
||||
.catch(() => {})
|
||||
}
|
||||
|
||||
const tabs = [
|
||||
|
||||
@@ -2,7 +2,8 @@ import { array, boolean, mixed, number, object, string } from 'yup'
|
||||
|
||||
export const courseSchema = object().shape({
|
||||
title: string().required().min(3).max(255),
|
||||
teacherId: mixed().required(),
|
||||
// The backend intentionally allows courses without an assigned teacher.
|
||||
teacherId: mixed().nullable().notRequired(),
|
||||
capacity: number()
|
||||
.typeError('ظرفیت باید بهصورت عدد وارد شود')
|
||||
.required()
|
||||
|
||||
@@ -95,7 +95,8 @@
|
||||
:accept="contentAccept"
|
||||
:multiple="false"
|
||||
:max-files="1"
|
||||
:disabled="!form.contentType"
|
||||
:max-size="contentMaxSize"
|
||||
:disabled="!form.contentType || contentUploadMutation.isPending.value"
|
||||
@select="onContentSelect"
|
||||
@remove="onContentRemove"
|
||||
@error="onContentError"
|
||||
@@ -162,7 +163,12 @@ import TextareaField from '@/components/form/TextareaField.vue'
|
||||
import { sessionSchema } from '@/features/admin/sessions/schema'
|
||||
import { useAdminCoursesListQuery } from '@/services/query/admin-courses'
|
||||
import BoxedIconTitleBlock from '@/components/blocks/BoxedIconTitleBlock.vue'
|
||||
import { COURSE_CONTENT_TYPE, COURSE_CONTENT_TYPE_ACCEPT, SESSION_TYPE } from '@/enums'
|
||||
import {
|
||||
COURSE_CONTENT_TYPE,
|
||||
COURSE_CONTENT_TYPE_ACCEPT,
|
||||
COURSE_CONTENT_TYPE_MAX_SIZE,
|
||||
SESSION_TYPE,
|
||||
} from '@/enums'
|
||||
import {
|
||||
adminSessionsKeys,
|
||||
useAddAdminSessionMutation,
|
||||
@@ -175,6 +181,7 @@ const router = useRouter()
|
||||
const queryClient = useQueryClient()
|
||||
|
||||
const sessionId = computed(() => (route.params.id ? Number(route.params.id) : null))
|
||||
const presetCourseId = computed(() => (route.query.courseId ? Number(route.query.courseId) : null))
|
||||
const isEditMode = computed(() => !!sessionId.value)
|
||||
|
||||
const sessionTypeOptions = [
|
||||
@@ -189,7 +196,7 @@ const contentTypeOptions = Object.entries(COURSE_CONTENT_TYPE).map(([value, labe
|
||||
|
||||
const form = ref({
|
||||
title: '',
|
||||
courseId: '',
|
||||
courseId: presetCourseId.value ?? '',
|
||||
contentType: '',
|
||||
type: '',
|
||||
link: '',
|
||||
@@ -202,6 +209,9 @@ const coverMediaId = ref(null)
|
||||
const contentMediaId = ref(null)
|
||||
|
||||
const contentAccept = computed(() => COURSE_CONTENT_TYPE_ACCEPT[form.value.contentType] || '*')
|
||||
const contentMaxSize = computed(
|
||||
() => COURSE_CONTENT_TYPE_MAX_SIZE[form.value.contentType] || 50 * 1024 * 1024
|
||||
)
|
||||
|
||||
const { validate, validateAt, errors } = useYup(sessionSchema)
|
||||
|
||||
@@ -276,7 +286,8 @@ watch(
|
||||
{ immediate: true }
|
||||
)
|
||||
|
||||
const uploadMutation = useUploadMediaMutation()
|
||||
const contentUploadMutation = useUploadMediaMutation()
|
||||
const coverUploadMutation = useUploadMediaMutation()
|
||||
|
||||
const purposeForContentType = (contentType) => {
|
||||
if (contentType === 'video') return 'video'
|
||||
@@ -293,7 +304,7 @@ const onContentSelect = async (files) => {
|
||||
purpose: purposeForContentType(form.value.contentType),
|
||||
context: 'session',
|
||||
})
|
||||
const response = await uploadMutation.mutateAsync(formData)
|
||||
const response = await contentUploadMutation.mutateAsync(formData)
|
||||
const payload = response?.data ?? response
|
||||
const id = payload?.id ?? payload?.uploadId
|
||||
contentFiles.value = [{ id, name: file.name, size: file.size, url: payload?.url }]
|
||||
@@ -313,7 +324,7 @@ const onContentError = (msg) => toast.error(msg)
|
||||
const onImageCropped = async (file) => {
|
||||
try {
|
||||
const formData = objectToFormData({ file, purpose: 'cover', context: 'session' })
|
||||
const response = await uploadMutation.mutateAsync(formData)
|
||||
const response = await coverUploadMutation.mutateAsync(formData)
|
||||
const payload = response?.data ?? response
|
||||
image.value = { url: payload?.url, ...payload }
|
||||
coverMediaId.value = payload?.id ?? null
|
||||
@@ -346,16 +357,34 @@ const buildPayload = (values) => {
|
||||
const addMutation = useAddAdminSessionMutation()
|
||||
const updateMutation = useUpdateAdminSessionMutation()
|
||||
|
||||
const submitting = computed(() => addMutation.isPending.value || updateMutation.isPending.value)
|
||||
const submitting = computed(
|
||||
() =>
|
||||
contentUploadMutation.isPending.value ||
|
||||
coverUploadMutation.isPending.value ||
|
||||
addMutation.isPending.value ||
|
||||
updateMutation.isPending.value
|
||||
)
|
||||
|
||||
const onSubmit = async () => {
|
||||
if (contentUploadMutation.isPending.value || coverUploadMutation.isPending.value) {
|
||||
toast.info('لطفاً تا پایان بارگذاری محتوای جلسه منتظر بمانید.')
|
||||
return
|
||||
}
|
||||
const { isValid } = await validate(form.value)
|
||||
if (!isValid) return
|
||||
if (form.value.contentType && contentMediaId.value == null) {
|
||||
toast.error('برای نوع محتوای انتخابشده، فایل جلسه را بارگذاری کنید.')
|
||||
return
|
||||
}
|
||||
const payload = buildPayload(form.value)
|
||||
if (isEditMode.value) {
|
||||
await updateMutation.mutateAsync({ id: sessionId.value, payload })
|
||||
} else {
|
||||
await addMutation.mutateAsync(payload)
|
||||
try {
|
||||
if (isEditMode.value) {
|
||||
await updateMutation.mutateAsync({ id: sessionId.value, payload })
|
||||
} else {
|
||||
await addMutation.mutateAsync(payload)
|
||||
}
|
||||
} catch {
|
||||
return
|
||||
}
|
||||
// The list query is inactive while we're on the form page, and the global
|
||||
// `refetchOnMount: false` means navigating back won't refetch a merely-stale
|
||||
|
||||
@@ -109,7 +109,12 @@ const onFilterApply = () => resetPagination()
|
||||
const onFilterReset = () => resetPagination()
|
||||
|
||||
const onAdd = () => {
|
||||
router.push({ name: 'admin-add-session' }).catch(() => {})
|
||||
router
|
||||
.push({
|
||||
name: 'admin-add-session',
|
||||
query: routeCourseId.value ? { courseId: routeCourseId.value } : undefined,
|
||||
})
|
||||
.catch(() => {})
|
||||
}
|
||||
|
||||
const onEdit = (session) => {
|
||||
|
||||
Reference in New Issue
Block a user