fix: design
This commit is contained in:
@@ -119,7 +119,7 @@ import LineTitleBlock from '@/components/LineTitleBlock.vue'
|
||||
import ToggleSwitch from '@/components/form/ToggleSwitch.vue'
|
||||
import ImageCropper from '@/components/form/ImageCropper.vue'
|
||||
import { objectToFormData } from '@/utils/object-to-formdata'
|
||||
import { useUploadTemporaryMutation } from '@/services/query/auth'
|
||||
import { useUploadMediaMutation } from '@/services/query/auth'
|
||||
import { useAdminTermsListQuery } from '@/services/query/admin-terms'
|
||||
import { offeredCourseSchema } from '@/features/admin/courses/schema'
|
||||
import { useAdminCourseTemplatesListQuery } from '@/services/query/admin-course-templates'
|
||||
@@ -213,11 +213,11 @@ watch(existingCourse, (course) => {
|
||||
if (course.image) image.value = { url: course.image }
|
||||
})
|
||||
|
||||
const uploadMutation = useUploadTemporaryMutation()
|
||||
const uploadMutation = useUploadMediaMutation()
|
||||
|
||||
const onImageCropped = async (file) => {
|
||||
try {
|
||||
const formData = objectToFormData({ file, subType: 'avatar', context: 'course' })
|
||||
const formData = objectToFormData({ file, purpose: 'cover', context: 'course' })
|
||||
const response = await uploadMutation.mutateAsync(formData)
|
||||
const payload = response?.data ?? response
|
||||
image.value = { url: payload?.url, uploadId: payload?.uploadId, ...payload }
|
||||
|
||||
@@ -48,13 +48,35 @@
|
||||
name="defaultTeacherId"
|
||||
label="استاد"
|
||||
:options="teacherOptions"
|
||||
option-label="label"
|
||||
option-label="name"
|
||||
option-value="id"
|
||||
:searchable="true"
|
||||
:on-search="searchTeachers"
|
||||
:error="errors.defaultTeacherId"
|
||||
/>
|
||||
</div>
|
||||
<div class="course-form__cell course-form__cell--third">
|
||||
<TextField
|
||||
v-model="form.defaultCapacity"
|
||||
name="defaultCapacity"
|
||||
label="ظرفیت (نفر)"
|
||||
inputmode="numeric"
|
||||
:convert-digits="true"
|
||||
:error="errors.defaultCapacity"
|
||||
@blur="validateAt('defaultCapacity', form.defaultCapacity)"
|
||||
/>
|
||||
</div>
|
||||
<div class="course-form__cell course-form__cell--third">
|
||||
<TextField
|
||||
v-model="form.sessionsCount"
|
||||
name="sessionsCount"
|
||||
label="تعداد جلسه"
|
||||
inputmode="numeric"
|
||||
:convert-digits="true"
|
||||
:error="errors.sessionsCount"
|
||||
@blur="validateAt('sessionsCount', form.sessionsCount)"
|
||||
/>
|
||||
</div>
|
||||
<div class="course-form__cell course-form__cell--third">
|
||||
<SelectField
|
||||
v-model="form.prerequisites"
|
||||
@@ -69,25 +91,36 @@
|
||||
/>
|
||||
</div>
|
||||
<div class="course-form__cell course-form__cell--third">
|
||||
<TextField
|
||||
v-model="form.defaultCapacity"
|
||||
name="defaultCapacity"
|
||||
label="ظرفیت (نفر)"
|
||||
inputmode="numeric"
|
||||
:convert-digits="true"
|
||||
:error="errors.defaultCapacity"
|
||||
@blur="validateAt('defaultCapacity', form.defaultCapacity)"
|
||||
<SelectField
|
||||
v-model="form.contentType"
|
||||
name="contentType"
|
||||
label="نوع فایل دوره"
|
||||
:options="contentTypeOptions"
|
||||
option-label="label"
|
||||
option-value="value"
|
||||
:error="errors.contentType"
|
||||
@change="onContentTypeChange"
|
||||
/>
|
||||
</div>
|
||||
<div class="course-form__cell course-form__cell--third course-form__toggle-cell">
|
||||
<ToggleSwitch v-model="form.isActiveByDefault" label="دوره فعال باشد" />
|
||||
</div>
|
||||
<div class="course-form__cell course-form__cell--full">
|
||||
<TextareaField
|
||||
v-model="form.description"
|
||||
name="description"
|
||||
label="توضیحات"
|
||||
label="توضیحات دوره"
|
||||
:row="5"
|
||||
:error="errors.description"
|
||||
/>
|
||||
</div>
|
||||
<div class="course-form__cell course-form__cell--full">
|
||||
<label class="course-form__uploader-label">فایل دوره</label>
|
||||
<FileUploader
|
||||
v-model="contentFiles"
|
||||
:accept="contentAccept"
|
||||
:multiple="false"
|
||||
:max-files="1"
|
||||
@select="onContentSelect"
|
||||
@remove="onContentRemove"
|
||||
@error="onContentError"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -134,13 +167,14 @@ import SvgIcon from '@/components/icons/SvgIcon.vue'
|
||||
import TextField from '@/components/form/TextField.vue'
|
||||
import SelectField from '@/components/form/SelectField.vue'
|
||||
import LineTitleBlock from '@/components/LineTitleBlock.vue'
|
||||
import ToggleSwitch from '@/components/form/ToggleSwitch.vue'
|
||||
import FileUploader from '@/components/form/FileUploader.vue'
|
||||
import ImageCropper from '@/components/form/ImageCropper.vue'
|
||||
import { objectToFormData } from '@/utils/object-to-formdata'
|
||||
import { useUploadMediaMutation } from '@/services/query/auth'
|
||||
import TextareaField from '@/components/form/TextareaField.vue'
|
||||
import { useUploadTemporaryMutation } from '@/services/query/auth'
|
||||
import { useAdminUsersListQuery } from '@/services/query/admin-users'
|
||||
import { courseTemplateSchema } from '@/features/admin/courses/schema'
|
||||
import { COURSE_CONTENT_TYPE, COURSE_CONTENT_TYPE_ACCEPT } from '@/enums'
|
||||
import BoxedIconTitleBlock from '@/components/blocks/BoxedIconTitleBlock.vue'
|
||||
import {
|
||||
adminCourseTemplatesKeys,
|
||||
@@ -155,23 +189,33 @@ const router = useRouter()
|
||||
const queryClient = useQueryClient()
|
||||
|
||||
const courseId = computed(() => (route.params.id ? Number(route.params.id) : null))
|
||||
const termId = computed(() => (route.query.termId ? Number(route.query.termId) : null))
|
||||
const isEditMode = computed(() => !!courseId.value)
|
||||
|
||||
const form = ref({
|
||||
title: '',
|
||||
defaultTeacherId: '',
|
||||
prerequisites: [],
|
||||
defaultCapacity: '',
|
||||
sessionsCount: '',
|
||||
prerequisites: [],
|
||||
contentType: '',
|
||||
contentMediaId: null,
|
||||
description: '',
|
||||
imageId: null,
|
||||
isActiveByDefault: false,
|
||||
coverMediaId: null,
|
||||
termId: termId.value,
|
||||
})
|
||||
|
||||
const image = ref(null)
|
||||
const contentFiles = ref([])
|
||||
|
||||
const schema = courseTemplateSchema
|
||||
const contentTypeOptions = Object.entries(COURSE_CONTENT_TYPE).map(([value, label]) => ({
|
||||
value,
|
||||
label,
|
||||
}))
|
||||
|
||||
const { validate, validateAt, errors } = useYup(schema)
|
||||
const contentAccept = computed(() => COURSE_CONTENT_TYPE_ACCEPT[form.value.contentType] || '*')
|
||||
|
||||
const { validate, validateAt, errors } = useYup(courseTemplateSchema)
|
||||
|
||||
const teacherSearch = ref('')
|
||||
const teacherFilters = computed(() => ({ name: teacherSearch.value }))
|
||||
@@ -222,24 +266,37 @@ watch(existingCourse, (course) => {
|
||||
form.value = {
|
||||
title: course.title || '',
|
||||
defaultTeacherId: teacher?.id || course.defaultTeacherId || '',
|
||||
prerequisites: prereqs.map((p) => p.courseId ?? p.id).filter(Boolean),
|
||||
defaultCapacity: course.defaultCapacity ?? course.capacity ?? '',
|
||||
sessionsCount: course.sessionsCount ?? '',
|
||||
prerequisites: prereqs.map((p) => p.courseId ?? p.id).filter(Boolean),
|
||||
contentType: course.contentType || '',
|
||||
contentMediaId: course.contentMediaId || null,
|
||||
description: course.description || '',
|
||||
imageId: course.imageId || null,
|
||||
isActiveByDefault: course.isActiveByDefault ?? course.isActive ?? false,
|
||||
coverMediaId: course.coverMediaId || null,
|
||||
termId: termId.value,
|
||||
}
|
||||
if (course.coverUrl) image.value = { url: course.coverUrl }
|
||||
if (course.contentMedia) {
|
||||
contentFiles.value = [
|
||||
{
|
||||
id: course.contentMedia.id,
|
||||
name: course.contentMedia.name || course.contentMedia.fileName || 'file',
|
||||
size: course.contentMedia.size ?? 0,
|
||||
url: course.contentMedia.url,
|
||||
},
|
||||
]
|
||||
}
|
||||
if (course.image) image.value = { url: course.image }
|
||||
})
|
||||
|
||||
const uploadMutation = useUploadTemporaryMutation()
|
||||
const uploadMutation = useUploadMediaMutation()
|
||||
|
||||
const onImageCropped = async (file) => {
|
||||
try {
|
||||
const formData = objectToFormData({ file, subType: 'avatar', context: 'course' })
|
||||
const formData = objectToFormData({ file, purpose: 'cover', context: 'course' })
|
||||
const response = await uploadMutation.mutateAsync(formData)
|
||||
const payload = response?.data ?? response
|
||||
image.value = { url: payload?.url, uploadId: payload?.uploadId, ...payload }
|
||||
form.value.imageId = payload?.uploadId || payload?.id
|
||||
image.value = { url: payload?.url, ...payload }
|
||||
form.value.coverMediaId = payload?.id
|
||||
} catch {
|
||||
/* handled globally */
|
||||
}
|
||||
@@ -247,6 +304,38 @@ const onImageCropped = async (file) => {
|
||||
|
||||
const onImageError = (msg) => toast.error(msg)
|
||||
|
||||
const onContentTypeChange = () => {
|
||||
contentFiles.value = []
|
||||
form.value.contentMediaId = null
|
||||
}
|
||||
|
||||
const onContentSelect = async (files) => {
|
||||
const file = files?.[0]
|
||||
if (!file) return
|
||||
try {
|
||||
const formData = objectToFormData({
|
||||
file,
|
||||
purpose: 'content',
|
||||
context: 'course',
|
||||
type: form.value.contentType,
|
||||
})
|
||||
const response = await uploadMutation.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 }]
|
||||
form.value.contentMediaId = id
|
||||
} catch {
|
||||
contentFiles.value = []
|
||||
}
|
||||
}
|
||||
|
||||
const onContentRemove = () => {
|
||||
contentFiles.value = []
|
||||
form.value.contentMediaId = null
|
||||
}
|
||||
|
||||
const onContentError = (msg) => toast.error(msg)
|
||||
|
||||
const addMutation = useAddAdminCourseTemplateMutation()
|
||||
const updateMutation = useUpdateAdminCourseTemplateMutation()
|
||||
|
||||
@@ -345,9 +434,14 @@ const onCancel = () => router.push({ name: 'admin-courses' })
|
||||
}
|
||||
}
|
||||
|
||||
&__toggle-cell {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
&__uploader-label {
|
||||
display: block;
|
||||
margin-bottom: 0.5rem;
|
||||
font-family: var(--font-family-fa);
|
||||
font-weight: 300;
|
||||
line-height: 1.5rem;
|
||||
font-size: 0.875rem;
|
||||
color: var(--color-prim-gray);
|
||||
}
|
||||
|
||||
&__divider {
|
||||
|
||||
@@ -164,7 +164,7 @@ const { data: offeredData, isLoading: offeredPending } = useAdminCoursesListQuer
|
||||
}
|
||||
)
|
||||
|
||||
const templates = computed(() => templatesData.value?.data ?? [])
|
||||
const templates = computed(() => templatesData.value?.data?.items ?? [])
|
||||
const templatesPaginationMeta = computed(() => ({
|
||||
page: templatesPagination.value.page,
|
||||
perPage: templatesPagination.value.perPage,
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
import { array, boolean, object, string } from 'yup'
|
||||
import { array, boolean, mixed, number, object, string } from 'yup'
|
||||
|
||||
export const courseTemplateSchema = object().shape({
|
||||
title: string().required().min(3).max(255),
|
||||
defaultTeacherId: string().required(),
|
||||
defaultCapacity: string().required(),
|
||||
defaultTeacherId: mixed().required(),
|
||||
defaultCapacity: number().required().min(1),
|
||||
sessionsCount: number().required().min(1),
|
||||
prerequisites: array().nullable().default([]),
|
||||
contentType: string().oneOf(['video', 'voice', 'text']).required(),
|
||||
contentMediaId: number().nullable().notRequired(),
|
||||
description: string().nullable().notRequired(),
|
||||
termId: string().nullable(),
|
||||
})
|
||||
|
||||
export const offeredCourseSchema = object().shape({
|
||||
|
||||
@@ -236,7 +236,7 @@ import FileUploader from '@/components/form/FileUploader.vue'
|
||||
import { objectToFormData } from '@/utils/object-to-formdata'
|
||||
import TextareaField from '@/components/form/TextareaField.vue'
|
||||
import { sessionSchema } from '@/features/admin/sessions/schema'
|
||||
import { useUploadTemporaryMutation } from '@/services/query/auth'
|
||||
import { useUploadMediaMutation } from '@/services/query/auth'
|
||||
import DatePickerField from '@/components/form/DatePickerField.vue'
|
||||
import BoxedIconTitleBlock from '@/components/blocks/BoxedIconTitleBlock.vue'
|
||||
import { useAdminCourseTemplatesListQuery } from '@/services/query/admin-course-templates'
|
||||
@@ -341,7 +341,7 @@ watch(existingSession, (session) => {
|
||||
}
|
||||
})
|
||||
|
||||
const uploadMutation = useUploadTemporaryMutation()
|
||||
const uploadMutation = useUploadMediaMutation()
|
||||
|
||||
const onImageCropped = async (file) => {
|
||||
try {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<template>
|
||||
<div class="term-item">
|
||||
<div class="term-item__main">
|
||||
<div v-if="term.image" class="term-item__image">
|
||||
<img :src="term.image" :alt="term.title" />
|
||||
<div v-if="term.coverUrl" class="term-item__image">
|
||||
<img :src="term.coverUrl" :alt="term.title" />
|
||||
</div>
|
||||
<div v-else class="term-item__image term-item__image--placeholder">
|
||||
<SvgIcon name="book" :size="24" color="#bcbcbc" />
|
||||
|
||||
@@ -42,20 +42,20 @@
|
||||
</div>
|
||||
<div class="term-form__cell term-form__cell--third">
|
||||
<DatePickerField
|
||||
v-model="form.startDate"
|
||||
name="startDate"
|
||||
v-model="form.startsAt"
|
||||
name="startsAt"
|
||||
label="تاریخ شروع"
|
||||
:min="todayIso"
|
||||
:error="errors.startDate"
|
||||
:error="errors.startsAt"
|
||||
/>
|
||||
</div>
|
||||
<div class="term-form__cell term-form__cell--third">
|
||||
<DatePickerField
|
||||
v-model="form.endDate"
|
||||
name="endDate"
|
||||
v-model="form.endsAt"
|
||||
name="endsAt"
|
||||
label="تاریخ پایان"
|
||||
:min="todayIso"
|
||||
:error="errors.endDate"
|
||||
:error="errors.endsAt"
|
||||
/>
|
||||
</div>
|
||||
<div class="term-form__cell term-form__cell--full">
|
||||
@@ -112,8 +112,8 @@ import { termSchema } from '@/features/admin/terms/schema'
|
||||
import LineTitleBlock from '@/components/LineTitleBlock.vue'
|
||||
import ImageCropper from '@/components/form/ImageCropper.vue'
|
||||
import { objectToFormData } from '@/utils/object-to-formdata'
|
||||
import { useUploadMediaMutation } from '@/services/query/auth'
|
||||
import TextareaField from '@/components/form/TextareaField.vue'
|
||||
import { useUploadTemporaryMutation } from '@/services/query/auth'
|
||||
import DatePickerField from '@/components/form/DatePickerField.vue'
|
||||
import BoxedIconTitleBlock from '@/components/blocks/BoxedIconTitleBlock.vue'
|
||||
import {
|
||||
@@ -134,17 +134,16 @@ const todayIso = new Date().toISOString()
|
||||
|
||||
const form = ref({
|
||||
title: '',
|
||||
startDate: '',
|
||||
endDate: '',
|
||||
description: '',
|
||||
imageId: null,
|
||||
isActive: true,
|
||||
startsAt: '',
|
||||
endsAt: '',
|
||||
coverMediaId: null,
|
||||
})
|
||||
|
||||
const image = ref(null)
|
||||
|
||||
const schema = termSchema
|
||||
|
||||
const { validate, validateAt, errors } = useYup(schema)
|
||||
const { validate, validateAt, errors } = useYup(termSchema)
|
||||
|
||||
const { data: existingTerm } = useAdminTermQuery(termId, {
|
||||
enabled: () => !!termId.value,
|
||||
@@ -154,23 +153,24 @@ watch(existingTerm, (term) => {
|
||||
if (!term) return
|
||||
form.value = {
|
||||
title: term.title || '',
|
||||
startDate: term.startDate || '',
|
||||
endDate: term.endDate || '',
|
||||
description: term.description || '',
|
||||
imageId: term.imageId || null,
|
||||
isActive: term.isActive ?? true,
|
||||
startsAt: term.startsAt || '',
|
||||
endsAt: term.endsAt || '',
|
||||
coverMediaId: term.coverMediaId || null,
|
||||
}
|
||||
if (term.image) image.value = { url: term.image }
|
||||
if (term.coverUrl) image.value = { url: term.coverUrl }
|
||||
})
|
||||
|
||||
const uploadMutation = useUploadTemporaryMutation()
|
||||
const uploadMutation = useUploadMediaMutation()
|
||||
|
||||
const onImageCropped = async (file) => {
|
||||
try {
|
||||
const formData = objectToFormData({ file, subType: 'avatar', context: 'term' })
|
||||
const formData = objectToFormData({ file, purpose: 'cover', context: 'term' })
|
||||
const response = await uploadMutation.mutateAsync(formData)
|
||||
const payload = response?.data ?? response
|
||||
image.value = { url: payload?.url, uploadId: payload?.uploadId, ...payload }
|
||||
form.value.imageId = payload?.uploadId || payload?.id
|
||||
image.value = { url: payload?.url, ...payload }
|
||||
form.value.coverMediaId = payload?.id
|
||||
} catch {
|
||||
/* handled globally */
|
||||
}
|
||||
@@ -191,7 +191,7 @@ const onSubmit = async () => {
|
||||
} else {
|
||||
await addMutation.mutateAsync(payload)
|
||||
}
|
||||
await queryClient.invalidateQueries({ queryKey: adminTermsKeys.all })
|
||||
await queryClient.resetQueries({ queryKey: adminTermsKeys.all })
|
||||
router.push({ name: 'admin-terms' })
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import { array, mixed, object, string } from 'yup'
|
||||
import { array, boolean, mixed, number, object, string } from 'yup'
|
||||
|
||||
export const termSchema = object().shape({
|
||||
title: string().required().min(3),
|
||||
startDate: string().required(),
|
||||
endDate: string().required(),
|
||||
description: string().nullable().notRequired(),
|
||||
isActive: boolean().default(true),
|
||||
startsAt: string().required(),
|
||||
endsAt: string().required(),
|
||||
coverMediaId: number().nullable().notRequired(),
|
||||
})
|
||||
|
||||
export const addTermStudentSchema = object().shape({
|
||||
|
||||
@@ -72,11 +72,7 @@ import SvgIcon from '@/components/icons/SvgIcon.vue'
|
||||
import BaseButton from '@/components/BaseButton.vue'
|
||||
import { CHANGEABLE_ROLES, ROLE_LABELS } from '@/enums'
|
||||
import DropdownMenu from '@/components/DropdownMenu.vue'
|
||||
import {
|
||||
adminUsersKeys,
|
||||
useAdminRolesListQuery,
|
||||
useUpdateAdminUserRoleMutation,
|
||||
} from '@/services/query/admin-users'
|
||||
import { adminUsersKeys, useUpdateAdminUserRoleMutation } from '@/services/query/admin-users'
|
||||
|
||||
defineProps({
|
||||
users: { type: Array, required: true },
|
||||
@@ -124,15 +120,6 @@ const onMoreClick = (event, user) => {
|
||||
const roleMenuOpen = ref(false)
|
||||
const roleMenuTrigger = ref(null)
|
||||
|
||||
const { data: rolesList = ref([]) } = useAdminRolesListQuery()
|
||||
const roleIdByName = computed(() => {
|
||||
const map = {}
|
||||
;(rolesList.value ?? []).forEach((r) => {
|
||||
if (r?.name) map[r.name] = r.id
|
||||
})
|
||||
return map
|
||||
})
|
||||
|
||||
const updateRoleMutation = useUpdateAdminUserRoleMutation()
|
||||
|
||||
const invalidateUsers = () => queryClient.invalidateQueries({ queryKey: adminUsersKeys.all })
|
||||
@@ -150,10 +137,11 @@ const onRoleClick = (event, user) => {
|
||||
|
||||
const onChangeRole = (targetRoleName) => {
|
||||
const user = activeUser.value
|
||||
if (!user) return
|
||||
const roleId = roleIdByName.value[targetRoleName]
|
||||
const payload = roleId ? { roleId } : { role: targetRoleName }
|
||||
updateRoleMutation.mutate({ id: user.id, payload }, { onSuccess: invalidateUsers })
|
||||
if (!user || !targetRoleName) return
|
||||
updateRoleMutation.mutate(
|
||||
{ id: user.id, payload: { roles: [targetRoleName] } },
|
||||
{ onSuccess: invalidateUsers }
|
||||
)
|
||||
}
|
||||
|
||||
const roleMenuItems = computed(() => {
|
||||
|
||||
@@ -233,7 +233,7 @@ import { GENDER, MARITAL_STATUS, ROLE_LABELS } from '@/enums'
|
||||
import { objectToFormData } from '@/utils/object-to-formdata'
|
||||
import TextareaField from '@/components/form/TextareaField.vue'
|
||||
import PasswordField from '@/components/form/PasswordField.vue'
|
||||
import { useUploadTemporaryMutation } from '@/services/query/auth'
|
||||
import { useUploadMediaMutation } from '@/services/query/auth'
|
||||
import DatePickerField from '@/components/form/DatePickerField.vue'
|
||||
import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue'
|
||||
import BoxedIconTitleBlock from '@/components/blocks/BoxedIconTitleBlock.vue'
|
||||
@@ -348,7 +348,7 @@ watch(existingUser, (user) => {
|
||||
}
|
||||
})
|
||||
|
||||
const uploadMutation = useUploadTemporaryMutation()
|
||||
const uploadMutation = useUploadMediaMutation()
|
||||
|
||||
const onAvatarCropped = async (file) => {
|
||||
try {
|
||||
|
||||
@@ -79,7 +79,7 @@ import useModal from '@/composables/useModal'
|
||||
import { computed, onBeforeUnmount, ref } from 'vue'
|
||||
import SvgIcon from '@/components/icons/SvgIcon.vue'
|
||||
import { objectToFormData } from '@/utils/object-to-formdata'
|
||||
import { useUploadTemporaryMutation } from '@/services/query/auth'
|
||||
import { useUploadMediaMutation } from '@/services/query/auth'
|
||||
import PermissionModal from '@/features/auth/components/studentRegister/PermissionModal.vue'
|
||||
|
||||
const props = defineProps({
|
||||
@@ -123,7 +123,7 @@ const formattedTime = computed(() => {
|
||||
return `${mm}:${ss}`
|
||||
})
|
||||
|
||||
const uploadMutation = useUploadTemporaryMutation()
|
||||
const uploadMutation = useUploadMediaMutation()
|
||||
|
||||
const stopTracks = () => {
|
||||
if (mediaStream) {
|
||||
|
||||
@@ -167,7 +167,7 @@ import LineTitleBlock from '@/components/LineTitleBlock.vue'
|
||||
import ImageCropper from '@/components/form/ImageCropper.vue'
|
||||
import { objectToFormData } from '@/utils/object-to-formdata'
|
||||
import TextareaField from '@/components/form/TextareaField.vue'
|
||||
import { useUploadTemporaryMutation } from '@/services/query/auth'
|
||||
import { useUploadMediaMutation } from '@/services/query/auth'
|
||||
import DatePickerField from '@/components/form/DatePickerField.vue'
|
||||
import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue'
|
||||
import { GENDER, MARITAL_STATUS, STUDENT_REGISTRATION } from '@/enums'
|
||||
@@ -242,7 +242,7 @@ watch(
|
||||
}
|
||||
)
|
||||
|
||||
const uploadMutation = useUploadTemporaryMutation()
|
||||
const uploadMutation = useUploadMediaMutation()
|
||||
|
||||
const onAvatarCropped = async (file) => {
|
||||
try {
|
||||
|
||||
@@ -223,9 +223,9 @@ import BoxedIconTitleBlock from '@/components/blocks/BoxedIconTitleBlock.vue'
|
||||
import { useGetCitiesOfProvinceQuery, useGetProvincesQuery } from '@/services/query/common'
|
||||
import {
|
||||
authKeys,
|
||||
useGetProfileQuery,
|
||||
useGetMeQuery,
|
||||
useUpdateProfileMutation,
|
||||
useUploadTemporaryMutation,
|
||||
useUploadMediaMutation,
|
||||
} from '@/services/query/auth'
|
||||
|
||||
const router = useRouter()
|
||||
@@ -291,7 +291,7 @@ watch(
|
||||
}
|
||||
)
|
||||
|
||||
const { data: profile } = useGetProfileQuery()
|
||||
const { data: profile } = useGetMeQuery()
|
||||
|
||||
watch(profile, (user) => {
|
||||
if (!user) return
|
||||
@@ -315,7 +315,7 @@ watch(profile, (user) => {
|
||||
if (user.avatarUrl) avatar.value = { url: user.avatarUrl }
|
||||
})
|
||||
|
||||
const uploadMutation = useUploadTemporaryMutation()
|
||||
const uploadMutation = useUploadMediaMutation()
|
||||
|
||||
const onAvatarCropped = async (file) => {
|
||||
try {
|
||||
@@ -341,7 +341,7 @@ const onSubmit = async () => {
|
||||
delete payload.passwordConfirmation
|
||||
}
|
||||
await updateMutation.mutateAsync(payload)
|
||||
await queryClient.invalidateQueries({ queryKey: authKeys.profile() })
|
||||
await queryClient.invalidateQueries({ queryKey: authKeys.me() })
|
||||
toast.success('پروفایل با موفقیت بهروز شد')
|
||||
router.push({ name: 'student-dashboard' })
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user