Skip to content

Commit

Permalink
Merge pull request #795 from tutors-sdk/development
Browse files Browse the repository at this point in the history
support nested topics + tutors time fixes & adjustments
  • Loading branch information
edeleastar authored Sep 13, 2024
2 parents 1b3842d + b7d2913 commit faf277f
Show file tree
Hide file tree
Showing 45 changed files with 1,382 additions and 1,579 deletions.
19 changes: 19 additions & 0 deletions src/lib/services/models/course-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,25 @@ import { addIcon } from "$lib/ui/themes/styles/icon-lib";
import type { Composite, Course, IconNav, Lo, LoType, Topic } from "./lo-types";
import { filterByType, setShowHide } from "./lo-utils";

function threadToc(lo: Lo, course: Course) {
if (lo.type == "topic") {
const topic = lo as Topic;
topic.toc = [];
topic.toc.push(...topic.panels.panelVideos, ...topic.panels.panelTalks, ...topic.panels.panelNotes, ...topic.units.units, ...topic.units.standardLos, ...topic.units.sides);

topic.toc.forEach((lo) => {
lo.parentLo = course;
lo.parentTopic = topic;
if (lo.type === "unit" || lo.type === "side") {
const composite = lo as Composite;
composite.los.forEach((subLo) => {
subLo.parentTopic = topic;
});
}
});
}
}

