Item {index() + 1}
+{item.topic}
+Reason
+ {item.reason} +{props.data.tutorName}
+AI feedback
+{props.data.assignmentAiFeedback}
+Teacher feedback
+{props.data.assignmentTeacherFeedback}
+{props.data.questions.length} loaded from the mock dataset
+{props.data.questions.length} questions in this assignment
{question.responseLabel}
{question.responseValue} - {question.feedback} +Your steps and explanation
+{question.workingSteps}
+ Answer key
+Correct answer
{question.correctAnswer}
+
Pick the next teaching move for {props.data.selectedStudentName ?? "this student"}. The selected outcome will be saved with this student's review.
++ AI prepared this redo plan for {props.data.selectedStudentName} based on the completed review, weakness summary, and teacher feedback. +
+Why this student needs the planned mix of follow-up practice.
+These blueprint slices will be turned into a student-specific redo assignment when you generate it.
+Item {index() + 1}
+Reason
+ {item.reason} +Keep AI feedback and teacher feedback in one place for the whole assignment.
+{assignmentUiCopy.teacherReview.feedback.aiFeedback}
+ {props.data.assignmentAiFeedback || assignmentUiCopy.teacherReview.feedback.noAiFeedback} +{assignmentUiCopy.teacherReview.question.questionPrefix} {props.question.order}
+{assignmentUiCopy.teacherReview.question.studentAnswer}
+ {props.question.answerText} +{assignmentUiCopy.teacherReview.question.studentSteps}
+{props.question.workingSteps}
+ {assignmentUiCopy.teacherReview.question.correctAnswer}
+
+
+
{displayQuestions().length} questions in this review
+Loading assignment
+Assignment not found
+Your latest answers are synced. You can review the assignment or keep refining any answer.
+{props.data.classroomName}
+Answer each question, show your working, and save each answer back to the live assignment as you go.
+{props.saveLabel}
+{assignmentUiCopy.studentWork.header.submitHint}
+{assignmentUiCopy.studentWork.workspace.questionPrefix} {props.question.order}
+{props.question.statusLabel}
+{assignmentUiCopy.studentWork.workspace.helperEyebrow}
+Try to explain why each step makes sense, not just what number you wrote next.
+Assignments
-Stay in dashboard mode to see what is live, what needs finishing, and what is ready for review.
-{group.description}
-{item.meta}
- {item.subMeta} -Messages
-Keep dashboard context while you check tutor guidance, assignment reminders, and quick study nudges that point you to the next useful action.
-{thread.role}
-{thread.preview}
- - -Settings
-Keep this inside the dashboard shell so profile details, study preferences, and learner goals feel like part of the same student workspace.
-{panel.description}
-Mailbox
+{message()}
}{message()}
}The thread opens right away after creation, so you can send the first message from the conversation pane.
+ + + + } + > ++ {props.filteredThreads.length} of {props.threads.length} thread{props.threads.length === 1 ? "" : "s"} +
+Conversation
+{participantSummary(thread.participants, props.currentUserId)}
+{message()}
}{message()}
}{message()}
}{message()}
}Settings
+Keep your preferred name, profile photo, and learning setup in sync so the dashboard feels like your own workspace.
+{activitySummary.note}
+{props.activitySummary.note}
{dashboardUiCopy.studentAssignmentsFocus.eyebrow}
+{dashboardUiCopy.studentAssignmentsFocus.description}
+{group.description}
+{item.meta}
+ {item.subMeta} +{assignment.lessons}
diff --git a/Frontend/src/components/dashboard/dashboard-hero.module.scss b/Frontend/src/components/dashboard/student/dashboard-hero.module.scss similarity index 88% rename from Frontend/src/components/dashboard/dashboard-hero.module.scss rename to Frontend/src/components/dashboard/student/dashboard-hero.module.scss index 842d3f1..835f4be 100644 --- a/Frontend/src/components/dashboard/dashboard-hero.module.scss +++ b/Frontend/src/components/dashboard/student/dashboard-hero.module.scss @@ -2,11 +2,11 @@ display: grid; gap: 1rem; - @media (min-width: 960px) { + @include respond(desktop-sm) { gap: 1.25rem; } - @media (min-width: 1120px) { + @include respond(desktop-lg) { grid-template-columns: minmax(0, 1.6fr) minmax(18rem, 0.75fr); } } @@ -22,16 +22,16 @@ display: grid; gap: 1.25rem; padding: 1.15rem; - border-radius: 1.5rem; + border-radius: var(--radius-3xl); background: linear-gradient(135deg, var(--surface-hero-start), var(--surface-hero-end)); color: var(--text-on-accent); overflow: hidden; - @media (min-width: 640px) { + @include respond(phablet) { padding: 1.4rem; } - @media (min-width: 960px) { + @include respond(desktop-sm) { gap: 1.6rem; padding: 1.75rem; } @@ -59,7 +59,7 @@ font-size: 0.94rem; color: var(--text-on-accent-muted); - @media (min-width: 640px) { + @include respond(phablet) { font-size: 1rem; } } @@ -84,7 +84,7 @@ align-items: center; gap: 0.7rem; padding: 0.62rem 0.8rem; - border-radius: 9999px; + border-radius: var(--radius-full); background: var(--surface-overlay-soft); backdrop-filter: blur(8px); border: 1px solid var(--border-overlay); @@ -110,7 +110,7 @@ height: 2rem; display: grid; place-items: center; - border-radius: 9999px; + border-radius: var(--radius-full); font-weight: 700; color: var(--text-accent-strong); } @@ -136,11 +136,11 @@ display: grid; place-items: center; - @media (min-width: 640px) { + @include respond(phablet) { min-height: 12rem; } - @media (min-width: 960px) { + @include respond(desktop-sm) { min-height: 13rem; } } @@ -155,7 +155,7 @@ .visualCard { position: absolute; padding: 0.5rem 0.72rem; - border-radius: 9999px; + border-radius: var(--radius-full); background: var(--surface-overlay-strong); color: var(--text-on-accent); font-weight: 600; @@ -182,14 +182,14 @@ display: grid; gap: 0.85rem; padding: 1rem; - border-radius: 1.5rem; + border-radius: var(--radius-3xl); background: var(--surface-panel); - @media (min-width: 640px) { + @include respond(phablet) { padding: 1.15rem; } - @media (min-width: 960px) { + @include respond(desktop-sm) { gap: 1rem; padding: 1.35rem; } @@ -213,7 +213,7 @@ justify-content: center; padding: 0.82rem 0.95rem; border: none; - border-radius: 1rem; + border-radius: var(--radius-md); background: linear-gradient(135deg, var(--action-primary-start), var(--action-primary-end)); color: var(--action-primary-text); font-weight: 600; diff --git a/Frontend/src/components/dashboard/dashboard-hero.tsx b/Frontend/src/components/dashboard/student/dashboard-hero.tsx similarity index 60% rename from Frontend/src/components/dashboard/dashboard-hero.tsx rename to Frontend/src/components/dashboard/student/dashboard-hero.tsx index 490c1ce..9cfd616 100644 --- a/Frontend/src/components/dashboard/dashboard-hero.tsx +++ b/Frontend/src/components/dashboard/student/dashboard-hero.tsx @@ -1,20 +1,22 @@ import type { Component } from "solid-js"; import { For } from "solid-js"; import { A } from "@solidjs/router"; -import { heroSideCard, heroSummary, quickStats, spotlightStats } from "./dashboard.data"; +import type { DashboardHeroData } from "../shared/dashboard-types"; import styles from "./dashboard-hero.module.scss"; -const DashboardHero: Component = () => { +type DashboardHeroProps = DashboardHeroData; + +const DashboardHero: Component{heroSummary.eyebrow}
-{heroSummary.description}
+{props.heroSummary.eyebrow}
+{props.heroSummary.description}
{heroSideCard.description}
- - {heroSideCard.buttonLabel} +{props.heroSideCard.description}
+ + {props.heroSideCard.buttonLabel}{stat.label}
diff --git a/Frontend/src/components/dashboard/student/dashboard-home.data.ts b/Frontend/src/components/dashboard/student/dashboard-home.data.ts new file mode 100644 index 0000000..60501a8 --- /dev/null +++ b/Frontend/src/components/dashboard/student/dashboard-home.data.ts @@ -0,0 +1,321 @@ +import { + getAssignmentReviewHref, + getAssignmentWorkHref, + getDashboardAssignmentsHref, + getDashboardMessagesHref, + getDashboardPracticeHref, + getDashboardProgressHref, + getDashboardSettingsHref, + getDashboardHomeHref, +} from "../../../lib/routes"; +import { apiFetchJson } from "../../../lib/api"; +import type { ApiAssignment, ApiAssignmentStudentQuestionDetail, ApiClassroom, ApiListResponse, ApiUser } from "../../../lib/api-types"; +import { studentDashboardLabels } from "../../../content/dashboard-labels"; +import type { DashboardHomeData } from "../shared/dashboard-types"; +import { + buildAssignmentCards, + buildDerivedAssignments, + buildProgressSeries, + buildTopicAggregates, + buildUsageItems, + daysUntil, + formatAssignmentBadge, + formatAssignmentShortTitle, + formatDueCountdown, + formatRelativeTime, + initialsFor, + masteryTones, + sortByDueDate, + toneAt, +} from "./dashboard-home.helpers"; + +export const getDashboardHomeData = async (studentId: number): Promise