Skip to content

Commit

Permalink
Merge pull request #1361 from IFRCGo/feature/per-consideration
Browse files Browse the repository at this point in the history
Add color in the per dashboard and per export
  • Loading branch information
samshara authored Oct 17, 2024
2 parents 93f30c6 + 81dc3bd commit 13687b7
Show file tree
Hide file tree
Showing 24 changed files with 377 additions and 140 deletions.
10 changes: 10 additions & 0 deletions .changeset/spicy-dragons-teach.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
"@ifrc-go/ui": patch
---

- PieChart Component

- Added a `colorSelector` prop to select color for each pie

- ProgressBar Component
- Introduced a `color` prop to customize the progress bar's color
5 changes: 5 additions & 0 deletions .changeset/tricky-hornets-trade.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"go-web-app": patch
---

Added color mapping based on PER Area and Rating across all PER charts
4 changes: 2 additions & 2 deletions app/src/components/domain/PerAssessmentSummary/i18n.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
{
"namespace": "common",
"strings": {
"multiImageArea": "Area {areaId}",
"perArea": "Area {areaId}",
"benchmarksAssessed": "{totalQuestionCount} benchmarks assessed",
"perAssessmentSummaryHeading": "Summary",
"benchmarksAssessedTitle": "benchmarks assessed : {allAnsweredResponses} / {totalQuestionCount}"
"benchmarksAssessedTitle": "Benchmarks assessed : {allAnsweredResponses} / {totalQuestionCount}"
}
}
53 changes: 31 additions & 22 deletions app/src/components/domain/PerAssessmentSummary/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ import {
} from '@togglecorp/fujs';
import { PartialForm } from '@togglecorp/toggle-form';

import {
getPerAreaColor,
getPerRatingColor,
} from '#utils/domain/per';
import { type GoApiResponse } from '#utils/restRequest';

import i18n from './i18n.json';
Expand All @@ -43,14 +47,25 @@ interface Props {
areaIdToTitleMap: Record<number, string | undefined>;
}

const colors = [
'var(--go-ui-color-red-90)',
'var(--go-ui-color-red-70)',
'var(--go-ui-color-red-50)',
'var(--go-ui-color-red-40)',
'var(--go-ui-color-red-20)',
'var(--go-ui-color-red-10)',
];
const progressBarColor = 'var(--go-ui-color-dark-blue-40)';

function numberOfComponentsSelector({ components } : { components: unknown[]}) {
return components.length;
}

function perRatingColorSelector({ ratingValue }: { ratingValue: number | undefined }) {
return getPerRatingColor(ratingValue);
}

function perRatingLabelSelector({
ratingValue,
ratingDisplay,
}: {
ratingValue?: number;
ratingDisplay?: string;
}): string {
return `${ratingValue}-${ratingDisplay}`;
}

