Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added Education page showing my education history #368

Merged
merged 32 commits into from
Apr 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
68dcff9
FEATURE: Created interfaces for education page
mbeps Apr 1, 2024
3bb19d4
FEATURES: Created enums needed for the databases
mbeps Apr 1, 2024
33140e3
Created database for modules and course
mbeps Apr 5, 2024
bb0bc23
FEATURE: Created education page
mbeps Apr 5, 2024
3c5ce86
FEATURE: Created initial skeleton for single education entry
mbeps Apr 6, 2024
14d2e5a
FEATURE: Added skills table to the single education page
mbeps Apr 6, 2024
63b2007
Removed unnecessary heading
mbeps Apr 6, 2024
e207bcb
FEATURE: Created module page
mbeps Apr 6, 2024
56cffc4
BUG FIX: Grid component wasn't using default gap
mbeps Apr 6, 2024
cb02cd5
REFACTOR: Using const for skill page instead of hard coding `/skill`
mbeps Apr 6, 2024
75fd5dd
FEATURE: Added related modules in the skill page
mbeps Apr 6, 2024
1849c7b
FEATURE: Display module score if it exists
mbeps Apr 11, 2024
b4b6847
Cleaned database
mbeps Apr 14, 2024
09ed550
FEATURE: Added breadcrumb to the module page to go back to the course…
mbeps Apr 14, 2024
3cd24c9
Removed view all button if base path is not passed
mbeps Apr 14, 2024
b709ce8
REFACTOR: Separated section for displaying materials into its own com…
mbeps Apr 14, 2024
eeb2d46
DOC: Added documentation for the new code
mbeps Apr 14, 2024
299dc62
Added missing related materials to modules
mbeps Apr 14, 2024
ec36319
Changed how materials are displayed and added materials section to mo…
mbeps Apr 14, 2024
2587920
FEATURE: Added related material view to projects, certificates, blogs…
mbeps Apr 14, 2024
4b52ab7
Instead of having a total number of skills being displayed overall, w…
mbeps Apr 14, 2024
c7c8853
FEATURE: Added toggle to show archived modules
mbeps Apr 14, 2024
edffe47
Fixed spacing on mobile for course page
mbeps Apr 14, 2024
5d31154
Machine Learning assignment 1have improved names
mbeps Apr 14, 2024
a3e3bcb
Cleaned code
mbeps Apr 14, 2024
34b664c
Added default tab for material list and made certificates default for…
mbeps Apr 15, 2024
f215d70
Added missing education page to breadcrumbs on the modules page
mbeps Apr 15, 2024
888d7b3
REFACTOR: Created dynamic breadcrumb component
mbeps Apr 15, 2024
92badf7
Upgraded dependencies
mbeps Apr 15, 2024
14940f6
Added message above related material to all pages
mbeps Apr 15, 2024
2c45ee9
Fixed certificate padding on the course page
mbeps Apr 15, 2024
1b19db1
Removed home button from the navbar since the logo can be used as a h…
mbeps Apr 15, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import UniversityModuleKeysEnum from "@/enums/DatabaseKeysEnums/UniversityModuleKeysEnum";
import UniversityCourseInterface from "@/interfaces/material/UniversityCourseInterface";
import UniversityModuleInterface from "@/interfaces/material/UniversityModuleInterface";

export default function aggregateRelatedMaterialsForCourses(
coursesDatabase: Database<UniversityCourseInterface>,
modulesDatabase: Database<UniversityModuleInterface>
): Database<UniversityCourseInterface> {
// Create a new object to store the updated courses with aggregated related materials
const updatedCoursesDatabase: Database<UniversityCourseInterface> = {};

// Iterate over each course in the database
Object.keys(coursesDatabase).forEach((courseKey) => {
const course: UniversityCourseInterface = coursesDatabase[courseKey];

// Start with existing related materials in the course, if any
let aggregatedMaterials: string[] = course.relatedMaterials
? [...course.relatedMaterials]
: [];

// Iterate over each module key in the course
course.modules.forEach((moduleKey: UniversityModuleKeysEnum) => {
const moduleData: UniversityModuleInterface = modulesDatabase[moduleKey];
// Ensure the moduleData exists and has related materials
if (moduleData && moduleData.relatedMaterials) {
// Aggregate the related materials
aggregatedMaterials = [
...aggregatedMaterials,
...moduleData.relatedMaterials,
];
}
});

// Remove duplicate related materials if necessary
aggregatedMaterials = Array.from(new Set(aggregatedMaterials));

// Update the course object with the aggregated related materials and add it to the updated database
updatedCoursesDatabase[courseKey] = {
...course,
relatedMaterials: aggregatedMaterials,
};
});

// Return the updated courses database with the aggregated related materials
return updatedCoursesDatabase;
}
38 changes: 38 additions & 0 deletions actions/material/course/aggregate/aggregateSkillsForCourse.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import SkillKeysEnum from "@/enums/DatabaseKeysEnums/SkillKeysEnum";
import UniversityCourseInterface from "@/interfaces/material/UniversityCourseInterface";
import UniversityModuleInterface from "@/interfaces/material/UniversityModuleInterface";

