Skip to content

Commit

Permalink
fix: Add fallback UI for webgl init failure
Browse files Browse the repository at this point in the history
  • Loading branch information
benjaminpreiss committed Jul 30, 2024
1 parent ec7f4c1 commit e3ee05e
Show file tree
Hide file tree
Showing 9 changed files with 117 additions and 11 deletions.
4 changes: 3 additions & 1 deletion apps/info-dashboard/messages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -120,5 +120,7 @@
"node_status_node_overview_table_warning_status": "Not-earning",
"coming_soon_metrics_card": "Coming soon",
"leaderboard_node_provider_table_wallet_id_copy_text": "Copy",
"node_status_node_overview_table_wallet_id_copy_text": "Copy"
"node_status_node_overview_table_wallet_id_copy_text": "Copy",
"good_patient_spider_amuse": "WebGL is not supported / enabled",
"tangy_stout_guppy_loop": "Please enable WebGL to view this map. Follow the instructions at "
}
40 changes: 32 additions & 8 deletions apps/info-dashboard/src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@
import React from "react";
import * as m from "@/paraglide/messages.js";
import Head from "next/head";
import { Badge } from "@lilypad/shared-components";
import {
Badge,
ErrorBoundary,
WebGLFallback,
} from "@lilypad/shared-components";
import MetricsCard from "@/components/MetricsCard/MetricsCard";
import HeadingSection from "@/components/HeadingSection";
import { SectionContainer } from "@lilypad/shared-components";
Expand Down Expand Up @@ -35,7 +39,6 @@ import { DateTime } from "luxon";
import EmptyState from "@/components/EmptyState/EmptyState";
import ActiveNodesWorldMap from "@/components/ActiveNodesWorldMap/ActiveNodesWorldMap";
import { fetchNodes, toGeoJson } from "@/lib/fetchers/nodes";

export default function Home() {
const {
data: metricsData,
Expand Down Expand Up @@ -330,13 +333,34 @@ export default function Home() {
/>
</EmptyState>
) : (
<ActiveNodesWorldMap
geojson={toGeoJson(nodesData ?? [])}
protomapsApiKey={
process.env
.NEXT_PUBLIC_PROTOMAPS_API_KEY as string
<WebGLFallback
fallback={
<EmptyState
header={m.good_patient_spider_amuse()}
description={
<span>
{m.tangy_stout_guppy_loop()}
<a>https://get.webgl.org/</a>
</span>
}
>
<FeaturedIcon
spinIcon={false}
iconUrl={
alertAndFeedbackAlertCircle
}
/>
</EmptyState>
}
/>
>
<ActiveNodesWorldMap
geojson={toGeoJson(nodesData ?? [])}
protomapsApiKey={
process.env
.NEXT_PUBLIC_PROTOMAPS_API_KEY as string
}
/>
</WebGLFallback>
)}
</CardWithBorder>
</SectionContainer>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export default function ActiveNodesWorldMap({
return (
<div className="relative h-[60vh] w-full">
<Map
onError={(evt) => console.error(evt.error)}
initialViewState={{
latitude: 20,
longitude: 0,
Expand Down
4 changes: 2 additions & 2 deletions apps/info-dashboard/src/components/EmptyState/EmptyState.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { PropsWithChildren } from "react";
import { PropsWithChildren, type ReactNode } from "react";

export default function EmptyState({
children,
header,
description,
}: PropsWithChildren<{
header: string;
description: string;
description: ReactNode;
}>) {
return (
<div className="w-full h-[70vh] flex items-center flex-col justify-center space-y-uui-lg">
Expand Down
2 changes: 2 additions & 0 deletions packages/shared-components/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
export * from "./lib/Badge/index";
export * from "./lib/SectionContainer/index";
export * from "./lib/Anchor/index";
export * from "./lib/ErrorBoundary/index";
export * from "./lib/WebGLFallback/index";
export * from "./lib/types";
40 changes: 40 additions & 0 deletions packages/shared-components/lib/ErrorBoundary/ErrorBoundary.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { Component, type ErrorInfo, type ReactNode } from "react";

interface Props {
children?: ReactNode;
fallback: (error: Error) => ReactNode;
}

interface State {
error: Error | undefined;
}

class ErrorBoundary extends Component<Props, State> {
constructor(props: Props) {
super(props);
this.state = { error: undefined };
}

public state: State = {
error: undefined,
};

public static getDerivedStateFromError(error: Error): State {
// Update state so the next render will show the fallback UI.
return { error };
}

public componentDidCatch(error: Error, errorInfo: ErrorInfo) {
console.error("Uncaught error:", error, errorInfo);
}

public render() {
if (this.state.error) {
return this.props.fallback(this.state.error);
}

return this.props.children;
}
}

export default ErrorBoundary;
1 change: 1 addition & 0 deletions packages/shared-components/lib/ErrorBoundary/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as ErrorBoundary } from "./ErrorBoundary";
35 changes: 35 additions & 0 deletions packages/shared-components/lib/WebGLFallback/WebGLFallback.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import type { ReactNode } from "react";

function isWebglSupported() {
if (window.WebGLRenderingContext) {
const canvas = document.createElement("canvas");
try {
// Note that { failIfMajorPerformanceCaveat: true } can be passed as a second argument
// to canvas.getContext(), causing the check to fail if hardware rendering is not available. See
// https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/getContext
// for more details.
const context =
canvas.getContext("webgl2") || canvas.getContext("webgl");
if (context && typeof context.getParameter == "function") {
return true;
}
} catch (e) {
// WebGL is supported, but disabled
}
return false;
}
// WebGL not supported
return false;
}

// webgl doesnt exist on server. so this can be a client side only component.
export default function WebGLFallback({
fallback,
children,
}: {
fallback: ReactNode;
children: ReactNode;
}) {
if (isWebglSupported()) return children;
else return fallback;
}
1 change: 1 addition & 0 deletions packages/shared-components/lib/WebGLFallback/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as WebGLFallback } from "./WebGLFallback";

0 comments on commit e3ee05e

Please sign in to comment.