Skip to content

Commit

Permalink
fix: thumbnail display (#308)
Browse files Browse the repository at this point in the history
fix: problem with thumbnail
  • Loading branch information
mateuszszczecina authored Dec 23, 2024
1 parent 7ba3390 commit 094ffa1
Show file tree
Hide file tree
Showing 9 changed files with 62 additions and 42 deletions.
12 changes: 6 additions & 6 deletions apps/api/src/courses/course.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -447,7 +447,7 @@ export class CourseService {
.select({
id: courses.id,
title: courses.title,
thumbnailUrl: sql<string>`COALESCE(${courses.thumbnailS3Key}, '')`,
thumbnailS3Key: sql<string>`COALESCE(${courses.thumbnailS3Key}, '')`,
category: categories.title,
categoryId: categories.id,
description: sql<string>`${courses.description}`,
Expand Down Expand Up @@ -489,7 +489,7 @@ export class CourseService {
return await this.fileService.getFileUrl(url);
};

const thumbnailUrl = await getImageUrl(course.thumbnailUrl);
const thumbnailS3SingedUrl = await getImageUrl(course.thumbnailS3Key);

const updatedCourseLessonList = await Promise.all(
courseChapterList?.map(async (chapter) => {
Expand All @@ -507,7 +507,7 @@ export class CourseService {

return {
...course,
thumbnailUrl,
thumbnailS3SingedUrl,
chapters: updatedCourseLessonList ?? [],
};
}
Expand All @@ -517,7 +517,7 @@ export class CourseService {
.select({
id: courses.id,
title: courses.title,
thumbnailUrl: sql<string>`${courses.thumbnailS3Key}`,
thumbnailS3Key: sql<string>`${courses.thumbnailS3Key}`,
category: categories.title,
categoryId: categories.id,
description: sql<string>`${courses.description}`,
Expand Down Expand Up @@ -556,11 +556,11 @@ export class CourseService {
return await this.fileService.getFileUrl(url);
};

const thumbnailUrl = await getImageUrl(course.thumbnailUrl);
const thumbnailS3SingedUrl = await getImageUrl(course.thumbnailS3Key);

return {
...course,
thumbnailUrl,
thumbnailS3SingedUrl,
chapters: courseChapterList,
};
}
Expand Down
2 changes: 2 additions & 0 deletions apps/api/src/courses/schemas/showCourseCommon.schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ export const commonShowCourseSchema = Type.Object({
isScorm: Type.Optional(Type.Boolean()),
priceInCents: Type.Number(),
thumbnailUrl: Type.Optional(Type.String()),
thumbnailS3Key: Type.Optional(Type.String()),
thumbnailS3SingedUrl: Type.Optional(Type.String()),
title: Type.String(),
});

Expand Down
4 changes: 2 additions & 2 deletions apps/api/src/seed/seed-helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,8 @@ export async function createNiceCourses(
lessonData.type === LESSON_TYPES.presentation
? "pptx"
: lessonData.type === LESSON_TYPES.video
? "mp4"
: null,
? "mp4"
: null,
chapterId: chapter.id,
createdAt: createdAt,
updatedAt: createdAt,
Expand Down
18 changes: 18 additions & 0 deletions apps/api/src/swagger/api-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -3711,6 +3711,12 @@
"thumbnailUrl": {
"type": "string"
},
"thumbnailS3Key": {
"type": "string"
},
"thumbnailS3SingedUrl": {
"type": "string"
},
"title": {
"type": "string"
}
Expand Down Expand Up @@ -3857,6 +3863,12 @@
"thumbnailUrl": {
"type": "string"
},
"thumbnailS3Key": {
"type": "string"
},
"thumbnailS3SingedUrl": {
"type": "string"
},
"title": {
"type": "string"
}
Expand Down Expand Up @@ -4003,6 +4015,12 @@
"thumbnailUrl": {
"type": "string"
},
"thumbnailS3Key": {
"type": "string"
},
"thumbnailS3SingedUrl": {
"type": "string"
},
"title": {
"type": "string"
}
Expand Down
8 changes: 6 additions & 2 deletions apps/web/app/api/generated-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -467,6 +467,8 @@ export interface GetCourseResponse {
isScorm?: boolean;
priceInCents: number;
thumbnailUrl?: string;
thumbnailS3Key?: string;
thumbnailS3SingedUrl?: string;
title: string;
};
}
Expand Down Expand Up @@ -506,6 +508,8 @@ export interface GetCourseByIdResponse {
isScorm?: boolean;
priceInCents: number;
thumbnailUrl?: string;
thumbnailS3Key?: string;
thumbnailS3SingedUrl?: string;
title: string;
};
}
Expand Down Expand Up @@ -545,6 +549,8 @@ export interface GetBetaCourseByIdResponse {
isScorm?: boolean;
priceInCents: number;
thumbnailUrl?: string;
thumbnailS3Key?: string;
thumbnailS3SingedUrl?: string;
title: string;
};
}
Expand Down Expand Up @@ -1687,8 +1693,6 @@ export class API<SecurityDataType extends unknown> extends HttpClient<SecurityDa
*/
courseControllerGetStudentCourses: (
query?: {
/** @format uuid */
excludeCourseId?: string;
title?: string;
category?: string;
author?: string;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useCallback, useMemo, useState } from "react";
import { useCallback, useEffect, useMemo, useState } from "react";

import { useUploadFile } from "~/api/mutations/admin/useUploadFile";
import { useCategoriesSuspense } from "~/api/queries/useCategories";
Expand Down Expand Up @@ -26,30 +26,34 @@ type CourseSettingsProps = {
title?: string;
description?: string;
categoryId?: string;
imageUrl?: string;
thumbnailS3SingedUrl?: string;
thumbnailS3Key?: string;
};
const CourseSettings = ({
courseId,
title,
description,
categoryId,
imageUrl,
thumbnailS3SingedUrl,
thumbnailS3Key,
}: CourseSettingsProps) => {
const { form, onSubmit } = useCourseSettingsForm({
title,
description,
categoryId,
imageUrl,
thumbnailS3Key,
courseId: courseId || "",
});
const { data: categories } = useCategoriesSuspense();
const [isUploading, setIsUploading] = useState(false);
const { mutateAsync: uploadFile } = useUploadFile();
const isFormValid = form.formState.isValid;
const [displayThumbnailUrl, setDisplayThumbnailUrl] = useState<string | undefined>(
thumbnailS3SingedUrl || undefined,
);

const watchedTitle = form.watch("title");
const watchedDescription = form.watch("description");
const watchedImageUrl = form.watch("imageUrl");
const watchedCategoryId = form.getValues("categoryId");

const categoryName = useMemo(() => {
Expand All @@ -61,7 +65,8 @@ const CourseSettings = ({
setIsUploading(true);
try {
const result = await uploadFile({ file, resource: "course" });
form.setValue("imageUrl", result.fileUrl, { shouldValidate: true });
form.setValue("thumbnailS3Key", result.fileKey, { shouldValidate: true });
setDisplayThumbnailUrl(result.fileUrl);
} catch (error) {
console.error("Error uploading image:", error);
} finally {
Expand All @@ -71,6 +76,11 @@ const CourseSettings = ({
[form, uploadFile],
);

const removeThumbnail = () => {
form.setValue("thumbnailS3Key", "");
setDisplayThumbnailUrl(undefined);
};

return (
<div className="w-full flex h-full gap-x-6">
<div className="w-full basis-full">
Expand Down Expand Up @@ -121,16 +131,16 @@ const CourseSettings = ({
/>
<FormField
control={form.control}
name="imageUrl"
name="thumbnailS3Key"
render={({ field }) => (
<FormItem className="max-h-[440px]">
<Label htmlFor="imageUrl">Thumbnail</Label>
<Label htmlFor="thumbnailS3Key">Thumbnail</Label>
<FormControl>
<ImageUploadInput
field={field}
handleImageUpload={handleImageUpload}
isUploading={isUploading}
imageUrl={imageUrl}
imageUrl={displayThumbnailUrl}
/>
</FormControl>
{isUploading && <p>Uploading image...</p>}
Expand All @@ -139,11 +149,8 @@ const CourseSettings = ({
)}
/>
<div className="flex items-center justify-start gap-x-2">
{watchedImageUrl && (
<Button
onClick={() => form.setValue("imageUrl", "")}
className="bg-red-500 text-white py-2 px-6"
>
{displayThumbnailUrl && (
<Button onClick={removeThumbnail} className="bg-red-500 text-white py-2 px-6">
<Icon name="TrashIcon" className="mr-2" />
Remove Thumbnail
</Button>
Expand All @@ -160,7 +167,7 @@ const CourseSettings = ({
</div>
<div className="max-w-[480px] w-full">
<CourseCardPreview
imageUrl={watchedImageUrl}
imageUrl={displayThumbnailUrl}
title={watchedTitle}
description={watchedDescription}
category={categoryName}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { zodResolver } from "@hookform/resolvers/zod";
import { useForm } from "react-hook-form";

import { useDeleteFile } from "~/api/mutations/admin/useDeleteFile";
import { useUpdateCourse } from "~/api/mutations/admin/useUpdateCourse";
import { courseQueryOptions } from "~/api/queries/admin/useCourseById";
import { queryClient } from "~/api/queryClient";
Expand All @@ -14,46 +13,35 @@ type CourseSettingsProps = {
title?: string;
description?: string;
categoryId?: string;
imageUrl?: string;
thumbnailS3Key?: string;
courseId: string;
};

export const useCourseSettingsForm = ({
title,
description,
categoryId,
imageUrl,
thumbnailS3Key,
courseId,
}: CourseSettingsProps) => {
const { mutateAsync: updateCourse } = useUpdateCourse();

const { mutateAsync: deleteOldFile } = useDeleteFile();
const form = useForm<CourseSettingsFormValues>({
resolver: zodResolver(courseSettingsFormSchema),
defaultValues: {
title: title || "",
description: description || "",
categoryId: categoryId || "",
imageUrl: imageUrl || "",
thumbnailS3Key: thumbnailS3Key || "",
},
});

const newImageUrl = form.getValues("imageUrl");
const oldImageUrl = imageUrl ?? "";

const oldImageExist = Boolean(oldImageUrl);
const newImageExist = Boolean(newImageUrl);
const imageUrlChanged = oldImageExist && newImageExist && newImageUrl !== oldImageUrl;

const onSubmit = async (data: UpdateCourseBody) => {
updateCourse({
data: { ...data },
courseId,
}).then(() => {
queryClient.invalidateQueries(courseQueryOptions(courseId));
if (imageUrlChanged) {
deleteOldFile(oldImageUrl);
}
});
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ export const courseSettingsFormSchema = z.object({
title: z.string().min(2, "Title must be at least 2 characters."),
description: z.string().min(2, "Description must be at least 2 characters."),
categoryId: z.string().min(1, "Category is required"),
imageUrl: z.union([z.string().url("Invalid image URL"), z.string().length(0)]).optional(),
thumbnailS3Key: z.string().optional(),
});

export type CourseSettingsFormValues = z.infer<typeof courseSettingsFormSchema>;
3 changes: 2 additions & 1 deletion apps/web/app/modules/Admin/EditCourse/EditCourse.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,8 @@ const EditCourse = () => {
title={course?.title}
description={course?.description}
categoryId={course?.categoryId}
imageUrl={course?.thumbnailUrl}
thumbnailS3SingedUrl={course?.thumbnailS3SingedUrl}
thumbnailS3Key={course?.thumbnailS3Key}
/>
</TabsContent>
<TabsContent value="Curriculum" className="h-full overflow-hidden">
Expand Down

0 comments on commit 094ffa1

Please sign in to comment.