From d24902a07a5be53af1d1b5ae38b6c517a0e77415 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 30 Aug 2026 02:55:19 +0000 Subject: [PATCH 1/3] Initial plan From 806232a40bb8b2249eaf9498e1334dc1bb2dba79 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 30 Aug 2026 03:01:05 +0000 Subject: [PATCH 2/3] Add help tours for key app and admin sections Co-authored-by: mgmodell <7279993+mgmodell@users.noreply.github.com> --- app/javascript/components/Admin.tsx | 39 ++++++++++++++++++- .../components/BingoBoards/BingoShell.tsx | 4 +- app/javascript/components/HomeShell.tsx | 4 +- .../assignments/AssignmentShell.tsx | 19 ++++++++- .../components/checkin/InstallmentReport.tsx | 17 ++++++++ config/locales/home.en.yml | 8 ++++ 6 files changed, 85 insertions(+), 6 deletions(-) diff --git a/app/javascript/components/Admin.tsx b/app/javascript/components/Admin.tsx index 1f99562af..fc2f232e5 100644 --- a/app/javascript/components/Admin.tsx +++ b/app/javascript/components/Admin.tsx @@ -1,8 +1,9 @@ import React, { Suspense, useEffect } from "react"; -import { Route, Routes, Navigate, Outlet } from "react-router"; +import { Route, Routes, Navigate, Outlet, useLocation } from "react-router"; import WorkingIndicator from "./infrastructure/WorkingIndicator"; import { Skeleton } from "primereact/skeleton"; import { useTypedSelector } from "./infrastructure/AppReducers"; +import { useTour } from "./infrastructure/TourContext"; import CourseAdmin from "./course_admin/CourseAdmin"; import SchoolList from "./course_admin/SchoolList"; @@ -13,11 +14,47 @@ import RubricDataAdmin from "./assignments/RubricDataAdmin"; import ConsentFormList from "./Consent/ConsentFormList"; import ConsentFormDataAdmin from "./Consent/ConsentFormDataAdmin"; import ConceptsTable from "./ConceptsTable"; +import { useTranslation } from "react-i18next"; //interface AdminProps {} export default function Admin( /*props: AdminProps */) { const user = useTypedSelector(state => state.profile.user); + const { setTourSteps } = useTour(); + const location = useLocation(); + const [t] = useTranslation(); + + useEffect(() => { + let description = t("home.admin_help"); + + if (location.pathname.includes("/admin/courses")) { + description = t("home.admin_help_courses"); + } else if (location.pathname.includes("/admin/rubrics")) { + description = t("home.admin_help_rubrics"); + } else if (location.pathname.includes("/admin/concepts")) { + description = t("home.admin_help_concepts"); + } else if (location.pathname.includes("/admin/users")) { + description = t("home.admin_help_users"); + } else if (location.pathname.includes("/admin/schools")) { + description = t("home.admin_help_schools"); + } else if (location.pathname.includes("/admin/consent_forms")) { + description = t("home.admin_help_consent_forms"); + } + + setTourSteps([ + { + element: "body", + popover: { + title: t("home.admin_help_title"), + description, + align: "center", + side: "left" + } + } + ]); + + return () => setTourSteps([]); + }, [location.pathname, setTourSteps, t]); return ( diff --git a/app/javascript/components/BingoBoards/BingoShell.tsx b/app/javascript/components/BingoBoards/BingoShell.tsx index 5e2ee4e62..d19a88dd9 100644 --- a/app/javascript/components/BingoBoards/BingoShell.tsx +++ b/app/javascript/components/BingoBoards/BingoShell.tsx @@ -23,8 +23,8 @@ export default function BingoShell(props: Props) { { element: "body", popover: { - title: "No Help Available", - description: "There is no help available for this topic", + title: "Bingo!", + description: "Complete your Bingo! activity here by entering terms, playing assigned games, and reviewing results when available.", align: "center", side: "left" } diff --git a/app/javascript/components/HomeShell.tsx b/app/javascript/components/HomeShell.tsx index b44f5f68a..0e7fff1d4 100644 --- a/app/javascript/components/HomeShell.tsx +++ b/app/javascript/components/HomeShell.tsx @@ -55,8 +55,8 @@ export default function HomeShell(props: Props) { { element: "body", popover: { - title: "Welcome to the Application!", - description: "This stuff is awesome. More information soon!", + title: "Home", + description: "Use this page to review your current tasks, switch between task and calendar views, and open each activity.", align: "center", side: "left" } diff --git a/app/javascript/components/assignments/AssignmentShell.tsx b/app/javascript/components/assignments/AssignmentShell.tsx index c519ec7a5..0f4365871 100644 --- a/app/javascript/components/assignments/AssignmentShell.tsx +++ b/app/javascript/components/assignments/AssignmentShell.tsx @@ -1,8 +1,9 @@ -import React, { Suspense, useState } from "react"; +import React, { Suspense, useState, useEffect } from "react"; import { Route, Routes } from "react-router"; import WorkingIndicator from "../infrastructure/WorkingIndicator"; import RequireInstructor from "../infrastructure/RequireInstructor"; import { Skeleton } from "primereact/skeleton"; +import { useTour } from "../infrastructure/TourContext"; import AssignmentViewer from "./AssignmentViewer"; import CritiqueShell from "./CritiqueShell"; @@ -13,6 +14,22 @@ type Props = { export default function AssignmentShell( props: Props) { const [working] = useState(true); + const { setTourSteps } = useTour(); + + useEffect(() => { + setTourSteps([ + { + element: "body", + popover: { + title: "Assignments", + description: "Review assignment details, submit your responses, and check progress feedback in this section.", + align: "center", + side: "left" + } + } + ]); + return () => setTourSteps([]); + }, [setTourSteps]); return ( diff --git a/app/javascript/components/checkin/InstallmentReport.tsx b/app/javascript/components/checkin/InstallmentReport.tsx index 709cafdc1..891af1294 100644 --- a/app/javascript/components/checkin/InstallmentReport.tsx +++ b/app/javascript/components/checkin/InstallmentReport.tsx @@ -25,6 +25,7 @@ import distributeChange from "./distributeChange"; import { FloatLabel } from "primereact/floatlabel"; import GuardRedirect, { RedirectState } from "../infrastructure/GuardRedirect"; import { DATETIME_SHORT, formatZonedDateTime, parseISO, TemporalSettings } from "../infrastructure/TemporalSettings"; +import { useTour } from "../infrastructure/TourContext"; interface IContribution { userId: number; @@ -84,6 +85,22 @@ export default function InstallmentReport(props: Props) { const [redirectUrl, setRedirectUrl] = useState(undefined); const [redirectMessage, setRedirectMessage] = useState(""); const [redirectMessageHeading, setRedirectMessageHeading] = useState(""); + const { setTourSteps } = useTour(); + + useEffect(() => { + setTourSteps([ + { + element: "body", + popover: { + title: "Check-ins", + description: "Submit your weekly check-in by rating team contributions and adding comments before you save.", + align: "center", + side: "left" + } + } + ]); + return () => setTourSteps([]); + }, [setTourSteps]); const updateSlice = (id, update) => { const lContributions = { ...contributions}; diff --git a/config/locales/home.en.yml b/config/locales/home.en.yml index d4e00e80d..def364082 100644 --- a/config/locales/home.en.yml +++ b/config/locales/home.en.yml @@ -189,6 +189,14 @@ en: demonstration: Demonstration home: title: Home + admin_help_title: Admin Functions + admin_help: Use the admin area to manage courses, users, schools, rubrics, concepts, and consent forms. + admin_help_courses: Manage course settings, enrollments, and course activities in this section. + admin_help_rubrics: Create, publish, and maintain grading rubrics here. + admin_help_concepts: Review and maintain shared concept vocabulary used by Bingo! activities. + admin_help_users: Find users, review account details, and manage account roles in this section. + admin_help_schools: Create and edit school records, including labels and time zones. + admin_help_consent_forms: Create and update research consent forms, text, dates, and attached PDFs. your_tasks: Your Tasks invited: You've been invited! greeting: Hello #{name} From dcd2c2baab6489f18146871b2efd4211f9d9a728 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 30 Aug 2026 03:05:08 +0000 Subject: [PATCH 3/3] Harden admin help route section matching Co-authored-by: mgmodell <7279993+mgmodell@users.noreply.github.com> --- app/javascript/components/Admin.tsx | 31 ++++++++++++----------------- 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/app/javascript/components/Admin.tsx b/app/javascript/components/Admin.tsx index fc2f232e5..885c078b2 100644 --- a/app/javascript/components/Admin.tsx +++ b/app/javascript/components/Admin.tsx @@ -1,5 +1,5 @@ import React, { Suspense, useEffect } from "react"; -import { Route, Routes, Navigate, Outlet, useLocation } from "react-router"; +import { Route, Routes, Navigate, Outlet, useMatch } from "react-router"; import WorkingIndicator from "./infrastructure/WorkingIndicator"; import { Skeleton } from "primereact/skeleton"; import { useTypedSelector } from "./infrastructure/AppReducers"; @@ -17,29 +17,24 @@ import ConceptsTable from "./ConceptsTable"; import { useTranslation } from "react-i18next"; //interface AdminProps {} +const SECTION_HELP_KEYS: Record = { + courses: "home.admin_help_courses", + rubrics: "home.admin_help_rubrics", + concepts: "home.admin_help_concepts", + users: "home.admin_help_users", + schools: "home.admin_help_schools", + consent_forms: "home.admin_help_consent_forms" +}; export default function Admin( /*props: AdminProps */) { const user = useTypedSelector(state => state.profile.user); const { setTourSteps } = useTour(); - const location = useLocation(); + const adminMatch = useMatch("/admin/*"); const [t] = useTranslation(); useEffect(() => { - let description = t("home.admin_help"); - - if (location.pathname.includes("/admin/courses")) { - description = t("home.admin_help_courses"); - } else if (location.pathname.includes("/admin/rubrics")) { - description = t("home.admin_help_rubrics"); - } else if (location.pathname.includes("/admin/concepts")) { - description = t("home.admin_help_concepts"); - } else if (location.pathname.includes("/admin/users")) { - description = t("home.admin_help_users"); - } else if (location.pathname.includes("/admin/schools")) { - description = t("home.admin_help_schools"); - } else if (location.pathname.includes("/admin/consent_forms")) { - description = t("home.admin_help_consent_forms"); - } + const adminSection = (adminMatch?.params?.["*"] || "").split("/")[0]; + const description = t(SECTION_HELP_KEYS[adminSection] || "home.admin_help"); setTourSteps([ { @@ -54,7 +49,7 @@ export default function Admin( /*props: AdminProps */) { ]); return () => setTourSteps([]); - }, [location.pathname, setTourSteps, t]); + }, [adminMatch?.params?.["*"], setTourSteps, t]); return (