#11 - Add total hours per career, per category and per course.

This commit is contained in:
Luciano Giacchetta 2025-08-20 17:59:45 -03:00
parent 3fa78d78c8
commit 663b256112
5 changed files with 69 additions and 13 deletions

View File

@ -1,6 +1,7 @@
import directus from './directus'; import directus from './directus';
import { readItems, type Query } from '@directus/sdk'; import { readItems, type Query } from '@directus/sdk';
import type { CodyopsCareers, Careers } from '../types/codyops-careers'; import type { CodyopsCareers, Careers } from '../types/codyops-careers';
import { sumTimes } from '../utils/time';
export async function getCareers(): Promise<Careers[]> { export async function getCareers(): Promise<Careers[]> {
const careers = await directus.request( const careers = await directus.request(
@ -16,6 +17,11 @@ export async function getCareers(): Promise<Careers[]> {
'name', 'name',
'level', 'level',
'category', 'category',
{
modules: [
'duration'
]
}
], ],
}, },
], ],
@ -23,5 +29,41 @@ export async function getCareers(): Promise<Careers[]> {
], ],
}) })
); );
return careers;
const careersWithCalculatedHours = careers.map(career => {
let totalCareerMinutes = 0;
const coursesWithCalculatedHours = career.courses.map(courseItem => {
const course = courseItem.codyops_courses_id;
if (course && course.modules) {
const moduleDurations = course.modules
.map(module => module.duration)
.filter((duration): duration is string => duration !== undefined && duration !== null); // Filter out undefined/null
const { hours, minutes } = sumTimes(moduleDurations);
const totalCourseMinutes = (hours * 60) + minutes;
totalCareerMinutes += totalCourseMinutes;
return {
...courseItem,
codyops_courses_id: {
...course,
totalCourseHours: hours + (minutes / 60), // Store as decimal hours
totalCourseMinutes: totalCourseMinutes,
}
};
}
return courseItem;
});
const totalCareerHours = Math.floor(totalCareerMinutes / 60);
const remainingCareerMinutes = totalCareerMinutes % 60;
return {
...career,
courses: coursesWithCalculatedHours,
totalCareerHours: totalCareerHours + (remainingCareerMinutes / 60), // Store as decimal hours
totalCareerMinutes: totalCareerMinutes,
};
});
return careersWithCalculatedHours;
} }

View File

@ -48,7 +48,7 @@ const FeaturesComponent = (await import(`../../sections/${career.slug}/${career.
<DescriptionComponent /> <DescriptionComponent />
</CareerSection> </CareerSection>
<Cta /> <Cta />
<CareerProgram list={career.courses.map(c => c.codyops_courses_id)} /> <CareerProgram career={career} />
<Cta /> <Cta />
</Main> </Main>
</Root> </Root>

View File

@ -1,29 +1,39 @@
--- ---
import type { Courses } from '../../../types/codyops-courses'; import type { Courses } from '../../../types/codyops-courses';
import type { Careers } from '../../../types/codyops-careers';
import { toSnakeCase, fromSnakeCase } from '../../../utils'; import { toSnakeCase, fromSnakeCase } from '../../../utils';
type Props = { type Props = {
list?: Courses[]; career: Careers;
}; };
const { list }: Props = Astro.props; const { career }: Props = Astro.props;
// Group courses by category // Group courses by category
const groupedCourses = list?.reduce((acc, course) => { const groupedCourses = career.courses?.reduce((acc, courseItem) => {
const course = courseItem.codyops_courses_id;
if (course) {
const category = course.category; const category = course.category;
if (!acc[category]) { if (!acc[category]) {
acc[category] = []; acc[category] = { courses: [], totalCategoryMinutes: 0 };
}
acc[category].courses.push(course);
if (course.totalCourseMinutes) {
acc[category].totalCategoryMinutes += course.totalCourseMinutes;
}
} }
acc[category].push(course);
return acc; return acc;
}, {} as Record<string, Courses[]>); }, {} as Record<string, { courses: Courses[]; totalCategoryMinutes: number }>);
--- ---
<section id="program" class="container content-space-t-3 career__section"> <section id="program" class="container content-space-t-3 career__section">
<h2 class="career-subtitle text-white text-center mb-5">Programa de Carrera</h2> <h2 class="career-subtitle text-white text-center mb-5">Programa de Carrera</h2>
<div class="text-center text-white mb-4">
Total Carrera: {career.totalCareerHours?.toFixed(1)} horas
</div>
<div class="accordion accordion-btn-icon-start"> <div class="accordion accordion-btn-icon-start">
{groupedCourses && Object.entries(groupedCourses).map(([category, courses]) => ( {groupedCourses && Object.entries(groupedCourses).map(([category, { courses, totalCategoryMinutes }]) => (
<div class="accordion-item"> <div class="accordion-item">
<div class="accordion-header" id={`heading-${toSnakeCase(category)}`}> <div class="accordion-header" id={`heading-${toSnakeCase(category)}`}>
<a <a
@ -46,7 +56,7 @@ const groupedCourses = list?.reduce((acc, course) => {
<!-- End Col --> <!-- End Col -->
<div class="col-lg-6"> <div class="col-lg-6">
{/* Hours will be calculated and displayed here if needed */} <span class="small text-white">{(totalCategoryMinutes / 60).toFixed(1)} hours</span>
</div> </div>
<!-- End Col --> <!-- End Col -->
</div> </div>
@ -87,7 +97,7 @@ const groupedCourses = list?.reduce((acc, course) => {
<!-- End Col --> <!-- End Col -->
<div class="col-lg-6"> <div class="col-lg-6">
{/* Hours will be displayed here if needed */} <span class="small text-white">{course.totalCourseHours?.toFixed(1)} hours</span>
</div> </div>
<!-- End Col --> <!-- End Col -->
</div> </div>

View File

@ -15,6 +15,8 @@ export interface Careers {
courses: { courses: {
codyops_courses_id: Courses; codyops_courses_id: Courses;
}[]; }[];
totalCareerHours?: number;
totalCareerMinutes?: number;
} }
export interface CodyopsCareers { export interface CodyopsCareers {

View File

@ -25,6 +25,8 @@ export interface Courses {
codyops_careers?: { codyops_careers?: {
codyops_careers_id?: Partial<Careers>; codyops_careers_id?: Partial<Careers>;
}; };
totalCourseHours?: number;
totalCourseMinutes?: number;
} }
export interface CodyopsCourses { export interface CodyopsCourses {