From 8e6a764c387178cbd50981e1c8cbd038027462f3 Mon Sep 17 00:00:00 2001 From: joshwanf <17016446+joshwanf@users.noreply.github.com> Date: Wed, 4 Mar 2026 14:11:19 -0500 Subject: [PATCH 1/4] Moved
into it's own directory for subcomponents --- .../src/components/{ => Header}/Header.tsx | 2 +- .../src/components/homeScreen/HomeScreen.tsx | 4 +- .../EligibilityCheckDetail.tsx | 53 ++++++++++++++----- .../src/components/project/Project.tsx | 39 +++++++++----- 4 files changed, 70 insertions(+), 28 deletions(-) rename builder-frontend/src/components/{ => Header}/Header.tsx (96%) diff --git a/builder-frontend/src/components/Header.tsx b/builder-frontend/src/components/Header/Header.tsx similarity index 96% rename from builder-frontend/src/components/Header.tsx rename to builder-frontend/src/components/Header/Header.tsx index e04ad7e1..8ef8cf41 100644 --- a/builder-frontend/src/components/Header.tsx +++ b/builder-frontend/src/components/Header/Header.tsx @@ -1,4 +1,4 @@ -import { useAuth } from "../context/AuthContext"; +import { useAuth } from "../../context/AuthContext"; import { useLocation, useNavigate } from "@solidjs/router"; import bdtLogo from "../assets/logos/bdt-logo-large-mono-light.svg"; diff --git a/builder-frontend/src/components/homeScreen/HomeScreen.tsx b/builder-frontend/src/components/homeScreen/HomeScreen.tsx index 039fd79d..86c35384 100644 --- a/builder-frontend/src/components/homeScreen/HomeScreen.tsx +++ b/builder-frontend/src/components/homeScreen/HomeScreen.tsx @@ -2,14 +2,14 @@ import { Accessor, createSignal, Match, Switch } from "solid-js"; import EligibilityChecksList from "./eligibilityCheckList/EligibilityChecksList"; import ProjectsList from "./ProjectsList"; -import Header from "../Header"; +import Header from "../Header/Header"; import BdtNavbar, { NavbarProps } from "@/components/shared/BdtNavbar"; 0; const HomeScreen = () => { const [screenMode, setScreenMode] = createSignal<"screeners" | "checks">( - "screeners" + "screeners", ); const navbarDefs: Accessor = () => { diff --git a/builder-frontend/src/components/homeScreen/eligibilityCheckList/eligibilityCheckDetail/EligibilityCheckDetail.tsx b/builder-frontend/src/components/homeScreen/eligibilityCheckList/eligibilityCheckDetail/EligibilityCheckDetail.tsx index 786b6405..546929b8 100644 --- a/builder-frontend/src/components/homeScreen/eligibilityCheckList/eligibilityCheckDetail/EligibilityCheckDetail.tsx +++ b/builder-frontend/src/components/homeScreen/eligibilityCheckList/eligibilityCheckDetail/EligibilityCheckDetail.tsx @@ -4,7 +4,7 @@ import { useParams } from "@solidjs/router"; import { clsx } from "clsx"; import toast from "solid-toast"; -import Header from "../../../Header"; +import Header from "../../../Header/Header"; import Loading from "../../../Loading"; import KogitoDmnEditorView from "./KogitoDmnEditorView"; import EligibilityCheckTest from "./checkTesting/EligibilityCheckTest"; @@ -16,17 +16,22 @@ import ParametersConfiguration from "./ParametersConfiguration"; import ErrorDisplayModal from "@/components/shared/ErrorModal"; import BdtNavbar, { NavbarProps } from "@/components/shared/BdtNavbar"; - -type CheckDetailScreenMode = "paramConfig" | "dmnDefinition" | "testing" | "publish"; +type CheckDetailScreenMode = + | "paramConfig" + | "dmnDefinition" + | "testing" + | "publish"; const EligibilityCheckDetail = () => { const { checkId } = useParams(); const [currentDmnModel, setCurrentDmnModel] = createSignal(""); - const [screenMode, setScreenMode] = createSignal("paramConfig"); + const [screenMode, setScreenMode] = + createSignal("paramConfig"); const [validationErrors, setValidationErrors] = createSignal([]); - const [showingErrorModal, setShowingErrorModal] = createSignal(false); + const [showingErrorModal, setShowingErrorModal] = + createSignal(false); const { eligibilityCheck, actions, actionInProgress, initialLoadStatus } = eligibilityCheckDetailResource(() => checkId); @@ -43,15 +48,31 @@ const EligibilityCheckDetail = () => { } else { toast.success("No validation errors found in DMN model."); } - } + }; const navbarDefs: Accessor = () => { return { tabDefs: [ - { key: "paramConfig", label: "Parameter Configuration", onClick: () => setScreenMode("paramConfig") }, - { key: "dmnDefinition", label: "DMN Definition", onClick: () => setScreenMode("dmnDefinition") }, - { key: "testing", label: "Testing", onClick: () => setScreenMode("testing") }, - { key: "publish", label: "Publish", onClick: () => setScreenMode("publish") }, + { + key: "paramConfig", + label: "Parameter Configuration", + onClick: () => setScreenMode("paramConfig"), + }, + { + key: "dmnDefinition", + label: "DMN Definition", + onClick: () => setScreenMode("dmnDefinition"), + }, + { + key: "testing", + label: "Testing", + onClick: () => setScreenMode("testing"), + }, + { + key: "publish", + label: "Publish", + onClick: () => setScreenMode("publish"), + }, ], activeTabKey: () => screenMode(), titleDef: { label: eligibilityCheck().name }, @@ -66,7 +87,11 @@ const EligibilityCheckDetail = () => {
- + { Validate Current DMN
actions.saveDmnModel(currentDmnModel())} > Save Changes diff --git a/builder-frontend/src/components/project/Project.tsx b/builder-frontend/src/components/project/Project.tsx index 5fb28868..a92d0b12 100644 --- a/builder-frontend/src/components/project/Project.tsx +++ b/builder-frontend/src/components/project/Project.tsx @@ -2,7 +2,7 @@ import { createSignal, createResource, Accessor } from "solid-js"; import { useParams } from "@solidjs/router"; import FormEditorView from "./FormEditorView"; -import Header from "../Header"; +import Header from "../Header/Header"; import Loading from "../Loading"; import ManageBenefits from "./manageBenefits/ManageBenefits"; import Preview from "./preview/Preview"; @@ -11,7 +11,6 @@ import Publish from "./Publish"; import { fetchProject } from "@/api/screener"; import BdtNavbar, { NavbarProps } from "@/components/shared/BdtNavbar"; - type TabOption = "manageBenefits" | "formEditor" | "preview" | "publish"; function Project() { @@ -34,16 +33,32 @@ function Project() { // including a dummy signal 'forceUpdate' that can be unique for // each call to the refetch () => [params.projectId, forceUpdate()], - fetchAndCacheProject + fetchAndCacheProject, ); const navbarDefs: Accessor = () => { return { tabDefs: [ - { key: "manageBenefits", label: "Manage Benefits", onClick: () => setActiveTab("manageBenefits") }, - { key: "formEditor", label: "Form Editor", onClick: () => setActiveTab("formEditor") }, - { key: "preview", label: "Preview", onClick: () => setActiveTab("preview") }, - { key: "publish", label: "Publish", onClick: () => setActiveTab("publish") }, + { + key: "manageBenefits", + label: "Manage Benefits", + onClick: () => setActiveTab("manageBenefits"), + }, + { + key: "formEditor", + label: "Form Editor", + onClick: () => setActiveTab("formEditor"), + }, + { + key: "preview", + label: "Preview", + onClick: () => setActiveTab("preview"), + }, + { + key: "publish", + label: "Publish", + onClick: () => setActiveTab("publish"), + }, ], activeTabKey: () => activeTab(), titleDef: { label: project().screenerName }, @@ -52,9 +67,9 @@ function Project() { return (
-
+
{project.loading ? ( - + ) : ( <> @@ -64,11 +79,9 @@ function Project() { setFormSchema={setFormSchema} /> )} - {activeTab() == "manageBenefits" && ( - - )} + {activeTab() == "manageBenefits" && } {activeTab() == "preview" && ( - + )} {activeTab() == "publish" && ( Date: Wed, 4 Mar 2026 15:45:05 -0500 Subject: [PATCH 2/4] Added to
containing user email and logout button --- .../src/components/Header/AccountMenu.tsx | 50 +++++++++++++++++++ .../src/components/Header/Header.css | 34 +++++++++++++ .../src/components/Header/Header.tsx | 7 ++- 3 files changed, 89 insertions(+), 2 deletions(-) create mode 100644 builder-frontend/src/components/Header/AccountMenu.tsx create mode 100644 builder-frontend/src/components/Header/Header.css diff --git a/builder-frontend/src/components/Header/AccountMenu.tsx b/builder-frontend/src/components/Header/AccountMenu.tsx new file mode 100644 index 00000000..aec44d71 --- /dev/null +++ b/builder-frontend/src/components/Header/AccountMenu.tsx @@ -0,0 +1,50 @@ +import { useAuth } from "@/context/AuthContext"; +import { useNavigate } from "@solidjs/router"; +import { createSignal, onCleanup, onMount, Show } from "solid-js"; + +export const AccountMenu = () => { + const [root, setRoot] = createSignal(); + const [showMenu, setShowMenu] = createSignal(false); + const navigate = useNavigate(); + + const auth = useAuth(); + const userEmail = auth.user().email; + const { logout } = auth; + + const handleClickOutside = (ev: MouseEvent) => { + const el = root(); + if (showMenu() && el && !el.contains(ev.target as Node)) { + setShowMenu(false); + } + }; + + onMount(() => { + document.addEventListener("click", handleClickOutside); + }); + + onCleanup(() => { + document.removeEventListener("click", handleClickOutside); + }); + + const handleLogout = () => { + logout(); + navigate("/login", { replace: true }); + }; + + return ( + + ); +}; diff --git a/builder-frontend/src/components/Header/Header.css b/builder-frontend/src/components/Header/Header.css new file mode 100644 index 00000000..4b9deb1b --- /dev/null +++ b/builder-frontend/src/components/Header/Header.css @@ -0,0 +1,34 @@ +@import "tailwindcss"; + +.account-menu-wrapper { + position: relative; + display: inline-block; +} + +.account-menu-toggle { + @apply px-4 py-3 font-bold text-gray-700 rounded-sm; +} +.account-menu-toggle:hover { + @apply bg-gray-300 cursor-pointer; +} + +.account-menu-panel { + position: absolute; + top: 100%; + left: 0; + width: 100%; + + z-index: 1000; + + background-color: white; + padding: 0.5rem; + margin-top: 0.5rem; + @apply border-1 border-black rounded-sm; +} + +.account-menu-item { + @apply p-2 rounded-sm; +} +.account-menu-item:hover { + @apply bg-slate-200 cursor-pointer; +} diff --git a/builder-frontend/src/components/Header/Header.tsx b/builder-frontend/src/components/Header/Header.tsx index 8ef8cf41..48cf3b67 100644 --- a/builder-frontend/src/components/Header/Header.tsx +++ b/builder-frontend/src/components/Header/Header.tsx @@ -1,8 +1,11 @@ import { useAuth } from "../../context/AuthContext"; import { useLocation, useNavigate } from "@solidjs/router"; -import bdtLogo from "../assets/logos/bdt-logo-large-mono-light.svg"; +import bdtLogo from "@/assets/logos/bdt-logo-large-mono-light.svg"; import { Show } from "solid-js"; +import { AccountMenu } from "@/components/Header/AccountMenu"; + +import "./Header.css"; const HeaderButton = ({ buttonText, @@ -57,7 +60,7 @@ export default function Header() { buttonText="User Guide" onClick={() => window.open("https://bdt-docs.web.app/", "_blank")} /> - +
); From a55480e6762a9b84e895b5a180e42b4875066221 Mon Sep 17 00:00:00 2001 From: joshwanf <17016446+joshwanf@users.noreply.github.com> Date: Fri, 6 Mar 2026 14:14:09 -0500 Subject: [PATCH 3/4] Fixed clicking around "Logout" to enable logout function. Changed popover-style menu to a new component --- .../src/components/Header/AccountMenu.tsx | 50 ---------------- .../src/components/Header/Header.css | 34 +++-------- .../src/components/Header/Header.tsx | 45 ++++++++++++-- .../shared/HamburgerMenu/HamburgerMenu.css | 38 ++++++++++++ .../HamburgerMenu/HamburgerMenuButton.tsx | 15 +++++ .../HamburgerMenu/HamburgerMenuItem.tsx | 13 ++++ .../HamburgerMenu/HamburgerMenuPanel.tsx | 21 +++++++ .../HamburgerMenu/HamburgerMenuWrapper.tsx | 60 +++++++++++++++++++ .../components/shared/HamburgerMenu/index.tsx | 27 +++++++++ 9 files changed, 224 insertions(+), 79 deletions(-) delete mode 100644 builder-frontend/src/components/Header/AccountMenu.tsx create mode 100644 builder-frontend/src/components/shared/HamburgerMenu/HamburgerMenu.css create mode 100644 builder-frontend/src/components/shared/HamburgerMenu/HamburgerMenuButton.tsx create mode 100644 builder-frontend/src/components/shared/HamburgerMenu/HamburgerMenuItem.tsx create mode 100644 builder-frontend/src/components/shared/HamburgerMenu/HamburgerMenuPanel.tsx create mode 100644 builder-frontend/src/components/shared/HamburgerMenu/HamburgerMenuWrapper.tsx create mode 100644 builder-frontend/src/components/shared/HamburgerMenu/index.tsx diff --git a/builder-frontend/src/components/Header/AccountMenu.tsx b/builder-frontend/src/components/Header/AccountMenu.tsx deleted file mode 100644 index aec44d71..00000000 --- a/builder-frontend/src/components/Header/AccountMenu.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import { useAuth } from "@/context/AuthContext"; -import { useNavigate } from "@solidjs/router"; -import { createSignal, onCleanup, onMount, Show } from "solid-js"; - -export const AccountMenu = () => { - const [root, setRoot] = createSignal(); - const [showMenu, setShowMenu] = createSignal(false); - const navigate = useNavigate(); - - const auth = useAuth(); - const userEmail = auth.user().email; - const { logout } = auth; - - const handleClickOutside = (ev: MouseEvent) => { - const el = root(); - if (showMenu() && el && !el.contains(ev.target as Node)) { - setShowMenu(false); - } - }; - - onMount(() => { - document.addEventListener("click", handleClickOutside); - }); - - onCleanup(() => { - document.removeEventListener("click", handleClickOutside); - }); - - const handleLogout = () => { - logout(); - navigate("/login", { replace: true }); - }; - - return ( - - ); -}; diff --git a/builder-frontend/src/components/Header/Header.css b/builder-frontend/src/components/Header/Header.css index 4b9deb1b..f5033787 100644 --- a/builder-frontend/src/components/Header/Header.css +++ b/builder-frontend/src/components/Header/Header.css @@ -1,34 +1,18 @@ @import "tailwindcss"; -.account-menu-wrapper { - position: relative; - display: inline-block; +.header-user-email { + width: 75%; + overflow-wrap: break-word; + @apply mt-2; } -.account-menu-toggle { - @apply px-4 py-3 font-bold text-gray-700 rounded-sm; +.header-menu ul { + @apply p-0; } -.account-menu-toggle:hover { - @apply bg-gray-300 cursor-pointer; -} - -.account-menu-panel { - position: absolute; - top: 100%; - left: 0; +.header-menu-item { width: 100%; - - z-index: 1000; - - background-color: white; - padding: 0.5rem; - margin-top: 0.5rem; - @apply border-1 border-black rounded-sm; -} - -.account-menu-item { - @apply p-2 rounded-sm; + @apply p-2 rounded-sm list-none; } -.account-menu-item:hover { +.header-menu-item:hover { @apply bg-slate-200 cursor-pointer; } diff --git a/builder-frontend/src/components/Header/Header.tsx b/builder-frontend/src/components/Header/Header.tsx index 48cf3b67..027f05b4 100644 --- a/builder-frontend/src/components/Header/Header.tsx +++ b/builder-frontend/src/components/Header/Header.tsx @@ -1,9 +1,9 @@ import { useAuth } from "../../context/AuthContext"; import { useLocation, useNavigate } from "@solidjs/router"; +import { Component, For, Show } from "solid-js"; import bdtLogo from "@/assets/logos/bdt-logo-large-mono-light.svg"; -import { Show } from "solid-js"; -import { AccountMenu } from "@/components/Header/AccountMenu"; +import { HamburgerMenu } from "@/components/shared/HamburgerMenu"; import "./Header.css"; @@ -27,8 +27,38 @@ const HeaderButton = ({ ); }; +interface MenuProps { + userEmail: string; + logout: () => void; +} + +const HeaderMenu: Component = (props) => { + const menuItems = [{ label: "Logout", onClick: props.logout }]; + + return ( +
+
+ Welcome {props.userEmail} +
+
+
    + + {(menuItem) => ( +
  • + {menuItem.label} +
  • + )} +
    +
+
+ ); +}; + export default function Header() { - const { logout } = useAuth(); + const auth = useAuth(); + const userEmail = auth.user().email; + const { logout } = auth; + const navigate = useNavigate(); const location = useLocation(); @@ -60,7 +90,14 @@ export default function Header() { buttonText="User Guide" onClick={() => window.open("https://bdt-docs.web.app/", "_blank")} /> - + + +
Open menu
+
+ + + +
); diff --git a/builder-frontend/src/components/shared/HamburgerMenu/HamburgerMenu.css b/builder-frontend/src/components/shared/HamburgerMenu/HamburgerMenu.css new file mode 100644 index 00000000..04b8a710 --- /dev/null +++ b/builder-frontend/src/components/shared/HamburgerMenu/HamburgerMenu.css @@ -0,0 +1,38 @@ +@import "tailwindcss"; + +.menu-wrapper { + position: relative; + display: inline-block; +} + +.menu-toggle { + @apply px-4 py-3 font-bold text-gray-700 rounded-sm; +} +.menu-toggle:hover { + @apply bg-gray-300 cursor-pointer; +} + +.menu-panel { + position: fixed; + top: 0; + right: 0; + width: 25%; + height: 100%; + + z-index: 1000; + + background-color: white; + padding: 0.5rem; + filter: drop-shadow(-25px -5px 25px #aaa); + + @apply rounded-sm; + /* @apply border-1 border-black; */ +} + +.menu-item { + width: 100%; + @apply p-2 rounded-sm list-none; +} +.menu-item:hover { + @apply bg-slate-200 cursor-pointer; +} diff --git a/builder-frontend/src/components/shared/HamburgerMenu/HamburgerMenuButton.tsx b/builder-frontend/src/components/shared/HamburgerMenu/HamburgerMenuButton.tsx new file mode 100644 index 00000000..0b681e7a --- /dev/null +++ b/builder-frontend/src/components/shared/HamburgerMenu/HamburgerMenuButton.tsx @@ -0,0 +1,15 @@ +import { Component, JSX } from "solid-js"; +import { useHamburgerMenuContext } from "./HamburgerMenuWrapper"; + +interface Props { + children: JSX.Element; +} + +export const HamburgerMenuButton: Component = (props) => { + const menuCtx = useHamburgerMenuContext(); + return ( + + ); +}; diff --git a/builder-frontend/src/components/shared/HamburgerMenu/HamburgerMenuItem.tsx b/builder-frontend/src/components/shared/HamburgerMenu/HamburgerMenuItem.tsx new file mode 100644 index 00000000..2ed37191 --- /dev/null +++ b/builder-frontend/src/components/shared/HamburgerMenu/HamburgerMenuItem.tsx @@ -0,0 +1,13 @@ +import { Component } from "solid-js"; + +interface Props { + label: string; + onClick: () => void; +} +export const HamburgerMenuItem: Component = (props) => { + return ( + + ); +}; diff --git a/builder-frontend/src/components/shared/HamburgerMenu/HamburgerMenuPanel.tsx b/builder-frontend/src/components/shared/HamburgerMenu/HamburgerMenuPanel.tsx new file mode 100644 index 00000000..18a6c268 --- /dev/null +++ b/builder-frontend/src/components/shared/HamburgerMenu/HamburgerMenuPanel.tsx @@ -0,0 +1,21 @@ +import { Component, JSX, Show } from "solid-js"; +import { useHamburgerMenuContext } from "./HamburgerMenuWrapper"; + +interface Props { + children: JSX.Element; +} +export const HamburgerMenuPanel: Component = (props) => { + const { showMenu, setShowMenu } = useHamburgerMenuContext(); + return ( + +
+ +
+
+ ); +}; diff --git a/builder-frontend/src/components/shared/HamburgerMenu/HamburgerMenuWrapper.tsx b/builder-frontend/src/components/shared/HamburgerMenu/HamburgerMenuWrapper.tsx new file mode 100644 index 00000000..336b4038 --- /dev/null +++ b/builder-frontend/src/components/shared/HamburgerMenu/HamburgerMenuWrapper.tsx @@ -0,0 +1,60 @@ +import { + createContext, + createSignal, + onCleanup, + onMount, + ParentComponent, + useContext, +} from "solid-js"; + +export type HamburgerMenuContextValue = { + showMenu: () => boolean; + setShowMenu: (show: boolean) => void; + toggle: () => void; +}; + +export const HamburgerMenuContext = createContext(); + +export const useHamburgerMenuContext = () => { + const ctx = useContext(HamburgerMenuContext); + if (!ctx) { + throw new Error( + "HamburgerMenu components must be used within ", + ); + } + return ctx; +}; + +export const HamburgerMenuWrapper: ParentComponent = (props) => { + const [root, setRoot] = createSignal(); + const [showMenu, setShowMenu] = createSignal(false); + + const handleClickOutside = (ev: MouseEvent) => { + const el = root(); + if (showMenu() && el && !el.contains(ev.target as Node)) { + setShowMenu(false); + } + }; + + const ctx: HamburgerMenuContextValue = { + showMenu, + setShowMenu, + toggle: () => setShowMenu(!showMenu()), + }; + + onMount(() => { + document.addEventListener("click", handleClickOutside); + }); + + onCleanup(() => { + document.removeEventListener("click", handleClickOutside); + }); + + return ( + + + + ); +}; diff --git a/builder-frontend/src/components/shared/HamburgerMenu/index.tsx b/builder-frontend/src/components/shared/HamburgerMenu/index.tsx new file mode 100644 index 00000000..3c81a233 --- /dev/null +++ b/builder-frontend/src/components/shared/HamburgerMenu/index.tsx @@ -0,0 +1,27 @@ +/** + * HamburgerMenu component + * + * Usage: + * - Wrap all sub-components in + * - Opens a panel on the left side (can be parameterized in the future) + * + * + * + * + * + * + * + * + * + */ + +import { HamburgerMenuWrapper } from "@/components/shared/HamburgerMenu/HamburgerMenuWrapper"; +import { HamburgerMenuButton } from "@/components/shared/HamburgerMenu/HamburgerMenuButton"; +import { HamburgerMenuPanel } from "@/components/shared/HamburgerMenu/HamburgerMenuPanel"; + +import "./HamburgerMenu.css"; + +export const HamburgerMenu = Object.assign(HamburgerMenuWrapper, { + Button: HamburgerMenuButton, + Panel: HamburgerMenuPanel, +}); From 5a2036d836a8601996dd5f533d4c98c815282581 Mon Sep 17 00:00:00 2001 From: joshwanf <17016446+joshwanf@users.noreply.github.com> Date: Fri, 6 Mar 2026 14:43:19 -0500 Subject: [PATCH 4/4] Moved User Guide link into
menu --- builder-frontend/src/components/Header/Header.tsx | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/builder-frontend/src/components/Header/Header.tsx b/builder-frontend/src/components/Header/Header.tsx index 027f05b4..ef990bfb 100644 --- a/builder-frontend/src/components/Header/Header.tsx +++ b/builder-frontend/src/components/Header/Header.tsx @@ -33,7 +33,13 @@ interface MenuProps { } const HeaderMenu: Component = (props) => { - const menuItems = [{ label: "Logout", onClick: props.logout }]; + const menuItems: { label: string; onClick: () => void }[] = [ + { + label: "User Guide", + onClick: () => window.open("https://bdt-docs.web.app/", "_blank"), + }, + { label: "Logout", onClick: props.logout }, + ]; return (
@@ -86,10 +92,7 @@ export default function Header() { onClick={() => navigate("/")} /> - window.open("https://bdt-docs.web.app/", "_blank")} - /> +
Open menu