Skip to content

Commit 799b577

Browse files
author
Rajat
committed
feat: add course discussions
1 parent e37f8ad commit 799b577

46 files changed

Lines changed: 9102 additions & 31 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

apps/web/app/(with-contexts)/course/[slug]/[id]/__tests__/layout-with-sidebar.test.tsx

Lines changed: 184 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,28 @@
1+
let mockPathname = "/course/test-course/course-1";
2+
13
jest.mock("next/navigation", () => ({
2-
usePathname: () => "/course/test-course/course-1",
4+
usePathname: () => mockPathname,
5+
useRouter: () => ({ push: jest.fn() }),
36
useSearchParams: () => new URLSearchParams(),
47
}));
58

69
jest.mock("next/link", () => {
7-
return ({ children }: { children: React.ReactNode }) => children;
10+
function MockLink({
11+
children,
12+
href,
13+
...props
14+
}: {
15+
children: React.ReactNode;
16+
href: string;
17+
}) {
18+
return (
19+
<a href={href} {...props}>
20+
{children}
21+
</a>
22+
);
23+
}
24+
25+
return MockLink;
826
});
927

1028
jest.mock("@components/contexts", () => {
@@ -25,6 +43,10 @@ jest.mock("@components/contexts", () => {
2543
ThemeContext: React.createContext({
2644
theme: {},
2745
}),
46+
AddressContext: React.createContext({
47+
backend: "http://localhost:3000",
48+
frontend: "http://localhost:3000",
49+
}),
2850
};
2951
});
3052

@@ -41,7 +63,12 @@ jest.mock("@components/ui/sidebar", () => ({
4163
SidebarMenuItem: ({ children }: any) => children,
4264
SidebarProvider: ({ children }: any) => children,
4365
SidebarTrigger: () => null,
44-
useSidebar: () => ({ openMobile: false }),
66+
useSidebar: () => ({
67+
open: false,
68+
openMobile: false,
69+
isMobile: false,
70+
setOpenMobile: jest.fn(),
71+
}),
4572
}));
4673

4774
jest.mock("@components/ui/tooltip", () => ({
@@ -63,10 +90,21 @@ jest.mock("@components/ui/button", () => ({
6390

6491
jest.mock("@components/admin/next-theme-switcher", () => () => null);
6592

93+
jest.mock("@/components/public/product-discussions/panel", () => () => null);
94+
6695
jest.mock("@courselit/components-library", () => ({
6796
Image: () => null,
6897
}));
6998

99+
jest.mock("@courselit/page-blocks", () => ({
100+
TextRenderer: () => null,
101+
}));
102+
103+
jest.mock("@courselit/text-editor", () => ({
104+
Editor: () => null,
105+
emptyDoc: {},
106+
}));
107+
70108
jest.mock("@courselit/icons", () => ({
71109
CheckCircled: () => null,
72110
Circle: () => null,
@@ -77,7 +115,9 @@ jest.mock("lucide-react", () => ({
77115
BookOpen: () => null,
78116
ChevronRight: () => null,
79117
Clock: () => null,
118+
Folder: () => null,
80119
LogOutIcon: () => null,
120+
MessageSquare: () => null,
81121
}));
82122

83123
jest.mock("@courselit/page-primitives", () => ({
@@ -797,6 +837,10 @@ describe("generateSideBarItems", () => {
797837
});
798838

799839
describe("Course viewer layout", () => {
840+
beforeEach(() => {
841+
mockPathname = "/course/test-course/course-1";
842+
});
843+
800844
it("renders the preview badge in the viewer header when preview mode is active", () => {
801845
const course = {
802846
title: "Course",
@@ -823,4 +867,141 @@ describe("Course viewer layout", () => {
823867

824868
expect(screen.getByText("Preview")).toBeInTheDocument();
825869
});
870+
871+
it("shows the discussions sidebar item only when discussions are enabled", () => {
872+
const course = {
873+
title: "Course",
874+
description: "",
875+
featuredImage: undefined,
876+
updatedAt: new Date().toISOString(),
877+
creatorId: "creator-1",
878+
slug: "test-course",
879+
cost: 0,
880+
courseId: "course-1",
881+
tags: [],
882+
paymentPlans: [],
883+
defaultPaymentPlan: "",
884+
firstLesson: "lesson-1",
885+
groups: [],
886+
discussions: false,
887+
} as unknown as CourseFrontend;
888+
889+
const profile = {
890+
userId: "user-1",
891+
purchases: [
892+
{
893+
courseId: "course-1",
894+
accessibleGroups: [],
895+
},
896+
],
897+
} as unknown as Profile;
898+
899+
expect(
900+
generateSideBarItems(
901+
course,
902+
profile,
903+
"/course/test-course/course-1",
904+
).some((item) => item.title === "Discussions"),
905+
).toBe(false);
906+
907+
expect(
908+
generateSideBarItems(
909+
{ ...course, discussions: true } as CourseFrontend,
910+
profile,
911+
"/course/test-course/course-1/discussions",
912+
).find((item) => item.title === "Discussions"),
913+
).toMatchObject({
914+
href: "/course/test-course/course-1/discussions",
915+
isActive: true,
916+
});
917+
});
918+
919+
it("does not show a discussions header action on the course overview page", () => {
920+
const course = {
921+
title: "Course",
922+
description: "",
923+
featuredImage: undefined,
924+
updatedAt: new Date().toISOString(),
925+
creatorId: "creator-1",
926+
slug: "test-course",
927+
cost: 0,
928+
courseId: "course-1",
929+
tags: [],
930+
paymentPlans: [],
931+
defaultPaymentPlan: "",
932+
firstLesson: "lesson-1",
933+
isPreview: false,
934+
groups: [],
935+
discussions: true,
936+
} as unknown as CourseFrontend;
937+
938+
render(
939+
<ProductPage product={course}>
940+
<div>Course body</div>
941+
</ProductPage>,
942+
);
943+
944+
expect(screen.queryByLabelText("Discussions")).not.toBeInTheDocument();
945+
});
946+
947+
it("does not show a discussions header action on the discussions hub page", () => {
948+
mockPathname = "/course/test-course/course-1/discussions";
949+
const course = {
950+
title: "Course",
951+
description: "",
952+
featuredImage: undefined,
953+
updatedAt: new Date().toISOString(),
954+
creatorId: "creator-1",
955+
slug: "test-course",
956+
cost: 0,
957+
courseId: "course-1",
958+
tags: [],
959+
paymentPlans: [],
960+
defaultPaymentPlan: "",
961+
firstLesson: "lesson-1",
962+
isPreview: false,
963+
groups: [],
964+
discussions: true,
965+
} as unknown as CourseFrontend;
966+
967+
render(
968+
<ProductPage product={course}>
969+
<div>Discussions body</div>
970+
</ProductPage>,
971+
);
972+
973+
expect(screen.queryByLabelText("Discussions")).not.toBeInTheDocument();
974+
});
975+
976+
it("opens the discussion panel from lesson pages", () => {
977+
mockPathname = "/course/test-course/course-1/lesson-1";
978+
const course = {
979+
title: "Course",
980+
description: "",
981+
featuredImage: undefined,
982+
updatedAt: new Date().toISOString(),
983+
creatorId: "creator-1",
984+
slug: "test-course",
985+
cost: 0,
986+
courseId: "course-1",
987+
tags: [],
988+
paymentPlans: [],
989+
defaultPaymentPlan: "",
990+
firstLesson: "lesson-1",
991+
isPreview: false,
992+
groups: [],
993+
discussions: true,
994+
} as unknown as CourseFrontend;
995+
996+
render(
997+
<ProductPage product={course}>
998+
<div>Lesson body</div>
999+
</ProductPage>,
1000+
);
1001+
1002+
expect(screen.getByLabelText("Discussions")).toHaveAttribute(
1003+
"href",
1004+
"/course/test-course/course-1/lesson-1?discussion=open",
1005+
);
1006+
});
8261007
});

0 commit comments

Comments
 (0)