Skip to content

Commit

Permalink
Merge pull request #368 from mbeps/development
Browse files Browse the repository at this point in the history
Added Education page showing my education history
  • Loading branch information
mbeps authored Apr 15, 2024
2 parents f0fd478 + 1b19db1 commit a629f97
Show file tree
Hide file tree
Showing 48 changed files with 2,657 additions and 493 deletions.
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

0 comments on commit a629f97

Please sign in to comment.