From 3705667741b3d8fa7e54230e845fb085173c3395 Mon Sep 17 00:00:00 2001 From: tnagorra Date: Thu, 17 Oct 2024 15:54:51 +0545 Subject: [PATCH] Define colorSelector for PER rating, area, benchmark - Define types for PER rating, area, benchmark - Add union type in PieChart for colors / colorSelector --- .../domain/PerAssessmentSummary/i18n.json | 4 +- .../domain/PerAssessmentSummary/index.tsx | 12 +- app/src/utils/domain/per.ts | 106 ++++++++++-------- .../PrivateCountryPreparedness/index.tsx | 19 +--- .../RatingByAreaChart/i18n.json | 2 +- app/src/views/PerExport/index.tsx | 15 +-- packages/ui/src/components/PieChart/index.tsx | 40 +++++-- 7 files changed, 104 insertions(+), 94 deletions(-) diff --git a/app/src/components/domain/PerAssessmentSummary/i18n.json b/app/src/components/domain/PerAssessmentSummary/i18n.json index 7ee21a0ce..b95201cd5 100644 --- a/app/src/components/domain/PerAssessmentSummary/i18n.json +++ b/app/src/components/domain/PerAssessmentSummary/i18n.json @@ -1,9 +1,9 @@ { - "namespace": "perAssessmentSummary", + "namespace": "common", "strings": { "perArea": "Area {areaId}", "benchmarksAssessed": "{totalQuestionCount} benchmarks assessed", "perAssessmentSummaryHeading": "Summary", - "benchmarksAssessedTitle": "benchmarks assessed : {allAnsweredResponses} / {totalQuestionCount}" + "benchmarksAssessedTitle": "Benchmarks assessed : {allAnsweredResponses} / {totalQuestionCount}" } } diff --git a/app/src/components/domain/PerAssessmentSummary/index.tsx b/app/src/components/domain/PerAssessmentSummary/index.tsx index ebfd49460..15b4cca4d 100644 --- a/app/src/components/domain/PerAssessmentSummary/index.tsx +++ b/app/src/components/domain/PerAssessmentSummary/index.tsx @@ -23,9 +23,8 @@ import { import { PartialForm } from '@togglecorp/toggle-form'; import { - PER_FALLBACK_COLOR, - perAreaColorMap, - perRatingColorMap, + getPerAreaColor, + getPerRatingColor, } from '#utils/domain/per'; import { type GoApiResponse } from '#utils/restRequest'; @@ -55,10 +54,7 @@ function numberOfComponentsSelector({ components } : { components: unknown[]}) { } function perRatingColorSelector({ ratingValue }: { ratingValue: number | undefined }) { - if (isDefined(ratingValue)) { - return perRatingColorMap[ratingValue]; - } - return PER_FALLBACK_COLOR; + return getPerRatingColor(ratingValue); } function perRatingLabelSelector({ @@ -269,7 +265,7 @@ function PerAssessmentSummary(props: Props) { className={styles.filledBar} style={{ height: `${getPercentage(rating.rating, averageRatingByAreaList.length)}%`, - backgroundColor: perAreaColorMap[Number(rating.areaId)], + backgroundColor: getPerAreaColor(Number(rating.areaId)), }} /> diff --git a/app/src/utils/domain/per.ts b/app/src/utils/domain/per.ts index 6c387b275..f360b949d 100644 --- a/app/src/utils/domain/per.ts +++ b/app/src/utils/domain/per.ts @@ -39,72 +39,84 @@ export function getCurrentPerProcessStep(status: PerProcessStatusResponse | unde export function getFormattedComponentName(component: PerComponent): string { const { component_num, component_letter, title } = component; - const prefix = [component_num, component_letter].filter(isDefined).join(' ').trim(); - - return `${prefix} : ${title}`; + return `${prefix}: ${title}`; } -export const perRatingColors = [ - 'var(--go-ui-color-dark-blue-40)', - 'var(--go-ui-color-dark-blue-30)', - 'var(--go-ui-color-dark-blue-20)', - 'var(--go-ui-color-dark-blue-10)', - 'var(--go-ui-color-gray-40)', - 'var(--go-ui-color-gray-30)', -]; - -export const perRatingColorMap: { - [key: string]: string; -} = { - 5: 'var(--go-ui-color-dark-blue-40)', - 4: 'var(--go-ui-color-dark-blue-30)', - 3: 'var(--go-ui-color-dark-blue-20)', - 2: 'var(--go-ui-color-dark-blue-10)', - 1: 'var(--go-ui-color-gray-40)', - 0: 'var(--go-ui-color-gray-30)', -}; +export const PER_FALLBACK_COLOR = 'var(--go-ui-color-gray-40)'; -export const perAreaColorMap: { [key: number]: string } = { - 1: 'var(--go-ui-color-purple-per)', - 2: 'var(--go-ui-color-orange-per)', - 3: 'var(--go-ui-color-blue-per)', - 4: 'var(--go-ui-color-teal-per)', - 5: 'var(--go-ui-color-red-per)', +export type PerRatingValue = 0 | 1 | 2 | 3 | 4 | 5; +const PER_RATING_VALUE_NOT_REVIEWED = 0 satisfies PerRatingValue; +const PER_RATING_VALUE_DOES_NOT_EXIST = 1 satisfies PerRatingValue; +const PER_RATING_VALUE_PARTIALLY_EXISTS = 2 satisfies PerRatingValue; +const PER_RATING_VALUE_NEEDS_IMPROVEMENT = 3 satisfies PerRatingValue; +const PER_RATING_VALUE_EXISTS_COULD_BE_STRENGTHENED = 4 satisfies PerRatingValue; +const PER_RATING_VALUE_HIGH_PERFORMANCE = 5 satisfies PerRatingValue; + +const perRatingColorMap: Record = { + [PER_RATING_VALUE_HIGH_PERFORMANCE]: 'var(--go-ui-color-dark-blue-40)', + [PER_RATING_VALUE_EXISTS_COULD_BE_STRENGTHENED]: 'var(--go-ui-color-dark-blue-30)', + [PER_RATING_VALUE_NEEDS_IMPROVEMENT]: 'var(--go-ui-color-dark-blue-20)', + [PER_RATING_VALUE_PARTIALLY_EXISTS]: 'var(--go-ui-color-dark-blue-10)', + [PER_RATING_VALUE_DOES_NOT_EXIST]: 'var(--go-ui-color-gray-40)', + [PER_RATING_VALUE_NOT_REVIEWED]: 'var(--go-ui-color-gray-30)', }; -export const perBenchmarkColorMap: { - [key: string]: string; -} = { - 1: 'var(--go-ui-color-dark-blue-40)', - 2: 'var(--go-ui-color-dark-blue-30)', - 5: 'var(--go-ui-color-dark-blue-10)', -}; +export function getPerRatingColor(value: number | undefined) { + if (isDefined(value)) { + return perRatingColorMap[value as PerRatingValue] ?? PER_FALLBACK_COLOR; + } + return PER_FALLBACK_COLOR; +} +export function perRatingColorSelector(item: { value: number | undefined }) { + return getPerRatingColor(item.value); +} -export const PER_FALLBACK_COLOR = 'var(--go-ui-color-gray-40)'; +export type PerAreaNumber = 1 | 2 | 3 | 4 | 5; +const PER_AREA_NUMBER_1 = 1 satisfies PerAreaNumber; +const PER_AREA_NUMBER_2 = 2 satisfies PerAreaNumber; +const PER_AREA_NUMBER_3 = 3 satisfies PerAreaNumber; +const PER_AREA_NUMBER_4 = 4 satisfies PerAreaNumber; +const PER_AREA_NUMBER_5 = 5 satisfies PerAreaNumber; + +const perAreaColorMap: Record = { + [PER_AREA_NUMBER_1]: 'var(--go-ui-color-purple-per)', + [PER_AREA_NUMBER_2]: 'var(--go-ui-color-orange-per)', + [PER_AREA_NUMBER_3]: 'var(--go-ui-color-blue-per)', + [PER_AREA_NUMBER_4]: 'var(--go-ui-color-teal-per)', + [PER_AREA_NUMBER_5]: 'var(--go-ui-color-red-per)', +}; -export function perRatingColorSelector(item: { - value: number | undefined; -}) { - if (isDefined(item.value)) { - return perRatingColorMap[item.value]; +export function getPerAreaColor(value: number | undefined) { + if (isDefined(value)) { + return perAreaColorMap[value as PerAreaNumber] ?? PER_FALLBACK_COLOR; } return PER_FALLBACK_COLOR; } - export function perAreaColorSelector(item: { value: number | undefined; }) { - if (isDefined(item.value)) { - return perRatingColorMap[item.value]; - } - return PER_FALLBACK_COLOR; + return getPerAreaColor(item.value); } +type PerBenchmarkId = 1 | 2 | 5; +const PER_BENCHMARK_YES = 1 satisfies PerBenchmarkId; +const PER_BENCHMARK_NO = 2 satisfies PerBenchmarkId; +const PER_BENCHMARK_PARTIALLY_EXISTS = 5 satisfies PerBenchmarkId; + +const perBenchmarkColorMap: Record = { + [PER_BENCHMARK_YES]: 'var(--go-ui-color-dark-blue-40)', + [PER_BENCHMARK_NO]: 'var(--go-ui-color-dark-blue-30)', + [PER_BENCHMARK_PARTIALLY_EXISTS]: 'var(--go-ui-color-dark-blue-10)', +}; + +export function getPerBenchmarkColor(id: number | undefined) { + return perBenchmarkColorMap[id as PerBenchmarkId] ?? PER_FALLBACK_COLOR; +} export function perBenchmarkColorSelector(item: { id: number; label: string; count: number; }) { - return perBenchmarkColorMap[item.id]; + return getPerBenchmarkColor(item.id); } diff --git a/app/src/views/CountryPreparedness/PrivateCountryPreparedness/index.tsx b/app/src/views/CountryPreparedness/PrivateCountryPreparedness/index.tsx index 072c61706..5ff6d44e3 100644 --- a/app/src/views/CountryPreparedness/PrivateCountryPreparedness/index.tsx +++ b/app/src/views/CountryPreparedness/PrivateCountryPreparedness/index.tsx @@ -51,10 +51,8 @@ import WikiLink from '#components/WikiLink'; import useRouting from '#hooks/useRouting'; import { getFormattedComponentName, - PER_FALLBACK_COLOR, - perAreaColorMap, + getPerAreaColor, perBenchmarkColorSelector, - perRatingColors, perRatingColorSelector, } from '#utils/domain/per'; import { @@ -250,9 +248,7 @@ function PrivateCountryPreparedness() { id: groupedComponentList[0].area.id, areaNum: groupedComponentList[0].area.area_num, title: groupedComponentList[0].area.title, - color: isDefined(groupedComponentList[0].area.area_num) - ? perAreaColorMap[groupedComponentList[0].area.area_num] - : PER_FALLBACK_COLOR, + color: getPerAreaColor(groupedComponentList[0].area.area_num), value: getAverage( groupedComponentList.map( (component) => ( @@ -525,7 +521,6 @@ function PrivateCountryPreparedness() { labelSelector={(item) => item.title ?? '??'} keySelector={numericIdSelector} colorSelector={perRatingColorSelector} - colors={perRatingColors} /> )} @@ -604,9 +599,7 @@ function PrivateCountryPreparedness() { > {prioritizationStats.componentsToBeStrengthened.map( (priorityComponent) => { - const progressBarColor = isDefined(priorityComponent.areaNumber) - ? perAreaColorMap[priorityComponent.areaNumber] - : PER_FALLBACK_COLOR; + const progressBarColor = getPerAreaColor(priorityComponent.areaNumber); return (
{assessmentStats.topRatedComponents.map((component) => { - const progressBarColor = isDefined(component.area.area_num) - ? perAreaColorMap[component.area.area_num] - : PER_FALLBACK_COLOR; + const progressBarColor = getPerAreaColor(component.area.area_num); return ( ( @@ -428,7 +424,6 @@ export function Component() { labelSelector={(item) => item.title ?? '??'} keySelector={numericIdSelector} colorSelector={perRatingColorSelector} - colors={perRatingColors} showPercentageInLegend /> @@ -507,9 +502,7 @@ export function Component() { headingLevel={3} > {assessmentStats.topRatedComponents.map((component) => { - const progressBarColor = isDefined(component.area.area_num) - ? perAreaColorMap[component.area.area_num] - : PER_FALLBACK_COLOR; + const progressBarColor = getPerAreaColor(component.area.area_num); return ( { +export type Props = { className?: string; legendClassName?: string; data: D[] | undefined | null; valueSelector: (datum: D) => number | undefined | null; labelSelector: (datum: D) => React.ReactNode; keySelector: (datum: D) => number | string; - colorSelector?: (datum: D) => string; - colors: string[]; pieRadius?: number; chartPadding?: number; showPercentageInLegend?: boolean; -} +} & ({ + colorSelector: (datum: D) => string; + colors?: never; +} | { + colors: string[]; + colorSelector?: never; +}) function PieChart(props: Props) { const { @@ -103,7 +107,8 @@ function PieChart(props: Props) { const renderingData = useMemo( () => { let endAngle = 0; - return data?.map((datum) => { + + const result = data?.map((datum) => { const value = valueSelector(datum); if (isNotDefined(value)) { return undefined; @@ -115,15 +120,28 @@ function PieChart(props: Props) { return { key: keySelector(datum), value, - color: isDefined(colorSelector) ? colorSelector(datum) : undefined, label: labelSelector(datum), startAngle: endAngle - currentAngle, percentage: getPercentage(value, totalValueSafe), endAngle, + + datum, }; }).filter(isDefined) ?? []; + + if (colorSelector) { + return result.map(({ datum, ...other }) => ({ + ...other, + color: colorSelector(datum), + })); + } + // eslint-disable-next-line @typescript-eslint/no-unused-vars + return result.map(({ datum, ...other }, i) => ({ + ...other, + color: colors[i % colors.length], + })); }, - [data, keySelector, valueSelector, labelSelector, totalValueSafe, colorSelector], + [data, keySelector, valueSelector, labelSelector, totalValueSafe, colorSelector, colors], ); return ( @@ -136,12 +154,12 @@ function PieChart(props: Props) { }} > - {renderingData.map((datum, i) => ( + {renderingData.map((datum) => ( (props: Props) {
- {renderingData.map((datum, i) => ( + {renderingData.map((datum) => ( (props: Props) { withoutLabelColon /> ) : datum.label} - color={isDefined(datum.color) ? datum.color : colors[i % colors.length]} + color={datum.color} /> ))}