diff --git a/spotlight-client/src/App.test.tsx b/spotlight-client/src/App.test.tsx index b8c38282..74390e84 100644 --- a/spotlight-client/src/App.test.tsx +++ b/spotlight-client/src/App.test.tsx @@ -128,16 +128,14 @@ describe("navigation", () => { const homeLink = inNav.getByRole("link", { name: "Spotlight" }); const tenantLink = inNav.getByRole("link", { name: "North Dakota" }); const sentencingLink = await screen.findByRole("link", { - name: "Racial Disparities Data", + name: "Explore Prison Data", }); fireEvent.click(sentencingLink); // NOTE: *ByRole queries can be too expensive to run async with this much DOM, // so we are using *ByTestId queries here instead await waitFor(async () => - expect(await screen.findByTestId("PageTitle")).toHaveTextContent( - "Racial Disparities" - ) + expect(await screen.findByTestId("PageTitle")).toHaveTextContent("Prison") ); fireEvent.click(tenantLink); diff --git a/spotlight-client/src/OtherNarrativeLinksPreview/OtherNarrativeLinksPreview.tsx b/spotlight-client/src/OtherNarrativeLinksPreview/OtherNarrativeLinksPreview.tsx index bedf958d..b52bbd62 100644 --- a/spotlight-client/src/OtherNarrativeLinksPreview/OtherNarrativeLinksPreview.tsx +++ b/spotlight-client/src/OtherNarrativeLinksPreview/OtherNarrativeLinksPreview.tsx @@ -15,25 +15,27 @@ // along with this program. If not, see . // ============================================================================= -import { Link } from "@reach/router"; +import { + Tabs, + TabList as BasicTabList, + Tab, + TabPanel as BasicTabPanel, +} from "@recidiviz/design-system"; import { ascending } from "d3-array"; import { observer } from "mobx-react-lite"; import { rem } from "polished"; import React from "react"; -import { animated, useSpring } from "react-spring/web.cjs"; import styled from "styled-components/macro"; -import { track } from "../analytics"; -import { NarrativeTypeId, TenantId } from "../contentApi/types"; +import { DEFAULT_SELECTED_TAB, DEFAULT_CAROUSEL_INTERVAL } from "../constants"; +import { NarrativeTypeId } from "../contentApi/types"; import RacialDisparitiesNarrative from "../contentModels/RacialDisparitiesNarrative"; import SystemNarrative from "../contentModels/SystemNarrative"; import { Narrative } from "../contentModels/types"; import MetricVizMapper from "../MetricVizMapper"; import ModelHydrator from "../ModelHydrator"; import BarChartPair from "../RacialDisparitiesNarrativePage/BarChartPair"; -import getUrlForResource from "../routerUtils/getUrlForResource"; import { useDataStore } from "../StoreProvider"; -import { breakpoints, colors } from "../UiLibrary"; -import Arrow from "../UiLibrary/Arrow"; +import { breakpoints, colors, fluidFontSizeStyles } from "../UiLibrary"; // grid styles adapted from IE-safe auto placement grid // https://css-tricks.com/css-grid-in-ie-faking-an-auto-placement-grid-with-gaps/ @@ -45,69 +47,63 @@ const Wrapper = styled.div` } `; -const LinkList = styled.ul` - display: flex; - flex-wrap: wrap; - font-size: ${rem(24)}; - line-height: 1.5; - /* this margin makes the cells flush left and right */ - margin: ${rem(48)} -${rem(32)} 0 0; +const ChartTitle = styled.div` + margin-top: ${rem(16)}; + font-size: ${rem(16)}; `; -const LinkListItem = styled.li` - /* creates gaps */ - border: 0 solid transparent; - border-width: 0 ${rem(32)} 0 0; - flex: 0 0 auto; - white-space: nowrap; - /* use width to create 1-4 columns, depending on screen size */ - width: 100%; - - @media (min-width: ${breakpoints.tablet[0]}px) { - width: calc(100% / 1); - } - - @media (min-width: ${breakpoints.desktop[0]}px) { - width: calc(100% / 1); - } - - @media (min-width: ${breakpoints.xl[0]}px) { - width: calc(100% / 2); - } +const ChartPreview = styled.div` + margin-top: ${rem(16)}; + height: ${rem(440)}; + animation: fadeIn 0.5s ease; - a { - border-top: 1px solid ${colors.rule}; - color: ${colors.text}; - display: block; - padding-right: ${rem(8)}; - padding-top: ${rem(24)}; - padding-bottom: ${rem(24)}; - text-decoration: none; - width: 100%; + @media screen and (max-width: ${breakpoints.tablet[0]}px) { + height: ${rem(330)}; + overflow: hidden; } - a:not(:last-child) { - border-bottom: 1px solid ${colors.rule}; + @keyframes fadeIn { + from { + opacity: 0; + } + to { + opacity: 1; + } } `; -const LinkText = styled.span` - white-space: normal; +const TabList = styled(BasicTabList)` + display: flex; + align-items: center; + flex-wrap: nowrap; + padding: 0; + overflow-x: auto; `; -const ChartTitle = styled.span` - font-size: ${rem(16)}; +const TabItem = styled(Tab)<{ minSize: number; maxSize: number }>` + padding: ${rem(25)} 0; + color: ${colors.caption}; + border-bottom: 1px solid transparent; + font-family: "Libre Baskerville"; + font-style: normal; + font-weight: 400; + + &:first-child { + margin-left: 0; + } + + ${(props) => fluidFontSizeStyles(props.minSize, props.maxSize)} `; -const ChartPreview = styled.div` - padding-top: ${rem(16)}; +const TabPanel = styled(BasicTabPanel)` + padding: 0; `; const PREVIEW_ORDER: NarrativeTypeId[] = [ "Prison", "RacialDisparities", - "Parole", "Probation", + "Parole", "Sentencing", ]; @@ -117,7 +113,6 @@ const ChartPreviewComponent: React.FC<{ if (narrative instanceof SystemNarrative && narrative.preview) return ( <> - {narrative.previewTitle} + {narrative.previewTitle} ); if (narrative instanceof RacialDisparitiesNarrative) { @@ -141,50 +137,74 @@ const RacialDisparitiesPreview = observer( return ( <> - Population by Race/Ethnicity {narrative.populationDataSeries && ( - + + + )} + Population by Race/Ethnicity ); } ); -const NarrativeLink: React.FC<{ - narrative: Narrative; - tenantId: TenantId; -}> = observer(({ narrative, tenantId }) => { - const [animationStyles, setAnimationStyles] = useSpring(() => ({ - opacity: 0, - from: { opacity: 0 }, - })); +const NarrativeTabs: React.FC<{ + narratives: Narrative[]; + onTabChange: (selectedTab: NarrativeTypeId) => void; +}> = observer(({ narratives, onTabChange }) => { + const tabs = narratives.map((narrative) => narrative.id); + const defaultTab = tabs.includes(DEFAULT_SELECTED_TAB) + ? DEFAULT_SELECTED_TAB + : tabs[0]; + + const [selectedTab, selectTab] = React.useState(defaultTab); + const [tabIndex, setTabIndex] = React.useState(tabs.indexOf(defaultTab)); + const [isHovered, setHovered] = React.useState(false); + + React.useEffect(() => { + const nextIndex = (tabIndex + 1) % tabs.length; + + const timer = setTimeout( + () => { + setTabIndex(nextIndex); + selectTab(tabs[nextIndex]); + }, + isHovered ? DEFAULT_CAROUSEL_INTERVAL * 1000 : DEFAULT_CAROUSEL_INTERVAL + ); + + onTabChange(selectedTab); + + return () => clearTimeout(timer); + }, [tabIndex, selectedTab, onTabChange, tabs, isHovered]); return ( - - - track("narrative_body_link_clicked", { - category: "navigation", - label: narrative.id, - }) - } - onMouseOver={() => setAnimationStyles({ opacity: 1 })} - onFocus={() => setAnimationStyles({ opacity: 1 })} - onMouseOut={() => setAnimationStyles({ opacity: 0 })} - onBlur={() => setAnimationStyles({ opacity: 0 })} - > - {narrative.title} Data  - - - - - - + setTabIndex(index)} + onMouseOver={() => setHovered(true)} + onFocus={() => setHovered(true)} + onMouseOut={() => setHovered(false)} + onBlur={() => setHovered(false)} + > + + {narratives.map((narrative) => ( + selectTab(narrative.id)} + > + {narrative.title} + + ))} + + {narratives.map((narrative) => ( + + + + ))} + ); }); @@ -192,7 +212,9 @@ const NarrativeLink: React.FC<{ * Produces a grid of links to available narratives for the current tenant. * If there is a current narrative selected, it will be excluded from the grid. */ -const OtherNarrativeLinksPreview = (): React.ReactElement | null => { +const OtherNarrativeLinksPreview: React.FC<{ + onTabChange: (selectedTab: NarrativeTypeId) => void; +}> = ({ onTabChange }): React.ReactElement | null => { const { tenant } = useDataStore(); if (!tenant) return null; @@ -209,17 +231,10 @@ const OtherNarrativeLinksPreview = (): React.ReactElement | null => { return ( - - {narrativesToDisplay.map((narrative) => { - return ( - - ); - })} - + ); }; diff --git a/spotlight-client/src/PageTenant/PageTenant.tsx b/spotlight-client/src/PageTenant/PageTenant.tsx index 5c05772f..47fbadf1 100644 --- a/spotlight-client/src/PageTenant/PageTenant.tsx +++ b/spotlight-client/src/PageTenant/PageTenant.tsx @@ -21,21 +21,51 @@ import { observer } from "mobx-react-lite"; import { rem } from "polished"; import React from "react"; import styled from "styled-components/macro"; -import { NAV_BAR_HEIGHT } from "../constants"; +import { DEFAULT_SELECTED_TAB, NAV_BAR_HEIGHT } from "../constants"; +import { NarrativeTypeId } from "../contentApi/types"; import OtherNarrativeLinksPreview from "../OtherNarrativeLinksPreview"; import { useDataStore } from "../StoreProvider"; -import { breakpoints, PageSection, PageTitle } from "../UiLibrary"; +import { breakpoints, PageSection, PageTitle, typefaces } from "../UiLibrary"; +import ExploreNarrativeButton from "../UiLibrary/ExploreNarrativeButton"; import withRouteSync from "../withRouteSync"; +const Page = styled.article` + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + + a { + text-decoration: none; + } + + @media screen and (min-width: ${breakpoints.xl[0]}px) { + flex-direction: row; + min-height: calc(100vh - ${rem(NAV_BAR_HEIGHT)}); + padding: 0 ${rem(120)}; + gap: ${rem(70)}; + } +`; + const Introduction = styled(PageSection)` + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; padding-bottom: ${rem(48)}; padding-top: ${rem(48)}; + @media screen and (min-width: ${breakpoints.xl[0]}px) { + padding-left: 0; + padding-right: 0; + max-width: 40%; + } + @media screen and (min-width: ${breakpoints.tablet[0]}px) { - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; + a { + margin-right: auto; + } + /* try to keep the links "above the fold" */ min-height: calc(100vh - ${rem(NAV_BAR_HEIGHT)} - ${rem(130)}); @@ -46,28 +76,63 @@ const Introduction = styled(PageSection)` } `; -const Links = styled(PageSection)``; +const Links = styled(PageSection)` + width: 100%; + + @media screen and (min-width: ${breakpoints.xl[0]}px) { + width: 60%; + padding: 0; + } +`; const Title = styled(PageTitle)` - font-size: ${rem(40)}; - max-width: ${rem(1100)}; + font-size: ${rem(34)}; + + @media screen and (max-width: ${breakpoints.tablet[0]}px) { + font-size: ${rem(28)}; + } +`; + +const Subtitle = styled.h2` + font-family: ${typefaces.body}; + letter-spacing: -0.04em; + font-size: ${rem(21)}; + margin-top: ${rem(24)}; + + @media screen and (max-width: ${breakpoints.tablet[0]}px) { + font-size: ${rem(18)}; + } `; const PageTenant: React.FC = () => { const { tenant } = useDataStore(); + const [narrativeId, setNarrativeId] = React.useState( + DEFAULT_SELECTED_TAB + ); if (!tenant) return null; return ( // tenant may be briefly undefined during initial page load -
+ - {HTMLReactParser(tenant.description)} + + {HTMLReactParser(tenant.description)} + {tenant.ctaCopy && ( + <Subtitle>{HTMLReactParser(tenant.ctaCopy)}</Subtitle> + )} + + - + setNarrativeId(selectedTab)} + /> -
+ ); }; diff --git a/spotlight-client/src/RacialDisparitiesNarrativePage/BarChartPair.tsx b/spotlight-client/src/RacialDisparitiesNarrativePage/BarChartPair.tsx index fa49cc84..e14da5b9 100644 --- a/spotlight-client/src/RacialDisparitiesNarrativePage/BarChartPair.tsx +++ b/spotlight-client/src/RacialDisparitiesNarrativePage/BarChartPair.tsx @@ -25,10 +25,10 @@ import VizControls, { VizControlsProps } from "../VizControls"; import VizNotes from "../VizNotes"; const CHART_HEIGHT = 165; - const CHART_HEIGHT_MOBILE = 100; -const CHART_HEIGHT_PREVIEW = 135; +const CHART_HEIGHT_PREVIEW = 420; +const CHART_HEIGHT_PREVIEW_MOBILE = 300; const Wrapper = styled.div` padding: ${rem(48)} 0; @@ -57,13 +57,30 @@ export default function BarChartPair({ ItemToHighlight | undefined >(); - let chartHeight = useBreakpoint(CHART_HEIGHT, [ + const chartHeight = useBreakpoint(CHART_HEIGHT, [ "mobile-", CHART_HEIGHT_MOBILE, ]); + const previewChartHeight = useBreakpoint(CHART_HEIGHT_PREVIEW, [ + "mobile-", + CHART_HEIGHT_PREVIEW_MOBILE, + ]); + if (preview) { - chartHeight = CHART_HEIGHT_PREVIEW; + return ( + <> + + + ); } return ( @@ -80,7 +97,6 @@ export default function BarChartPair({ title={data[0].label} height={chartHeight} highlighted={highlightedCategory} - showLegend={false} /> . +// ============================================================================= + +import { Button as BasicButton } from "@recidiviz/design-system"; +import { Link } from "@reach/router"; +import { observer } from "mobx-react-lite"; +import { rem } from "polished"; +import React from "react"; +import startCase from "lodash/startCase"; +import styled from "styled-components/macro"; +import { track } from "../analytics"; +import { NarrativeTypeId, TenantId } from "../contentApi/types"; +import getUrlForResource from "../routerUtils/getUrlForResource"; +import colors from "./colors"; +import Arrow from "./Arrow"; +import { fluidFontSizeStyles } from "./typography"; + +const Button = styled(BasicButton)<{ minSize: number; maxSize: number }>` + background: ${colors.text}; + padding: ${rem(16)} ${rem(24)}; + box-shadow: 0px 10px 20px rgba(0, 108, 103, 0.3); + + span { + display: flex; + flex-wrap: wrap; + align-items: center; + justify-content: center; + + strong { + animation: fadeInUp 0.5s ease; + } + } + + svg { + margin-left: ${rem(16)}; + } + + @keyframes fadeInUp { + from { + opacity: 0; + transform: translateY(${rem(30)}); + } + to { + opacity: 1; + transform: translateY(0); + } + } + + ${(props) => fluidFontSizeStyles(props.minSize, props.maxSize)} +`; + +const ExploreNarrativeButton: React.FC<{ + narrativeId: NarrativeTypeId; + tenantId: TenantId; +}> = observer(({ narrativeId, tenantId }) => { + return ( + + track("narrative_body_link_clicked", { + category: "navigation", + label: narrativeId, + }) + } + > + + + ); +}); + +export default ExploreNarrativeButton; diff --git a/spotlight-client/src/UiLibrary/breakpoints.ts b/spotlight-client/src/UiLibrary/breakpoints.ts index 2b2bad7b..8d5a547f 100644 --- a/spotlight-client/src/UiLibrary/breakpoints.ts +++ b/spotlight-client/src/UiLibrary/breakpoints.ts @@ -19,8 +19,8 @@ * these are overrides to defaults in @w11r/use-breakpoint */ export default { - mobile: [320, 767], - tablet: [768, 1023], + mobile: [400, 768], + tablet: [769, 1023], desktop: [1024, 1279], xl: [1280, 10000], }; diff --git a/spotlight-client/src/VizDemographicsByCategory/VizDemographicsByCategory.tsx b/spotlight-client/src/VizDemographicsByCategory/VizDemographicsByCategory.tsx index b3ed2c66..23ee8dd2 100644 --- a/spotlight-client/src/VizDemographicsByCategory/VizDemographicsByCategory.tsx +++ b/spotlight-client/src/VizDemographicsByCategory/VizDemographicsByCategory.tsx @@ -82,6 +82,7 @@ const VizDemographicsByCategory: React.FC = ({ ) : ( item.dataSeries.map( diff --git a/spotlight-client/src/charts/BubbleChart.tsx b/spotlight-client/src/charts/BubbleChart.tsx index d0098f6d..af02099b 100644 --- a/spotlight-client/src/charts/BubbleChart.tsx +++ b/spotlight-client/src/charts/BubbleChart.tsx @@ -72,11 +72,13 @@ const LegendWrapper = styled.div` type BubbleChartProps = { data: CategoricalChartRecord[]; height: number; + showLegend?: boolean; }; export default function BubbleChart({ data, height, + showLegend = true, }: BubbleChartProps): React.ReactElement { const { highlighted, setHighlighted } = useHighlightedItem(); @@ -132,13 +134,15 @@ export default function BubbleChart({ size={[width, height]} /> - - - + {showLegend && ( + + + + )} )} diff --git a/spotlight-client/src/charts/ProportionalBar.tsx b/spotlight-client/src/charts/ProportionalBar.tsx index bec33a17..eb0836b3 100644 --- a/spotlight-client/src/charts/ProportionalBar.tsx +++ b/spotlight-client/src/charts/ProportionalBar.tsx @@ -75,6 +75,7 @@ type ProportionalBarProps = { highlighted?: ItemToHighlight; setHighlighted?: (item?: ItemToHighlight) => void; showLegend?: boolean; + preview?: boolean; title: string; }; @@ -84,6 +85,7 @@ export default function ProportionalBar({ highlighted: externalHighlighted, setHighlighted: setExternalHighlighted, showLegend = true, + preview = false, title, }: ProportionalBarProps): React.ReactElement { const { @@ -135,12 +137,15 @@ export default function ProportionalBar({ /> - - - {title} - {noData && ", No Data"} - - {showLegend && ( + {showLegend && ( + + {!preview && ( + + {title} + {noData && ", No Data"} + + )} + - )} - + + )} )} diff --git a/spotlight-client/src/charts/WindowedTimeSeries.tsx b/spotlight-client/src/charts/WindowedTimeSeries.tsx index 58bf2a28..35c643b9 100644 --- a/spotlight-client/src/charts/WindowedTimeSeries.tsx +++ b/spotlight-client/src/charts/WindowedTimeSeries.tsx @@ -166,6 +166,11 @@ const WindowedTimeSeries: React.FC<{ matte: true, }; + if (!showMinimap) { + MARGIN.left = 0; + MARGIN.bottom = 0; + } + return ( {({ measureRef, width }) => { @@ -247,16 +252,7 @@ const WindowedTimeSeries: React.FC<{ /> ) : ( // @ts-expect-error Semiotic typedefs are wrong, can be true for default matte - + )} diff --git a/spotlight-client/src/constants.ts b/spotlight-client/src/constants.ts index 967606d0..bac92ff6 100644 --- a/spotlight-client/src/constants.ts +++ b/spotlight-client/src/constants.ts @@ -26,7 +26,7 @@ export const ERROR_MESSAGES = { export const NAV_BAR_HEIGHT = 80; -export const FOOTER_HEIGHT = 248; +export const FOOTER_HEIGHT = 130; export const REVOCATION_TYPE_LABELS = { ABSCOND: "Absconsion", @@ -40,3 +40,7 @@ export const SENTENCE_TYPE_LABELS = { PROBATION: "Probation", DUAL_SENTENCE: "Both", }; + +export const DEFAULT_SELECTED_TAB = "Prison"; + +export const DEFAULT_CAROUSEL_INTERVAL = 5000; diff --git a/spotlight-client/src/contentApi/sources/us_id.ts b/spotlight-client/src/contentApi/sources/us_id.ts index 7d037d59..ebf9da26 100644 --- a/spotlight-client/src/contentApi/sources/us_id.ts +++ b/spotlight-client/src/contentApi/sources/us_id.ts @@ -66,7 +66,9 @@ in a Idaho court may occasionally complete their supervision in a different stat const content: TenantContent = { name: "Idaho", - description: "Placeholder for IDOC Mission", + description: "Explore data from Idaho’s corrections system.", + ctaCopy: `The Idaho Department of Corrections aims to protect the public, our staff, + and those within our custody and supervision through safety, accountability, partnerships and providing opportunities for change.`, coBrandingCopy: 'Produced in collaboration with the Idaho Department of Correction.', feedbackUrl: diff --git a/spotlight-client/src/contentApi/sources/us_nd.ts b/spotlight-client/src/contentApi/sources/us_nd.ts index 3d58ca40..de3bfb81 100644 --- a/spotlight-client/src/contentApi/sources/us_nd.ts +++ b/spotlight-client/src/contentApi/sources/us_nd.ts @@ -83,9 +83,9 @@ in a North Dakota court may occasionally complete their supervision in a differe const content: TenantContent = { name: "North Dakota", description: - "Our mission is to transform lives, influence change, and strengthen community. Transparency is a critical element of our mission; sharing information builds greater accountability between the DOCR and the communities we serve.", - coBrandingCopy: - 'Produced in collaboration with the North Dakota Department of Corrections and Rehabilitation.', + "Our mission is to transform lives, influence change, and strengthen community.", + ctaCopy: `At the North Dakota Department of Corrections and Rehabilitation, transparency is a critical element of our mission; sharing information builds greater accountability between the DOCR and the communities we serve.`, + coBrandingCopy: `Produced in collaboration with the North Dakota Department of Corrections and Rehabilitation.`, feedbackUrl: "https://docs.google.com/forms/d/e/1FAIpQLSc3_wV2ltGumMdGTcLehUM41tQri0ZW5RjIKh0JJlhpJGE9Hg/viewform", demographicCategories: { diff --git a/spotlight-client/src/contentApi/sources/us_pa.ts b/spotlight-client/src/contentApi/sources/us_pa.ts index 172e5ca4..c0c52d66 100644 --- a/spotlight-client/src/contentApi/sources/us_pa.ts +++ b/spotlight-client/src/contentApi/sources/us_pa.ts @@ -19,12 +19,9 @@ import { TenantContent } from "../types"; const content: TenantContent = { name: "Pennsylvania", - description: ` - The Pennsylvania Department of Corrections (DOC) - is committed to enhancing public safety. The DOC's mission is to reduce criminal - behavior by providing individualized treatment and education to incarcerated - individuals, resulting in successful community reintegration through accountability - and positive change.`, + description: `The Pennsylvania Department of Corrections (DOC) + is committed to enhancing public safety.`, + ctaCopy: `The DOC's mission is to reduce criminal behavior by providing individualized treatment and education to incarcerated individuals, resulting in successful community reintegration through accountability and positive change.`, coBrandingCopy: 'Produced in collaboration with the Pennsylvania Department of Corrections.', feedbackUrl: "https://forms.gle/7bZMpgGR69uaW1eNA", diff --git a/spotlight-client/src/contentApi/sources/us_tn.ts b/spotlight-client/src/contentApi/sources/us_tn.ts index 02705d11..0210f193 100644 --- a/spotlight-client/src/contentApi/sources/us_tn.ts +++ b/spotlight-client/src/contentApi/sources/us_tn.ts @@ -66,7 +66,9 @@ in a Tennessee court may occasionally complete their supervision in a different const content: TenantContent = { name: "Tennessee", - description: "Placeholder for TDOC Mission", + description: "Explore data from Tennessee’s corrections system.", + ctaCopy: `The Tennessee Department of Correction has an inherent responsibility to provide those + within our custody with opportunities to grow. Sharing information builds greater accountability between our department and the communities we serve.`, coBrandingCopy: 'Produced in collaboration with the Tennessee Department of Correction.', feedbackUrl: diff --git a/spotlight-client/src/contentApi/types.ts b/spotlight-client/src/contentApi/types.ts index 9215f735..94d2a2ae 100644 --- a/spotlight-client/src/contentApi/types.ts +++ b/spotlight-client/src/contentApi/types.ts @@ -43,6 +43,7 @@ export type DemographicCategoryFilter = { export type TenantContent = { name: string; description: string; + ctaCopy?: string; coBrandingCopy: string; feedbackUrl: string; smallDataDisclaimer: string; diff --git a/spotlight-client/src/contentModels/Tenant.ts b/spotlight-client/src/contentModels/Tenant.ts index c2cf234b..95398089 100644 --- a/spotlight-client/src/contentModels/Tenant.ts +++ b/spotlight-client/src/contentModels/Tenant.ts @@ -26,6 +26,7 @@ type InitOptions = { id: TenantId; name: string; description: string; + ctaCopy?: string; coBrandingCopy: string; feedbackUrl: string; smallDataDisclaimer: string; @@ -48,6 +49,8 @@ export default class Tenant { readonly description: string; + readonly ctaCopy?: string; + readonly coBrandingCopy: string; readonly feedbackUrl: string; @@ -64,6 +67,7 @@ export default class Tenant { id, name, description, + ctaCopy, coBrandingCopy, feedbackUrl, smallDataDisclaimer, @@ -74,6 +78,7 @@ export default class Tenant { this.id = id; this.name = name; this.description = description; + this.ctaCopy = ctaCopy; this.coBrandingCopy = coBrandingCopy; this.feedbackUrl = feedbackUrl; this.smallDataDisclaimer = smallDataDisclaimer; @@ -140,6 +145,7 @@ export function createTenant({ tenantId }: TenantFactoryOptions): Tenant { id: tenantId, name: allTenantContent.name, description: allTenantContent.description, + ctaCopy: allTenantContent.ctaCopy, coBrandingCopy: allTenantContent.coBrandingCopy, feedbackUrl: allTenantContent.feedbackUrl, smallDataDisclaimer: allTenantContent.smallDataDisclaimer, diff --git a/spotlight-client/src/contentModels/__fixtures__/tenant_content_exhaustive.ts b/spotlight-client/src/contentModels/__fixtures__/tenant_content_exhaustive.ts index 7e7a214b..6198e25b 100644 --- a/spotlight-client/src/contentModels/__fixtures__/tenant_content_exhaustive.ts +++ b/spotlight-client/src/contentModels/__fixtures__/tenant_content_exhaustive.ts @@ -32,6 +32,7 @@ type ExhaustiveTenantContent = Required & const content: ExhaustiveTenantContent = { name: "Test Tenant", description: "test tenant description", + ctaCopy: "test tenant call to action", coBrandingCopy: "test tenant co-branding", feedbackUrl: "https://example.com/feedback", smallDataDisclaimer: "test small data disclaimer",