Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | 3x 3x 3x 3x 3x 3x 30x 15x 15x 2x 13x 13x 3x 10x 32x 10x 6x 4x 29x 30x 30x 30x 30x 30x 30x 30x 8x 30x 20x 6x 30x 26x 4x 4x 2x 1x | import { JSONValue } from "@growthbook/growthbook";
import { useFeatureValue } from "@growthbook/growthbook-react";
import { Alert as MuiAlert, AlertColor } from "@mui/material";
import Sentry from "platform/sentry";
import { usePersistedState } from "platform/usePersistedState";
import React, { useEffect } from "react";
type GlobalMessageData = { severity: AlertColor; message: string };
const SEVERITIES: readonly AlertColor[] = ["success", "info", "warning", "error"];
// { "severity": "info", "message": "Logins are <b>down</b>" }
function parseGlobalMessage(flag: JSONValue): GlobalMessageData | null {
if (flag === null) {
return null;
}
if (typeof flag !== "object" || Array.isArray(flag)) {
throw new Error("global_message is not an object");
}
const { severity, message } = flag;
if (message === undefined || message === "") {
return null;
}
Iif (typeof message !== "string") {
throw new Error("global_message.message is not a string");
}
const alertColor = SEVERITIES.find((s) => s === severity);
if (alertColor === undefined) {
throw new Error("global_message.severity is not a known severity");
}
return { severity: alertColor, message };
}
export function GlobalMessage() {
const flag = useFeatureValue<JSONValue>("global_message", null);
// dismissal is keyed on the banner's contents, so publishing anything different re-shows it
const [dismissed, setDismissed] = usePersistedState<string | null>("globalmessage.dismissed", null);
const flagJson = JSON.stringify(flag);
let data: GlobalMessageData | null = null;
let error: string | null = null;
try {
data = parseGlobalMessage(flag);
} catch (e) {
error = (e as Error).message;
}
// deps are strings because GrowthBook rebuilds the flag object on every refresh
useEffect(() => {
if (error !== null) {
Sentry.captureException(new Error(error), {
tags: { component: "GlobalMessage" },
extra: { flag: flagJson },
});
}
}, [error, flagJson]);
if (data === null) {
return null;
}
const key = `${data.severity}:${data.message}`;
if (key === dismissed) {
return null;
}
return (
<MuiAlert severity={data.severity} onClose={() => setDismissed(key)}>
<span dangerouslySetInnerHTML={{ __html: data.message }} />
</MuiAlert>
);
}
|