Skip to content

Commit 718486d

Browse files
authored
Merge pull request #1269 from dacadeorg/ft/learning-module-card
feat: implement new learning module card design
2 parents e1925af + 133bbdc commit 718486d

File tree

13 files changed

+126
-77
lines changed

13 files changed

+126
-77
lines changed

.vscode/settings.json

Lines changed: 0 additions & 4 deletions
This file was deleted.

public/locales/bg/common.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,7 @@
190190
"communities.scoreboard.empty-state.title": "Няма оценки за тази категория.",
191191
"communities.card.estimated": "Estimated Time",
192192
"communities.card.earn": "Earn rewards",
193+
"communities.card.module": "Модул",
193194
"communities.card.submissions": "{{count}} Изявления",
194195
"communities.card.submission": "{{count}} Подчинение",
195196
"communities.card.courses": "in {{count}} Courses",
@@ -209,6 +210,7 @@
209210
"course.scoreboard.button": "Load more",
210211
"learning-module.material.open.lesson": "Open Lesson",
211212
"learning-module.material.open.article": "Open Article",
213+
"learning-module.course.other.appearances": "Също се появява в:",
212214
"partnering.card.text": "To arrange a meeting, just drop us a line.",
213215
"communities.navigation.all": "All communities",
214216
"testimonials.community.title": "Join our community",

public/locales/en/common.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,7 @@
193193
"communities.scoreboard.empty-state.title": "No scores for this category",
194194
"communities.card.estimated": "Estimated Time",
195195
"communities.card.earn": "Earn rewards",
196+
"communities.card.module": "Module",
196197
"communities.card.submissions": "{{count}} Submissions",
197198
"communities.card.submission": "{{count}} Submission",
198199
"communities.card.courses": "in {{count}} Courses",
@@ -213,6 +214,7 @@
213214
"course.scoreboard.button": "Load more",
214215
"learning-module.material.open.lesson": "Open Lesson",
215216
"learning-module.material.open.article": "Open Article",
217+
"learning-module.course.other.appearances": "Also appears in:",
216218
"partnering.card.text": "To arrange a meeting, just drop us a line.",
217219
"communities.navigation.all": "All communities",
218220
"testimonials.community.title": "Join our community",

public/locales/es/common.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,7 @@
193193
"communities.scoreboard.empty-state.title": "No hay puntuaciones para esta categoría.",
194194
"communities.card.estimated": "Tiempo estimado",
195195
"communities.card.earn": "Gane recompensas",
196+
"communities.card.module": "Módulo",
196197
"communities.card.submissions": "{{count}} Envíos",
197198
"communities.card.submission": "{{count}} Envío",
198199
"communities.card.courses": "en {{count}} Cursos",
@@ -211,6 +212,7 @@
211212
"course.scoreboard.button": "Cargar más",
212213
"learning-module.material.open.lesson": "Abrir lección",
213214
"learning-module.material.open.article": "Abrir artículo",
215+
"learning-module.course.other.appearances": "También aparece en:",
214216
"partnering.card.text": "Para concertar un encuentro, diríjase a nosotros.",
215217
"communities.navigation.all": "Todas las comunidades",
216218
"testimonials.community.title": "Únase a nuestra comunidad",

public/locales/hr/common.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@
163163
"communities.scoreboard.empty-state.title": "Nema bodova za ovu kategoriju.",
164164
"communities.card.estimated": "Estimated Time",
165165
"communities.card.earn": "Earn rewards",
166+
"communities.card.module": "Modul",
166167
"communities.overview.challenge.rewards": "Nagrade",
167168
"communities.overview.challenge.subtitle": "Nakon uspješnog završetka",
168169
"communities.overview.challenge.certificate": "Certificate",
@@ -209,6 +210,7 @@
209210
"course.scoreboard.button": "Load more",
210211
"learning-module.material.open.lesson": "Open Lesson",
211212
"learning-module.material.open.article": "Otvori članak",
213+
"learning-module.course.other.appearances": "Također se pojavljuje u:",
212214
"partnering.card.text": "To arrange a meeting, just drop us a line.",
213215
"communities.navigation.all": "All communities",
214216
"testimonials.community.title": "Join our community",