export function createToc(course: Course) {
course.los.forEach((lo) => {
if (lo.type == "topic") {
Expand Down
19 changes: 16 additions & 3 deletions src/lib/services/models/lo-tree.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { isCompositeLo, type Course, type Lo, type Composite, type LoType, type Topic } from "./lo-types";
import { convertLoToHtml } from "./markdown-utils";
import { allVideoLos, crumbs, flattenLos, loadIcon, getPanels, getUnits, injectCourseUrl, removeUnknownLos } from "./lo-utils";
import { allVideoLos, crumbs, flattenLos, loadIcon, getPanels, getUnits, injectCourseUrl, removeUnknownLos, filterByType } from "./lo-utils";
import { createCompanions, createToc, createWalls, initCalendar, loadPropertyFlags } from "./course-utils";

export function decorateCourseTree(course: Course, courseId: string = "", courseUrl = "") {
Expand All @@ -26,12 +26,14 @@ export function decorateCourseTree(course: Course, courseId: string = "", course
const videoLos = allVideoLos(allLos);
videoLos.forEach((lo) => course.loIndex.set(lo.video, lo));
course.topicIndex = new Map<string, Topic>();
course.los.forEach((lo) => course.topicIndex.set(lo.route, lo as Topic));
//course.los.forEach((lo) => course.topicIndex.set(lo.route, lo as Topic));
const topicLos = filterByType(allLos, "topic");
topicLos.forEach((lo) => course.topicIndex.set(lo.route, lo as Topic));

loadPropertyFlags(course);
createCompanions(course);
createWalls(course);
createToc(course);
// createToc(course);
initCalendar(course);
}

Expand All @@ -51,6 +53,17 @@ export function decorateLoTree(course: Course, lo: Lo) {
const compositeLo = lo as Composite;
compositeLo.panels = getPanels(compositeLo.los);
compositeLo.units = getUnits(compositeLo.los);

compositeLo.toc = [];
compositeLo.toc.push(
...compositeLo?.panels?.panelVideos,
...compositeLo?.panels?.panelTalks,
...compositeLo?.panels?.panelNotes,
...compositeLo?.units?.units,
...compositeLo?.units?.standardLos,
...compositeLo?.units?.sides
);

for (const childLo of compositeLo.los) {
childLo.parentLo = lo;
if (compositeLo.los) {
Expand Down
2 changes: 1 addition & 1 deletion src/lib/services/models/lo-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,13 +155,13 @@ export type Units = {
};

export type Composite = Lo & {
toc: Lo[];
los: Lo[]; // child los
panels: Panels; // child panel los - paneltalks, panelvideos, panelnotes.
units: Units; // child units, including side units
};

export type Topic = Composite & {
toc: Lo[];
type: "topic";
};

Expand Down
231 changes: 193 additions & 38 deletions src/lib/services/types/supabase-metrics.ts
Original file line number Diff line number Diff line change
@@ -1,51 +1,206 @@
export interface CalendarMap {
date: string;
timeActive: number;
}

export interface LearningObject {
route: string;
loTitle: string;
parentLoTitle: string | undefined;
date: Date;
pageLoads: number;
timeActive: number;
nickname: string;
}

export interface LearningInteraction {
id?: Date;
loid?: string,
courseid: string,
studentid: string,
date: Date;
pageloads: number;
timeactive: number;
id?: Date;
loid?: string;
courseid: string;
studentid: string;
date: Date;
pageloads: number;
timeactive: number;
}

export interface GridConfig {
left: string | number;
right: string | number;
bottom: string | number;
top: string | number;
width: string | number;
height: string | number;
containLabel: boolean;
}

export type ChartType = {
type:
| "line"
| "bar"
| "pie"
| "scatter"
| "effectScatter"
| "radar"
| "tree"
| "treemap"
| "sunburst"
| "boxplot"
| "candlestick"
| "heatmap"
| "parallel"
| "lines"
| "graph"
| "sankey"
| "funnel"
| "gauge"
| "pictorialBar"
| "themeRiver"
| "calendar"
| "map"
| "custom";
};

export interface HeatMapSeriesData {
name: string;
type: string;
top: string;
data: number[][];
label: { show: boolean; };
export interface BackgroundColor {
image: HTMLImageElement;
repeat: "repeat";
}

export type HeatmapShowBoolean = {
show: boolean;
};

export interface LearningObject {
route: string;
loTitle: string;
parentLoTitle: string | undefined;
date: Date;
pageLoads: number;
timeActive: number;
nickname: string;
export interface AxisLabel {
interval: number;
fontSize: number;
margin?: number; // Adjust margin to control spacing
padding?: number[];
}

export interface AxisTick {
alignWithLabel: boolean;
}

export interface axisPointer {
type: "line" | "shadow" | "none";
}

export interface XAxis {
type: "value" | "category";
data: string[] | number[];
boundaryGap?: number[];
nameLocation?: "start" | "middle" | "center" | "end";
splitArea?: HeatmapShowBoolean;
axisLabel?: AxisLabel;
axisTick?: AxisTick;
axisPointer?: axisPointer;
position?: "top" | "bottom";
}

export interface YAxis {
type: "value" | "category";
data: string[];
splitArea?: HeatmapShowBoolean;
axisLabel?: AxisLabel;
}

export interface Color {
image: HTMLImageElement;
repeat: string;
}

export interface ItemStyle {
color: Color;
borderWidth: number;
borderColor: string;
}

export interface Tooltip {
position: "top" | "bottom" | "left" | "right";
trigger?: "item";
formatter?: (param: string | number) => string;
//formatter: string; //"{a} <br/>{b}: {c} mins"
}

export interface Series {
type: ChartType;
data: number[];
itemStyle: ItemStyle;
}

export interface BoxplotChartConfig {
backgroundColor: BackgroundColor;
xAxis: XAxis;
yAxis: YAxis;
series: Series[];
tooltip: Tooltip;
}

export type ChartTitle = {
top: string;
left: string;
text: string;
};

export interface CalendarMap {
date: string;
timeActive: number;
export interface VisualMap {
min: number;
max: number;
calculable: boolean;
orient: "horizontal" | "vertical";
left: number | string | "center" | "left" | "right";
align: "auto" | "left" | "right" | "center";
bottom: number | string | "center" | "top" | "bottom";
}

export interface HeatMapChartConfig {
title: ChartTitle;
tooltip: Tooltip;
backgroundColor: BackgroundColor;
grid: GridConfig;
xAxis: XAxis;
yAxis: YAxis;
visualMap: VisualMap;
series: HeatMapSeriesData[];
}

export interface BoxplotTooltip {
trigger: "item";
formatter: (param: string | number) => string;
//formatter: string; //"{a} <br/>{b}: {c} mins"
}

export interface HeatmapTooltip {
position: "top" | "bottom" | "left" | "right";
trigger: "item";
formatter: string; //"{a} <br/>{b}: {c} mins"
}

export type NameTypeData = {
name: string;
type?: string;
};

export interface LabStepData {
aggregatedTimeActive: number;
title: string;
loType: string;
export interface HeatMapSeriesData {
top: string | number;
name: string;
type: "heatmap";
selectedMode: "single" | "multiple";
data: number[][];
label: HeatmapShowBoolean;
}

export interface BoxplotData {
value: [number, number, number, number, number];
title: string;
lowNickname: string;
highNickname: string;
// export type HeatMapSeriesData = NameTypeData & {
// data: number[][];
// top: string;
// selectedMode?: string;
// label: { show: boolean };
// };

export type BoxplotData = NameTypeData & {
value: [number, number, number, number, number];
lowNickname: string;
highNickname: string;
};

export type OuterPieData = {
value: number;
name: string;
type: string;
};
export type DrilledDownData = NameTypeData & {
value: number;
};
41 changes: 22 additions & 19 deletions src/lib/services/utils/supabase-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ export async function getDurationTotal(key: string, table: string, id: string):
}

export async function insertOrUpdateCalendar(studentId: string, courseId: string) {
if(!studentId || !courseId) return;
const durationPromise = getCalendarDuration(formatDate(new Date()), studentId, courseId);
const countPromise = getCalendarCount(formatDate(new Date()), studentId, courseId);
const [timeActive, pageLoads] = await Promise.all([durationPromise, countPromise]);
Expand Down Expand Up @@ -205,12 +206,12 @@ export const updateCalendarDuration = async (id: string, studentId: string, cour

export async function storeStudentCourseLearningObjectInSupabase(course: Course, loid: string, lo: Lo, userDetails: User) {
// const loTitle = getLoTitle(params)
if (userDetails?.user_metadata.full_name === "Anon") return;
if (userDetails?.user_metadata?.full_name === "Anon") return;
// await insertOrUpdateCourse(course);
// await addOrUpdateStudent(userDetails);
// await addOrUpdateLo(loid, lo, lo.title);
await handleInteractionData(course.courseId, userDetails.user_metadata.user_name, loid, lo);
await insertOrUpdateCalendar(userDetails.user_metadata.user_name, course.courseId);
await handleInteractionData(course.courseId, userDetails?.user_metadata?.user_name, loid, lo);
await insertOrUpdateCalendar(userDetails?.user_metadata?.user_name, course.courseId);
}

export async function handleInteractionData(courseId: string, studentId: string, loId: string, lo: Lo) {
Expand Down Expand Up @@ -290,25 +291,27 @@ export function getSimpleTypesValues(los: Lo[]) {
return [...notes, ...archives, ...webs, ...githubs, ...panelnotes, ...paneltalks, ...panelVideos, ...talks, ...books, ...labs, ...steps];
}

export async function getUser(username: string) {
return fetch(`https://api.github.com/users/${username}`)
.then((response) => response.json())
.then((response) => {
return response.name;
});
export async function getUserNames(usernames: string[]): Promise<Map<string, string>> {
const userMap = new Map<string, string>();
for (const username of usernames) {
const response = await fetch(`https://api.github.com/users/${username}`);
const user = await response.json();
if (user.name) {
userMap.set(username, user.name);
}
}
return userMap;
}

export async function getGithubAvatarUrl(username: string) {
const url = `https://api.github.com/users/${username}`;
try {
export async function getGithubAvatarUrl(usernames: string[]): Promise<Map<string, string>> {
const imageMap = new Map<string, string>();
for (const username of usernames) {
const url = `https://api.github.com/users/${username}`;
const response = await fetch(url);
if (!response.ok) {
throw new Error(`User not found: ${response.status}`);
}
const data = await response.json();
return data.avatar_url;
} catch (error) {
console.error("Error fetching the avatar URL:", error);
return null;
if (data.avatar_url) {
imageMap.set(username, data.avatar_url);
}
}
return imageMap;
}
Loading

0 comments on commit faf277f

Please sign in to comment.