/**
* Adds the skills a course's modules to the course's skills itself.
* All the skills that are related to a module are also related to the course.
*
* @param coursesDatabase Courses to which the skills are to be added.
* @param modulesDatabase All the modules to access the data related to the modules.
* @returns The courses with the aggregated skills.
*/
export default function aggregateSkillsForCourse(
course: UniversityCourseInterface,
modulesDatabase: Database<UniversityModuleInterface>
): UniversityCourseInterface {
// Start with existing skills in the course, if any
let aggregatedSkills: SkillKeysEnum[] = [...course.skills];

// Iterate over each module key in the course
course.modules.forEach((moduleKey) => {
const moduleData: UniversityModuleInterface = modulesDatabase[moduleKey]; // Avoid using 'module' as a variable name
// Ensure the moduleData exists and has skills
if (moduleData && moduleData.skills) {
// Aggregate the skills
aggregatedSkills = [...aggregatedSkills, ...moduleData.skills];
}
});

// Remove duplicate skills if necessary
aggregatedSkills = Array.from(new Set(aggregatedSkills));

// Return the course object with the aggregated skills
return {
...course,
skills: aggregatedSkills,
};
}
51 changes: 51 additions & 0 deletions actions/material/course/aggregate/aggregateSkillsForCourses.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import SkillKeysEnum from "@/enums/DatabaseKeysEnums/SkillKeysEnum";
import UniversityModuleKeysEnum from "@/enums/DatabaseKeysEnums/UniversityModuleKeysEnum";
import UniversityCourseInterface from "@/interfaces/material/UniversityCourseInterface";
import UniversityModuleInterface from "@/interfaces/material/UniversityModuleInterface";

/**
* Adds the skills from a course's modules to the course's skills itself.
* This works multiple courses at once.
* All the skills that are related to a module are also related to the course.
*
* @param coursesDatabase Courses to which the skills are to be added.
* @param modulesDatabase All the modules to access the data related to the modules.
* @returns The courses with the aggregated skills.
*/
export default function aggregateSkillsForCourses(
coursesDatabase: Database<UniversityCourseInterface>,
modulesDatabase: Database<UniversityModuleInterface>
): Database<UniversityCourseInterface> {
// Create a new object to store the updated courses with aggregated skills
const updatedCoursesDatabase: Database<UniversityCourseInterface> = {};

// Iterate over each course in the database
Object.keys(coursesDatabase).forEach((courseKey) => {
const course: UniversityCourseInterface = coursesDatabase[courseKey];

// Start with existing skills in the course, if any
let aggregatedSkills: SkillKeysEnum[] = [...course.skills];

// Iterate over each module key in the course
course.modules.forEach((moduleKey: UniversityModuleKeysEnum) => {
const moduleData: UniversityModuleInterface = modulesDatabase[moduleKey];
// Ensure the moduleData exists and has skills
if (moduleData && moduleData.skills) {
// Aggregate the skills
aggregatedSkills = [...aggregatedSkills, ...moduleData.skills];
}
});

// Remove duplicate skills if necessary
aggregatedSkills = Array.from(new Set(aggregatedSkills));

// Update the course object with the aggregated skills and add it to the updated database
updatedCoursesDatabase[courseKey] = {
...course,
skills: aggregatedSkills,
};
});

// Return the updated courses database with the aggregated skills
return updatedCoursesDatabase;
}
15 changes: 15 additions & 0 deletions actions/material/course/findCourseKeyForModule.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import UniversityModuleKeysEnum from "@/enums/DatabaseKeysEnums/UniversityModuleKeysEnum";
import UniversityCourseInterface from "@/interfaces/material/UniversityCourseInterface";

export default function findCourseKeyForModule(
moduleKey: UniversityModuleKeysEnum,
coursesDatabase: Database<UniversityCourseInterface>
): string | null {
// Iterate through the courses to find the one related to the specified module
for (const [courseKey, course] of Object.entries(coursesDatabase)) {
if (course.modules.includes(moduleKey)) {
return courseKey; // Return the key of the course related to the module
}
}
return null; // Return null if no related course is found
}
7 changes: 1 addition & 6 deletions actions/material/group/groupMaterialsByMaterialType.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,7 @@
import MaterialType from "@/enums/MaterialType";
import MaterialGroupInterface from "@/interfaces/material/MaterialGroupInterface";
import MaterialInterface from "@/interfaces/material/MaterialInterface";