src/components/badges/Duration.tsx

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import DateManager from "@/utilities/DateManager";
2+
import classNames from "classnames";
3+
import { useRouter } from "next/router";
4+
import { useMemo } from "react";
5+
6+
export const DurationBadge = ({ value, type = "gray" }: { value: number, type?: string }) => {
7+
const router = useRouter();
8+
const duration = useMemo(() => {
9+
if (!value) {
10+
return 0;
11+
}
12+
if (isNaN(Number(value))) return value
13+
return DateManager.humanize(value, router.locale as string);
14+
}, [router.locale, value]);
15+
16+
return (
17+
<span className={classNames("text-xxs uppercase font-semibold px-2 rounded-3xl inline-block text-gray-500",
18+
{
19+
"bg-gray-200": type === 'gray',
20+
"border border-gray-200": type === "bordered"
21+
}
22+
)}>
23+
{duration}
24+
</span>
25+
)
26+
}
27+

src/components/cards/Learning.tsx

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import useNavigation from "@/hooks/useNavigation";
2-
import DateManager from "@/utilities/DateManager";
32
import { useRouter } from "next/router";
4-
import { ReactElement, useMemo } from "react";
3+
import { ReactElement } from "react";
4+
import { DurationBadge } from "../badges/Duration";
55

66
/**
77
* LearningModule interface
@@ -40,15 +40,6 @@ export default function Learning({ learningModule }: LearningProps): ReactElemen
4040
const router = useRouter();
4141
const navigation = useNavigation();
4242

43-
const duration = useMemo(() => {
44-
return (value: number) => {
45-
if (!value) {
46-
return 0;
47-
}
48-
return DateManager.humanize(value, router.locale as string);
49-
};
50-
}, [router.locale]);
51-
5243
const navigate = () => {
5344
const courseLink = navigation.community.learningModulePath(learningModule.id);
5445
router.push(courseLink);
@@ -58,10 +49,8 @@ export default function Learning({ learningModule }: LearningProps): ReactElemen
5849
<div className="px-5 pt-5 pb-8 bg-secondary rounded-3xl min-h-2xs w-full border-solid border-2 border-gray-100 md:mt-0 cursor-pointer">
5950
<div onClick={navigate} className="flex flex-col">
6051
<div className="w-full">
61-
<h4 className="font-medium block text-xl">{learningModule.title}</h4>
62-
{learningModule.duration && (
63-
<span className="text-xxs mt-4 uppercase font-semibold px-2 mb-2 bg-gray-200 rounded-3xl inline-block text-gray-500">{duration(learningModule.duration)}</span>
64-
)}
52+
<h4 className="font-medium block text-xl mb-4">{learningModule.title}</h4>
53+
{learningModule.duration && <DurationBadge type="bordered" value={learningModule.duration} />}
6554
</div>
6655
{learningModule.description && (
6756
<span className="text-sm mt-4 rounded-3xl">
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import { Fragment, useMemo } from "react";
2+
import ArrowButton from "@/components/ui/button/Arrow";
3+
import Link from "next/link";
4+
import { useTranslation } from "next-i18next";
5+
import Tag from "../ui/Tag";
6+
import { DurationBadge } from "@/components/badges/Duration";
7+
import { useMultiSelector } from "@/hooks/useTypedSelector";
8+
import { IRootState } from "@/store";
9+
import { LearningModule } from "@/types/course";
10+
11+
/**
12+
* Props for the RelatedLearning component.
13+
*/
14+
15+
/**
16+
* Component that displays related learning material with a title, description, and "Start now" button.
17+
*/
18+
export function LearningModuleCard({ data }: { data: LearningModule }): JSX.Element {
19+
const { t } = useTranslation()
20+
const { challenge, community, colors } = useMultiSelector<any, any>({
21+
challenge: (state: IRootState) => state.challenges.current,
22+
community: (state: IRootState) => state.communities.current,
23+
colors: (state: IRootState) => state.ui.colors
24+
})
25+
26+
const level = useMemo(() => {
27+
const value = challenge?.level;
28+
return t((value === 0 || value === 1) ? "course.challenge.level-0" : "course.challenge.level-2");
29+
}, [challenge?.level]);
30+
31+
const courses = data?.courses.map(course => ({ name: course.name, slug: course.slug }))
32+
33+
return (
34+
<div className="flex flex-col content-start w-full p-8 rounded-3xl group text-gray-700 border-solid border border-gray-200 gap-8">
35+
<div className="flex flex-wrap gap-2 text-xs items-center justify-between">
36+
<div className="gap-2 flex items-center">
37+
<div className="h-4.5 w-4.5 rounded-sm" style={{ backgroundColor: colors?.primary }} />
38+
<span className="uppercase font-semibold">{t("communities.card.module")}</span>
39+
</div>
40+
<div className="gap-2 flex items-center">
41+
{challenge.level && <Tag className="uppercase">{level}</Tag>}
42+
<DurationBadge value={data.duration} type="bordered" />
43+
</div>
44+
</div>
45+
46+
<div className="flex-grow flex flex-col gap-6">
47+
<div className="text-base font-medium leading-normal text-gray-900">{data.title}</div>
48+
<div className="text-sm font-normal text-gray-700 max-w-xxs">{data.description}</div>
49+
</div>
50+
51+
{courses.length ?
52+
<p className="font-medium text-gray text-tertiary text-sm">
53+
{t('learning-module.course.other.appearances')}
54+
{courses.map((course, index) =>
55+
<Fragment key={`related-course-${index}`}>
56+
<Link
57+
key={`other-appearance-course-${index}`}
58+
href={`/communities/${community.slug}/courses/${course?.slug}`}
59+
className="hover:underline ml-1">{course.name}
60+
</Link>
61+
{index !== courses.length - 1 && ","}
62+
</Fragment>
63+
)}
64+
</p>
65+
:
66+
<></>}
67+
68+
<div className="w-full mb-0 justify-self-end">
69+
<Link href={`/communities/${community.slug}/challenges/${challenge?.id}/learning-modules/${data.id}`}>
70+
<ArrowButton communityStyles={true} variant="outline-primary">
71+
{t("communities.overview.challenge.learning.start")}
72+
</ArrowButton>
73+
</Link>
74+
</div>
75+
</div>
76+
);
77+
};
78+