function PerAssessmentSummary(props: Props) {
const {
Expand Down Expand Up @@ -142,9 +157,10 @@ function PerAssessmentSummary(props: Props) {
(areaResponse) => {
// NOTE: do we take the average of only rated components or of all the
// components?
// Also, 'component.rating' refers to the component ID and is misnamed.
const filteredComponents = areaResponse?.component_responses?.filter(
(component) => isDefined(component?.rating)
&& component.rating !== 0,
&& component.rating !== 1,
) ?? [];

if (filteredComponents.length === 0) {
Expand Down Expand Up @@ -173,7 +189,7 @@ function PerAssessmentSummary(props: Props) {
areaId,
rating: averageRatingByAreaMap[Number(areaId)] ?? 0,
areaDisplay: resolveToString(
strings.multiImageArea,
strings.perArea,
{ areaId },
),
}),
Expand Down Expand Up @@ -208,6 +224,7 @@ function PerAssessmentSummary(props: Props) {
},
)}
value={allAnsweredResponses?.length ?? 0}
color={progressBarColor}
totalValue={totalQuestionCount}
description={(
<div className={styles.answerCounts}>
Expand All @@ -228,18 +245,9 @@ function PerAssessmentSummary(props: Props) {
<StackedProgressBar
className={styles.componentRating}
data={statusGroupedComponentList ?? []}
// FIXME: don't use inline selectors
valueSelector={
(statusGroupedComponent) => (
statusGroupedComponent.components.length
)
}
// FIXME: don't use inline selectors
colorSelector={(_, i) => colors[i]}
// FIXME: don't use inline selectors
labelSelector={
(statusGroupedComponent) => `${statusGroupedComponent.ratingValue}-${statusGroupedComponent.ratingDisplay}`
}
valueSelector={numberOfComponentsSelector}
colorSelector={perRatingColorSelector}
labelSelector={perRatingLabelSelector}
/>
<div className={styles.avgComponentRating}>
{averageRatingByAreaList.map(
Expand All @@ -257,6 +265,7 @@ function PerAssessmentSummary(props: Props) {
className={styles.filledBar}
style={{
height: `${getPercentage(rating.rating, averageRatingByAreaList.length)}%`,
backgroundColor: getPerAreaColor(Number(rating.areaId)),
}}
/>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
.total-progress {
.answer-counts {
display: flex;
color: var(--go-ui-color-dark-blue-40);
gap: var(--go-ui-spacing-lg);
}
}
Expand Down Expand Up @@ -37,7 +38,7 @@
height: 4rem;

.filled-bar {
background-color: var(--go-ui-color-primary-red);
background-color: var(--go-ui-color-dark-blue-40);
width: 100%;
}
}
Expand Down
6 changes: 5 additions & 1 deletion app/src/hooks/useNumericChartData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ interface Options<DATUM> {
keySelector: (d: DATUM, index: number) => number | string;
xValueSelector: (d: DATUM, index: number) => number | undefined | null;
yValueSelector: (d: DATUM, index: number) => number | undefined | null;
colorSelector?: (d: DATUM, index: number) => string;
xAxisHeight?: number;
yAxisWidth?: number;
chartMargin?: Rect;
Expand All @@ -57,6 +58,7 @@ function useNumericChartData<DATUM>(data: DATUM[] | null | undefined, options: O
keySelector,
xValueSelector,
yValueSelector,
colorSelector,
chartMargin = defaultChartMargin,
chartPadding = defaultChartPadding,
numXAxisTicks: numXAxisTicksFromProps = 'auto',
Expand Down Expand Up @@ -87,6 +89,7 @@ function useNumericChartData<DATUM>(data: DATUM[] | null | undefined, options: O
() => data?.map(
(datum, i) => {
const key = keySelector(datum, i);
const color = isDefined(colorSelector) ? colorSelector(datum, i) : undefined;
const xValue = xValueSelector(datum, i);
const yValue = yValueSelector(datum, i);

Expand All @@ -96,6 +99,7 @@ function useNumericChartData<DATUM>(data: DATUM[] | null | undefined, options: O

return {
key,
color,
originalData: datum,
xValue,
yValue,
Expand All @@ -104,7 +108,7 @@ function useNumericChartData<DATUM>(data: DATUM[] | null | undefined, options: O
).filter(isDefined).sort(
(a, b) => compareNumber(a.xValue, b.xValue),
) ?? [],
[data, keySelector, xValueSelector, yValueSelector],
[data, keySelector, xValueSelector, yValueSelector, colorSelector],
);

const dataDomain = useMemo(
Expand Down
80 changes: 78 additions & 2 deletions app/src/utils/domain/per.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +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}`;
}

export const PER_FALLBACK_COLOR = 'var(--go-ui-color-gray-40)';

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<PerRatingValue, string> = {
[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 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);
}

return `${prefix} : ${title}`;
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<PerAreaNumber, string> = {
[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 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;
}) {
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<PerBenchmarkId, string> = {
[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 getPerBenchmarkColor(item.id);
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,15 +49,15 @@ function PreviousAssessmentCharts(props: Props) {
const ratingTitleMap = listToMap(
ratingOptions,
(option) => option.value,
(option) => option.title,
(option) => `${option.title} ${option.value}`,
);

const chartData = useNumericChartData(
[...data].sort((a, b) => compareNumber(a.assessment_number, b.assessment_number)),
{
chartMargin: {
...defaultChartMargin,
top: 10,
top: 30,
},
keySelector: (datum) => datum.assessment_number,
xValueSelector: (datum) => datum.assessment_number,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
height: 20rem;

.path {
stroke: var(--go-ui-color-primary-red);
stroke: var(--go-ui-color-dark-blue-30);
fill: none;
pointer-events: none;
}
Expand All @@ -13,7 +13,7 @@
}

.circle {
color: var(--go-ui-color-primary-red);
color: var(--go-ui-color-dark-blue-30);
pointer-events: none;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@
"lastUpdatedLabel": "Last update",
"perExport": "Export",
"upload": "Upload",
"typeOfOperation": "Type of Operation",
"relevantDocumentHeader": "Relevant Documents",
"uploadLimitDisclaimer": "Note: You can only upload upto 10 documents."
"uploadLimitDisclaimer": "Note: You can only upload upto 10 documents.",
"perArea": "Area {areaNumber}: {title}"
}
}
Loading

0 comments on commit 13687b7

Please sign in to comment.