export enum MaterialType {
Projects = "Projects",
Certificates = "Certificates",
Blogs = "Blogs",
}

/**
* Groups the materials based on the material type as defined in {@link MaterialType}.
* A name for the group is provided.
Expand Down
37 changes: 25 additions & 12 deletions app/blogs/[slug]/page.tsx → app/blogs/[blogKey]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import getMarkdownFromFileSystem from "@/actions/file-system/getMarkdownFromFileSystem";
import filterSkillsByType from "@/actions/skills/filter/filterSkillsByType";
import categoriseAndGroupSkills from "@/actions/skills/group/categoriseAndGroupSkills";
import MaterialList from "@/components/MaterialLists/MaterialList";
import Reader from "@/components/Reader/Reader";
import SkillTableSection from "@/components/Skills/SkillTableSection";
import HeadingTwo from "@/components/Text/HeadingTwo";
import PageDescription from "@/components/UI/PageDescription";
import developerName from "@/constants/developerName";
import { BLOG_PAGE } from "@/constants/pages";
import blogDatabase from "@/database/blogs";
import certificateDatabase from "@/database/certificates";
import skillDatabase from "@/database/skills";
import SkillKeysEnum from "@/enums/DatabaseKeysEnums/SkillKeysEnum";
import SkillTypesEnum from "@/enums/SkillTypesEnum";
Expand All @@ -15,7 +18,7 @@ import type { Metadata, ResolvingMetadata } from "next";
import { notFound } from "next/navigation";

type BlogPageProps = {
params: { slug: string };
params: { blogKey: string };
searchParams: { [key: string]: string | string[] | undefined };
};

Expand All @@ -33,7 +36,7 @@ export async function generateMetadata(
{ params, searchParams }: BlogPageProps,
parent: ResolvingMetadata
): Promise<Metadata> {
const blogKey: string = params.slug;
const blogKey: string = params.blogKey;
const blog: BlogInterface = blogDatabase[blogKey];

return {
Expand All @@ -53,8 +56,8 @@ export async function generateMetadata(
* @see https://nextjs.org/docs/app/building-your-application/optimizing/metadata
*/
export const generateStaticParams = async () => {
return Object.keys(blogDatabase).map((slug) => ({
slug,
return Object.keys(blogDatabase).map((blogKey) => ({
blogKey,
}));
};

Expand All @@ -66,29 +69,29 @@ export const generateStaticParams = async () => {
* @returns Content of the blog and the skills used
*/
const BlogPage: React.FC<BlogPageProps> = ({ params }) => {
const blogKey: string = params.slug;
const blogKey: string = params.blogKey;
const basePath: string = BLOG_PAGE.path;
const blogMetadata: BlogInterface = blogDatabase[blogKey];
const blogData: BlogInterface = blogDatabase[blogKey];
const blogContent: string | undefined = getMarkdownFromFileSystem(
`public${basePath}/${blogKey}/blog.md`
)?.content;

if (!blogContent || !blogMetadata) {
if (!blogContent || !blogData) {
notFound();
}

const technologies: SkillKeysEnum[] = filterSkillsByType(
blogMetadata.skills,
blogData.skills,
skillDatabase,
SkillTypesEnum.Hard
);
const generalSkills: SkillKeysEnum[] = filterSkillsByType(
blogMetadata.skills,
blogData.skills,
skillDatabase,
SkillTypesEnum.General
);
const softSkills: SkillKeysEnum[] = filterSkillsByType(
blogMetadata.skills,
blogData.skills,
skillDatabase,
SkillTypesEnum.Soft
);
Expand Down Expand Up @@ -118,9 +121,9 @@ const BlogPage: React.FC<BlogPageProps> = ({ params }) => {
return (
<div>
<div className="text-center">
<HeadingTwo title={blogMetadata?.name} />
<HeadingTwo title={blogData?.name} />
<p className="text-neutral-600 dark:text-neutral-400">
{blogMetadata?.subtitle}
{blogData?.subtitle}
</p>
</div>

Expand All @@ -131,6 +134,16 @@ const BlogPage: React.FC<BlogPageProps> = ({ params }) => {
<div className="mt-4">
<SkillTableSection allGroupedSkills={allGroupedSkills} />
</div>

{blogData.relatedMaterials && blogData.relatedMaterials.length > 0 && (
<>
<div className="border-b border-gray-200 dark:border-neutral-600 pb-4" />
<PageDescription
description={`List of material directly related to ${certificateDatabase.name}`}
/>
<MaterialList materialKeys={blogData.relatedMaterials} />
</>
)}
</div>
);
};
Expand Down
Loading
Loading