Skip to content

Commit

Permalink
[Issue #3247] logged in state for header with email address (#3458)
Browse files Browse the repository at this point in the history
* updates to session management to allow for decrypting the login.gov JWT in order to pull out user email
* creation of a logged in state for the header
  • Loading branch information
doug-s-nava authored and acouch committed Jan 13, 2025
1 parent b3fca0a commit 40735e0
Show file tree
Hide file tree
Showing 29 changed files with 611 additions and 323 deletions.
21 changes: 0 additions & 21 deletions frontend/src/app/[locale]/dev/feature-flags/FeatureFlagsTable.tsx
Original file line number Diff line number Diff line change
@@ -1,39 +1,18 @@
"use client";

import { useFeatureFlags } from "src/hooks/useFeatureFlags";
import { useUser } from "src/services/auth/useUser";

import React from "react";
import { Button, Table } from "@trussworks/react-uswds";

import Loading from "src/components/Loading";

/**
* View for managing feature flags
*/
export default function FeatureFlagsTable() {
const { setFeatureFlag, featureFlags } = useFeatureFlags();
const { user, isLoading, error } = useUser();

if (isLoading) {
return <Loading />;
}

if (error) {
// there's no error page within this tree, should we make a top level error?
return (
<>
<h1>Error</h1>
{error.message}
</>
);
}

return (
<>
<h2>
{user?.token ? `Logged in with token: ${user.token}` : "Not logged in"}
</h2>
<Table>
<thead>
<tr>
Expand Down
7 changes: 0 additions & 7 deletions frontend/src/app/[locale]/dev/layout.tsx

This file was deleted.

2 changes: 1 addition & 1 deletion frontend/src/app/[locale]/process/ProcessNext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ const ProcessNext = () => {
>
<IconListIcon>
<USWDSIcon
className="usa-icon text-base"
className="text-base"
name="check_circle_outline"
/>
</IconListIcon>
Expand Down
3 changes: 1 addition & 2 deletions frontend/src/app/api/auth/callback/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@ const createSessionAndSetStatus = async (
};

/*
currently it looks like the API will send us a request with the params below, and we will be responsible
for directing the user accordingly. For now, we'll send them to generic success and error pages with cookie set on success
For now, we'll send them to generic success and error pages with cookie set on success
message: str ("success" or "error")
token: str | None
Expand Down
5 changes: 3 additions & 2 deletions frontend/src/app/api/auth/logout/route.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { deleteSession, getSession } from "src/services/auth/session";
import { getSession } from "src/services/auth/session";
import { deleteSession } from "src/services/auth/sessionUtils";
import { postLogout } from "src/services/fetch/fetchers/userFetcher";

export async function POST() {
try {
// logout on API via /v1/users/token/logout
const session = await getSession();
if (!session || !session.token) {
throw new Error("No active session to logout");
}
// logout on API via /v1/users/token/logout
const response = await postLogout(session.token);
if (!response) {
throw new Error("No logout response from API");
Expand Down
6 changes: 3 additions & 3 deletions frontend/src/app/api/auth/session/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ import { getSession } from "src/services/auth/session";

import { NextResponse } from "next/server";

export const revalidate = 0;

export async function GET() {
const currentSession = await getSession();
if (currentSession) {
return NextResponse.json({
token: currentSession.token,
});
return NextResponse.json(currentSession);
} else {
return NextResponse.json({ token: "" });
}
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/Footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ type SocialLinkProps = {
const SocialLink = ({ href, name, icon }: SocialLinkProps) => (
<a className="usa-social-link" href={href} title={name} target="_blank">
<USWDSIcon
className="usa-icon usa-social-link__icon"
className="usa-social-link__icon"
height="40px"
name={icon}
aria-label={name}
Expand Down
39 changes: 3 additions & 36 deletions frontend/src/components/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {
Header as USWDSHeader,
} from "@trussworks/react-uswds";

import { USWDSIcon } from "src/components/USWDSIcon";
import { UserControl } from "./user/UserControl";

type PrimaryLink = {
text?: string;
Expand Down Expand Up @@ -120,36 +120,6 @@ const NavLinks = ({
);
};

const LoginLink = ({ navLoginLinkText }: { navLoginLinkText: string }) => {
const [authLoginUrl, setAuthLoginUrl] = useState<string | null>(null);

useEffect(() => {
async function fetchEnv() {
const res = await fetch("/api/env");
const data = (await res.json()) as { auth_login_url: string };
data.auth_login_url
? setAuthLoginUrl(data.auth_login_url)
: console.error("could not access auth_login_url");
}
fetchEnv().catch((error) => console.warn("error fetching api/env", error));
}, []);

return (
<a
{...(authLoginUrl ? { href: authLoginUrl } : "")}
key="login-link"
className="usa-nav__link text-primary font-sans-2xs display-flex text-normal"
>
<USWDSIcon
className="usa-icon margin-right-05 margin-left-neg-05"
name="login"
key="login-link-icon"
/>
{navLoginLinkText}
</a>
);
};

const Header = ({ logoPath, locale }: Props) => {
logoPath = "./img/grants-logo.svg";
const t = useTranslations("Header");
Expand All @@ -173,7 +143,6 @@ const Header = ({ logoPath, locale }: Props) => {

const { checkFeatureFlag } = useFeatureFlags();
const showLoginLink = checkFeatureFlag("authOn");

const language = locale && locale.match("/^es/") ? "spanish" : "english";

const handleMobileNavToggle = () => {
Expand Down Expand Up @@ -223,10 +192,8 @@ const Header = ({ logoPath, locale }: Props) => {
/>
</div>
{!!showLoginLink && (
<div className="usa-nav__primary margin-top-0 margin-bottom-1 desktop:margin-bottom-5px text-no-wrap desktop:order-last margin-left-auto">
<div className="usa-nav__primary-item border-0">
<LoginLink navLoginLinkText={t("nav_link_login")} />
</div>
<div className="usa-nav__primary margin-top-0 padding-bottom-05 text-no-wrap desktop:order-last margin-left-auto desktop:height-auto height-6">
<UserControl />
</div>
)}
<NavLinks
Expand Down
26 changes: 15 additions & 11 deletions frontend/src/components/Layout.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import UserProvider from "src/services/auth/UserProvider";

import { useTranslations } from "next-intl";
import { setRequestLocale } from "next-intl/server";

Expand All @@ -17,16 +19,18 @@ export default function Layout({ children, locale }: Props) {

return (
// Stick the footer to the bottom of the page
<div className="display-flex flex-column minh-viewport">
<a className="usa-skipnav z-top" href="#main-content">
{t("Layout.skip_to_main")}
</a>
<Header locale={locale} />
<main id="main-content" className="border-top-0">
{children}
</main>
<Footer />
<GrantsIdentifier />
</div>
<UserProvider>
<div className="display-flex flex-column minh-viewport">
<a className="usa-skipnav" href="#main-content">
{t("Layout.skip_to_main")}
</a>
<Header locale={locale} />
<main id="main-content" className="border-top-0">
{children}
</main>
<Footer />
<GrantsIdentifier />
</div>
</UserProvider>
);
}
6 changes: 4 additions & 2 deletions frontend/src/components/USWDSIcon.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import clsx from "clsx";

import SpriteSVG from "public/img/uswds-sprite.svg";

interface IconProps {
name: string;
className: string;
className?: string;
height?: string;
}

Expand All @@ -12,7 +14,7 @@ const sprite_uri = SpriteSVG.src as string;
export function USWDSIcon(props: IconProps) {
return (
<svg
className={props.className}
className={clsx("usa-icon", props.className)}
aria-hidden="true"
height={props.height}
role="img"
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/content/IndexGoalContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const IndexGoalContent = () => {
<span className="margin-right-5">{t("goal.cta")}</span>
<USWDSIcon
name="arrow_forward"
className="usa-icon usa-icon--size-4 text-middle margin-left-neg-4"
className="usa-icon--size-4 text-middle margin-left-neg-4"
aria-label="arrow-forward"
/>
</Button>
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/components/content/ProcessAndResearchContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ const ProcessAndResearchContent = () => {
</span>
<USWDSIcon
name="arrow_forward"
className="usa-icon usa-icon--size-4 text-middle margin-left-neg-4"
className="usa-icon--size-4 text-middle margin-left-neg-4"
aria-label="arrow-forward"
/>
</Button>
Expand All @@ -47,7 +47,7 @@ const ProcessAndResearchContent = () => {
</span>
<USWDSIcon
name="arrow_forward"
className="usa-icon usa-icon--size-4 text-middle margin-left-neg-4"
className="usa-icon--size-4 text-middle margin-left-neg-4"
aria-label="arrow-forward"
/>
</Button>
Expand Down
5 changes: 1 addition & 4 deletions frontend/src/components/opportunity/OpportunityCTA.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,7 @@ const OpportunityCTA = ({ id }: { id: number }) => {
>
<Button type="button" outline={true} className="margin-top-2">
<span>{t("button_content")}</span>
<USWDSIcon
name="launch"
className="usa-icon usa-icon--size-4 text-middle"
/>
<USWDSIcon name="launch" className="usa-icon--size-4 text-middle" />
</Button>
</a>
</>
Expand Down
5 changes: 1 addition & 4 deletions frontend/src/components/opportunity/OpportunityDownload.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,7 @@ const OpportunityDownload = ({ nofoPath }: Props) => {
<div className="grid-row flex-justify">
<Button onClick={() => downloadNOFO(nofoPath)} type="button">
<span>{t("nofo_download")} </span>
<USWDSIcon
name={"file_download"}
className="usa-icon usa-icon--size-4"
/>
<USWDSIcon name={"file_download"} className="usa-icon--size-4" />
</Button>
<Link
className="flex-align-self-center"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ const OpportunityStatusWidget = ({ opportunityData }: Props) => {
switch (status) {
case "archived":
return (
<div className="usa-tag bg-base-lighter text-ink border-radius-2 border-base-lightest width-100 radius-md margin-right-0 font-sans-sm text-center text-no-uppercase">
<div className="usa-tag bg-base-lighter text-ink border-radius-2 border-base-lightest radius-md margin-right-0 font-sans-sm text-center text-no-uppercase">
<p>
<strong>{t("archived")}</strong>
<span>{formatDate(archiveDate) || "--"}</span>
Expand All @@ -71,7 +71,7 @@ const OpportunityStatusWidget = ({ opportunityData }: Props) => {
);
case "closed":
return (
<div className="usa-tag bg-base-lighter text-ink border-radius-2 border-base-lightest width-100 radius-md margin-right-0 font-sans-sm text-center text-no-uppercase">
<div className="usa-tag bg-base-lighter text-ink border-radius-2 border-base-lightest radius-md margin-right-0 font-sans-sm text-center text-no-uppercase">
<p>
<strong>{t("closed")}</strong>
<span>{formatDate(closeDate) || "--"}</span>
Expand All @@ -81,7 +81,7 @@ const OpportunityStatusWidget = ({ opportunityData }: Props) => {
case "posted":
return (
<>
<div className="usa-tag bg-accent-warm-dark width-100 radius-md margin-right-0 font-sans-sm text-center text-no-uppercase">
<div className="usa-tag bg-accent-warm-dark radius-md margin-right-0 font-sans-sm text-center text-no-uppercase">
<p>
<strong>{t("closing")}</strong>
<span>{formatDate(closeDate) || "--"}</span>
Expand All @@ -96,7 +96,7 @@ const OpportunityStatusWidget = ({ opportunityData }: Props) => {
);
case "forecasted":
return (
<div className="usa-tag bg-base-dark border-radius-2 width-100 radius-md margin-right-0 font-sans-sm text-center text-no-uppercase">
<div className="usa-tag bg-base-dark border-radius-2 radius-md margin-right-0 font-sans-sm text-center text-no-uppercase">
<p>
<strong>{t("forecasted")}</strong>
</p>
Expand Down
Loading

0 comments on commit 40735e0

Please sign in to comment.