fix: courseNo vs coursesNo mismatch on course save
This commit is contained in:
+1
-1
@@ -19,7 +19,7 @@
|
|||||||
let role = $state(get(course, 'metadata.instructor.role'));
|
let role = $state(get(course, 'metadata.instructor.role'));
|
||||||
let imgUrl = $state(get(course, 'metadata.instructor.imgUrl'));
|
let imgUrl = $state(get(course, 'metadata.instructor.imgUrl'));
|
||||||
let description = $state(get(course, 'metadata.instructor.description'));
|
let description = $state(get(course, 'metadata.instructor.description'));
|
||||||
let courseNo = $state(get(course, 'metadata.instructor.coursesNo'));
|
let courseNo = $state(get(course, 'metadata.instructor.coursesNo') ?? get(course, 'metadata.instructor.courseNo'));
|
||||||
let avatar: File | undefined = $state();
|
let avatar: File | undefined = $state();
|
||||||
let isUploading = $state(false);
|
let isUploading = $state(false);
|
||||||
|
|
||||||
|
|||||||
@@ -273,10 +273,39 @@ export const ZCourseReward = z.object({
|
|||||||
description: z.string()
|
description: z.string()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const METADATA_NULLABLE_STRING_KEYS = ['requirements', 'description', 'goals', 'videoUrl', 'paymentLink'] as const;
|
||||||
|
|
||||||
|
function preprocessCourseMetadata(value: unknown): unknown {
|
||||||
|
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
const metadata = { ...(value as Record<string, unknown>) };
|
||||||
|
|
||||||
|
for (const key of METADATA_NULLABLE_STRING_KEYS) {
|
||||||
|
if (metadata[key] === null) {
|
||||||
|
metadata[key] = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (metadata.instructor && typeof metadata.instructor === 'object' && !Array.isArray(metadata.instructor)) {
|
||||||
|
const instructor = { ...(metadata.instructor as Record<string, unknown>) };
|
||||||
|
|
||||||
|
if (instructor.coursesNo === undefined && instructor.courseNo !== undefined) {
|
||||||
|
instructor.coursesNo = instructor.courseNo;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete instructor.courseNo;
|
||||||
|
metadata.instructor = instructor;
|
||||||
|
}
|
||||||
|
|
||||||
|
return metadata;
|
||||||
|
}
|
||||||
|
|
||||||
export const ZCourseInstructor = z.object({
|
export const ZCourseInstructor = z.object({
|
||||||
name: z.string(),
|
name: z.string(),
|
||||||
role: z.string(),
|
role: z.string(),
|
||||||
coursesNo: z.number(),
|
coursesNo: z.coerce.number(),
|
||||||
description: z.string(),
|
description: z.string(),
|
||||||
imgUrl: z.string()
|
imgUrl: z.string()
|
||||||
});
|
});
|
||||||
@@ -302,8 +331,7 @@ export const ZCourseLessonTabsOrder = z.array(
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
// Course metadata schema matching the database structure
|
const ZCourseMetadataFields = z.object({
|
||||||
export const ZCourseMetadata = z.object({
|
|
||||||
requirements: z.string().optional(),
|
requirements: z.string().optional(),
|
||||||
description: z.string().optional(),
|
description: z.string().optional(),
|
||||||
goals: z.string().optional(),
|
goals: z.string().optional(),
|
||||||
@@ -324,29 +352,20 @@ export const ZCourseMetadata = z.object({
|
|||||||
sectionDisplay: z.record(z.string(), z.boolean()).optional(),
|
sectionDisplay: z.record(z.string(), z.boolean()).optional(),
|
||||||
isContentGroupingEnabled: z.boolean().optional()
|
isContentGroupingEnabled: z.boolean().optional()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Course metadata schema matching the database structure
|
||||||
|
export const ZCourseMetadata = z.preprocess(preprocessCourseMetadata, ZCourseMetadataFields);
|
||||||
export type TCourseMetadata = z.infer<typeof ZCourseMetadata>;
|
export type TCourseMetadata = z.infer<typeof ZCourseMetadata>;
|
||||||
|
|
||||||
export const ZCourseLandingPageMetadataUpdate = z.object({
|
export const ZCourseLandingPageMetadataUpdate = z.preprocess(
|
||||||
requirements: z.string().optional(),
|
preprocessCourseMetadata,
|
||||||
description: z.string().optional(),
|
ZCourseMetadataFields.omit({ allowNewStudent: true }).extend({
|
||||||
goals: z.string().optional(),
|
allowNewStudent: z.boolean().optional(),
|
||||||
videoUrl: z.string().optional(),
|
reward: ZCourseReward.partial().optional(),
|
||||||
showDiscount: z.boolean().optional(),
|
instructor: ZCourseInstructor.partial().optional(),
|
||||||
discount: z.number().optional(),
|
certificate: ZCourseCertificate.partial().optional()
|
||||||
paymentLink: z.string().optional(),
|
})
|
||||||
reward: ZCourseReward.partial().optional(),
|
);
|
||||||
instructor: ZCourseInstructor.partial().optional(),
|
|
||||||
certificate: ZCourseCertificate.partial().optional(),
|
|
||||||
reviews: z.array(ZCourseReview).optional(),
|
|
||||||
skills: z.array(z.string().min(1).max(80)).max(60).optional(),
|
|
||||||
tools: z.array(z.string().min(1).max(80)).max(60).optional(),
|
|
||||||
lessonTabsOrder: ZCourseLessonTabsOrder.optional(),
|
|
||||||
grading: z.boolean().optional(),
|
|
||||||
lessonDownload: z.boolean().optional(),
|
|
||||||
allowNewStudent: z.boolean().optional(),
|
|
||||||
sectionDisplay: z.record(z.string(), z.boolean()).optional(),
|
|
||||||
isContentGroupingEnabled: z.boolean().optional()
|
|
||||||
});
|
|
||||||
export type TCourseLandingPageMetadataUpdate = z.infer<typeof ZCourseLandingPageMetadataUpdate>;
|
export type TCourseLandingPageMetadataUpdate = z.infer<typeof ZCourseLandingPageMetadataUpdate>;
|
||||||
|
|
||||||
export const ZCertificationSettings = z.object({
|
export const ZCertificationSettings = z.object({
|
||||||
|
|||||||
Reference in New Issue
Block a user