src/components/cards/challenge/_partials/RelatedLearning.tsx

Lines changed: 0 additions & 45 deletions
This file was deleted.

src/components/sections/challenges/Learning.tsx

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
1-
import React from "react";
21
import Accordion from "@/components/ui/accordion/Accordion";
32
import Section from "@/components/sections/communities/_partials/Section";
3+
import { LearningModuleCard } from "@/components/cards/LearningModule";
44
import CourseMaterial from "@/components/cards/course/CourseMaterial";
5-
import RelatedLearningCard from "@/components/cards/challenge/_partials/RelatedLearning";
65
import { Course, LearningModule } from "@/types/course";
76
import { Community } from "@/types/community";
8-
import { useSelector } from "@/hooks/useTypedSelector";
97
import { useTranslation } from "next-i18next";
108

119
/**
@@ -14,7 +12,6 @@ import { useTranslation } from "next-i18next";
1412
* @returns {JSX.Element} The Learning component JSX element.
1513
*/
1614
export default function Learning({ courses, learningModules, community }: { courses: Course[]; learningModules: LearningModule[]; community: Community }): JSX.Element {
17-
const challenge = useSelector((state) => state.challenges.current);
1815
const { t } = useTranslation();
1916
return (
2017
<Section>
@@ -38,13 +35,11 @@ export default function Learning({ courses, learningModules, community }: { cour
3835
/>
3936
))}
4037
</div>
41-
<div className="grid grid-cols-1 md:grid-cols-3 gap-3">
38+
<div className="grid grid-cols-1 md:grid-cols-2 gap-3">
4239
{learningModules?.map((learning) => (
43-
<RelatedLearningCard
40+
<LearningModuleCard
4441
key={`related-learning-card-${learning.id}`}
45-
title={learning.title}
46-
description={learning.description}
47-
path={`/communities/${community.slug}/challenges/${challenge?.id}/learning-modules/${learning.id}`}
42+
data={learning}
4843
/>
4944
))}
5045
</div>

0 commit comments

Comments
 (0)