Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[TM-1492] make dashboard endpoints publicly accessible #683

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 18 additions & 3 deletions src/components/extensive/BlurContainer/BlurContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import Text from "@/components/elements/Text/Text";

export interface BlurContainerProps {
isBlur: boolean;
textInformation?: string;
textInformation?: string | React.ReactNode;
children: React.ReactNode;
className?: string;
}
Expand All @@ -16,16 +16,31 @@ const BlurContainer = ({ isBlur, textInformation, children, className, ...props
return <>{children}</>;
}

const LoginText = () => (
<>
<a href="/auth/login" className="text-12-semibold underline">
Login to view.
</a>{" "}
If you are a funder or representing a government agency, please{" "}
<a
href="https://terramatchsupport.zendesk.com/hc/en-us/requests/new?ticket_form_id=30623040820123&tf_subject=Account%20Access%20Request%20for%20TerraMatch%20Dashboard&tf_description=Please%20provide%20your%20details%20to%20request%20access%20to%20the%20TerraMatch%20Dashboard.%20Once%20your%20information%20is%20submitted,%20our%20team%20will%20review%20your%20request%20and%20set%20up%20an%20account%20for%20you.%20You%E2%80%99ll%20receive%20an%20email%20with%20further%20instructions%20once%20your%20account%20is%20ready"
className="text-12-semibold underline"
>
click here to request an account.
</a>
</>
);

return (
<div className={tw("relative w-full text-black", className)}>
<div
className={`absolute left-0 top-0 flex h-full w-full items-center justify-center rounded-xl ${
isBlur ? "z-[1] bg-[#9d9a9a29] backdrop-blur-sm" : ""
}`}
>
<When condition={isBlur && textInformation}>
<When condition={isBlur && !!textInformation}>
<Text variant="text-12-semibold" className="h-fit w-fit max-w-[80%] rounded-lg bg-white px-4 py-3">
{textInformation}
{typeof textInformation === "string" ? textInformation : <LoginText />}
</Text>
</When>
</div>
Expand Down
4 changes: 3 additions & 1 deletion src/components/extensive/PageElements/Card/PageCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import EmptyField, { EmptyFieldProps } from "@/components/elements/Field/EmptyFi
import Paper from "@/components/elements/Paper/Paper";
import Text from "@/components/elements/Text/Text";
import ToolTip from "@/components/elements/Tooltip/Tooltip";
import { useMyUser } from "@/connections/User";
import { NO_DATA_INFORMATION } from "@/constants/dashboardConsts";
import { withFrameworkShow } from "@/context/framework.provider";
import { TextVariants } from "@/types/common";
Expand Down Expand Up @@ -55,6 +56,7 @@ const PageCard = ({
const [collapseSubtile, setCollapseSubtile] = useState(true);
const [subtitleText, setSubtitleText] = useState(subtitle);
const t = useT();
const [, { user }] = useMyUser();

const maxLength = 278;

Expand All @@ -68,7 +70,7 @@ const PageCard = ({

return (
<Paper {...props}>
<BlurContainer isBlur={!isUserAllowed} textInformation={NO_DATA_INFORMATION}>
<BlurContainer isBlur={!isUserAllowed} textInformation={user !== undefined ? NO_DATA_INFORMATION : <></>}>
<When condition={!!title || !!headerChildren}>
<div className="flex flex-wrap justify-between">
<When condition={!!title}>
Expand Down
8 changes: 7 additions & 1 deletion src/middleware.page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ export async function middleware(request: NextRequest) {
const accessToken = request.cookies.get("accessToken")?.value;
const middlewareCache = request.cookies.get(MiddlewareCacheKey)?.value;

if (request.nextUrl.pathname.startsWith("/dashboard")) {
return NextResponse.next();
}

if (!!accessToken && !!middlewareCache) {
// Skip middleware for dashboard routes to prevent redirect loop
if (request.nextUrl.pathname.startsWith("/dashboard")) {
Expand All @@ -37,7 +41,9 @@ export async function middleware(request: NextRequest) {
matcher.startWith("/auth")?.next();
matcher.exact("/")?.next();

matcher.redirect("/auth/login");
if (!matcher.hasMatch()) {
matcher.redirect("/auth/login");
}
},
async () => {
// The redux store isn't available yet at this point, so we do a quick manual users/me fetch
Expand Down
4 changes: 3 additions & 1 deletion src/pages/dashboard/index.page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import BlurContainer from "@/components/extensive/BlurContainer/BlurContainer";
import Icon, { IconNames } from "@/components/extensive/Icon/Icon";
import PageCard from "@/components/extensive/PageElements/Card/PageCard";
import PageRow from "@/components/extensive/PageElements/Row/PageRow";
import { useMyUser } from "@/connections/User";
import {
CHART_TYPES,
JOBS_CREATED_CHART_TYPE,
Expand Down Expand Up @@ -57,6 +58,7 @@ export interface GraphicLegendProps {

const Dashboard = () => {
const t = useT();
const [, { user }] = useMyUser();
const { filters, setFilters, frameworks } = useDashboardContext();
const {
dashboardHeader,
Expand Down Expand Up @@ -283,7 +285,7 @@ const Dashboard = () => {
</When>
<BlurContainer
isBlur={isUserAllowed !== undefined ? !isUserAllowed?.allowed : false}
textInformation={NO_DATA_INFORMATION}
textInformation={user !== undefined ? NO_DATA_INFORMATION : <></>}
>
<div className="grid w-full grid-cols-3 gap-4">
{dashboardHeader.map((item, index) => (
Expand Down
12 changes: 12 additions & 0 deletions src/utils/MiddlewareMatcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ type CallbackInterface = () => Response | null;
export class MiddlewareMatcher {
private request: NextRequest;
private result?: Response | null;
private hasMatchOccurred: boolean = false;

constructor(request: NextRequest) {
this.request = request;
Expand All @@ -27,17 +28,20 @@ export class MiddlewareMatcher {
this.cache(_url);
}

this.hasMatchOccurred = true;
return output;
} else {
return null;
}
}

/**
* Continue response without any change
* @returns Next response
*/
next() {
this.setResult(() => NextResponse.next());
this.hasMatchOccurred = true;
return this;
}

Expand Down Expand Up @@ -96,6 +100,14 @@ export class MiddlewareMatcher {
return this.when(this.request.nextUrl.pathname !== url);
}

/**
* Check if any matches have occurred
* @returns boolean indicating if any matches have occurred
*/
hasMatch(): boolean {
return this.hasMatchOccurred;
}

/**
* set matcher result if there is none
* @param callback response handler
Expand Down