Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ const IndicatorProgressChart: React.FC<IndicatorProgressChartProps> = (props: In
targetValue: apiData.targetValue,
actualValue: actualValue === 0 ? apiData.baseValue : actualValue
});
console.log("Progress Value: ", progress);

setProgressValue(progress);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ const IndicatorByProgram: React.FC<ProgramGroupedByIndicatorProps> = (props) =>
const handleIndicatorChange = (value: number) => {
if (indicators && indicators.length > 0) {
setSelectedIndicator(null);
const findIndicator = indicators.find((item: any) => item.id === value);
const findIndicator = indicators.find((item: any) => item.id == value);
console.log("Find Indicator: ", findIndicator);
if (findIndicator) {
setSelectedIndicator(findIndicator);
}
Expand All @@ -46,6 +47,7 @@ const IndicatorByProgram: React.FC<ProgramGroupedByIndicatorProps> = (props) =>
}, [indicators]);

useEffect(() => {
console.log("Selected Indicator ID: ", selectedIndicatorId);
handleIndicatorChange(selectedIndicatorId as number)
}, [selectedIndicatorId]);

Expand Down Expand Up @@ -104,7 +106,7 @@ const IndicatorByProgram: React.FC<ProgramGroupedByIndicatorProps> = (props) =>
</Row>
{selectedIndicator && (
<IndicatorProgressChart
title={translations['amp.ndd.dashboard:me-program-progress']}
title={translations['amp.ndd.dashboard:me-indicator-progress']}
section="left"
translations={translations}
filters={filters}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { useEffect, useState } from 'react';
import ProgramConfiguration from './ProgramConfiguration';
import ProgramProgressComponent from './ProgramProgressComponent';
import IndicatorByProgram from './IndicatorByProgram';
import { Button, Row } from 'react-bootstrap';
import { DefaultTranslations, ProgramConfigChild } from '../../types';
Expand Down Expand Up @@ -50,7 +50,7 @@ const LeftSection: React.FC<LeftSectionProps> = (props) => {
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [indicatorsByProgramReducer.data]);

// @ts-ignore
return (
<div>
Expand All @@ -68,7 +68,7 @@ const LeftSection: React.FC<LeftSectionProps> = (props) => {
<div style={{
minHeight: '350px'
}}>
<ProgramConfiguration
<ProgramProgressComponent
translations={translations}
setLevel1Child={setLevel1Child}
level1Child={level1Child}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ interface IndicatorByProgramProps extends ComponentProps {
settings: any;
}

const ProgramConfiguration: React.FC<IndicatorByProgramProps> = (props) => {
const ProgramProgressComponent: React.FC<IndicatorByProgramProps> = (props) => {
const {
translations,
level1Child,
Expand Down Expand Up @@ -254,4 +254,4 @@ const ProgramConfiguration: React.FC<IndicatorByProgramProps> = (props) => {
)
}

export default ProgramConfiguration;
export default ProgramProgressComponent;
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,16 @@ export type InitialState = {

export interface ActualValue {
year: string | number;
date: string;
value: number
}

export interface YearValues {
actualValues: ActualValue [];
baseValue: number;
baseValueDate: string;
targetValue: number;
targetValueDate: string;
indicatorId: number;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,15 @@ import {ActualValue, DefaultTranslations, LineChartData, SectorReport, YearValue
import {printChart} from "../../../sscdashboard/utils/PrintUtils";
import {
BASE_VALUE,
BASE_VALUE_COLOR, CURRENT_VALUE, CURRENT_VALUE_COLOR,
BASE_VALUE_COLOR,
CURRENT_VALUE,
CURRENT_VALUE_COLOR,
DEFAULT_REPORTING_PERIOD,
SECTOR_COLOR,
TARGET_VALUE,
TARGET_VALUE_COLOR,
SECTOR_COLOR
TARGET_VALUE_COLOR
} from "../../utils/constants";
import React from "react";
import {DataType} from "../components/charts/BarChart";
import _ from 'lodash';
import {DateUtil} from "../../../admin/indicator_manager/utils/dateFn";
import dayjs from "dayjs";

interface GaugeUtils {
Expand Down Expand Up @@ -75,6 +74,11 @@ class ChartUtils {

return actualValue ? actualValue.value : 0;
}
public static sumActualValues = (actualValues: ActualValue []) => {
if (!actualValues || actualValues.length === 0) return 0;

return actualValues.reduce((acc, curr) => acc + curr.value, 0);
}

public static getMaxActualValue = (actualValues: ActualValue []) => {
if (!actualValues || actualValues.length === 0) return 0;
Expand All @@ -88,7 +92,7 @@ class ChartUtils {
if (!curr.actualValues || curr.actualValues.length === 0) {
acc.actualValue += curr.baseValue;
}
acc.actualValue += ChartUtils.getActualValueForCurrentYear(curr.actualValues);
acc.actualValue += ChartUtils.sumActualValues(curr.actualValues);
acc.targetValue += curr.targetValue;
acc.baseValue += curr.baseValue;
return acc;
Expand Down Expand Up @@ -167,53 +171,86 @@ class ChartUtils {

const finalDataSet: DataType [] = [];

if (data) {
let aggregateValue = {
baseValue: 0,
targetValue: 0,
actualValue: 0
};

if (Array.isArray(data)) {
aggregateValue = ChartUtils.computeAggregateValues(data);
} else {
aggregateValue = ChartUtils.computeAggregateValues([data]);
}

const year = new Date().getFullYear();
if (aggregateValue.baseValue) {
const baseData = {
id: translations['amp.ndd.dashboard:me-baseline'],
value: aggregateValue.baseValue,
label: `${translations['amp.ndd.dashboard:me-baseline']} ${year}`,
color: BASE_VALUE_COLOR
}

finalDataSet.push(baseData);
}

if (aggregateValue.actualValue) {
const actualData = {
id: translations['amp.ndd.dashboard:me-current'],
value: aggregateValue.actualValue,
label: `${translations['amp.ndd.dashboard:me-current']} ${year}`,
color: CURRENT_VALUE_COLOR
};
const collectItems = Array.isArray(data) ? data : (data ? [data] : []);

finalDataSet.push(actualData);
// helper to parse dd/MM/yyyy or ISO to Date
const parseDate = (d?: string): Date | null => {
if (!d) return null;
const parts = d.split('/');
if (parts.length === 3 && parts[2].length === 4) {
const [dd, MM, yyyy] = parts;
const dateObj = new Date(Number(yyyy), Number(MM) - 1, Number(dd));
return isNaN(dateObj.getTime()) ? null : dateObj;
}
const iso = new Date(d);
return isNaN(iso.getTime()) ? null : iso;
};
// new helper: extract only the year string
const extractYear = (d?: string): string | undefined => {
if (!d) return undefined;
if (/^\d{4}$/.test(d)) return d; // already a year
const parsed = parseDate(d);
return parsed ? parsed.getFullYear().toString() : undefined;
};
const getLatestYearForActualValues = (values: ActualValue[]): number | undefined => {
if (!values || values.length === 0) return undefined;
const years = values.map(v => { return Number(v.year); }).filter((y): y is number => y !== null);
if (years.length === 0) return undefined;
return Math.max(...years);
}
const getMaxDateString = (dates: string[]): string | undefined => {
const mapped = dates.map(d => ({ raw: d, date: parseDate(d) }))
.filter(o => o.date !== null) as { raw: string; date: Date }[];
if (mapped.length === 0) return undefined;
mapped.sort((a,b) => a.date.getTime() - b.date.getTime());
return mapped[mapped.length - 1].raw; // keep original formatting
};

// aggregate numeric values (existing logic)
let aggregateValue = { baseValue: 0, targetValue: 0, actualValue: 0 };
if (collectItems.length > 0) {
aggregateValue = ChartUtils.computeAggregateValues(collectItems as YearValues[]);
}

if (aggregateValue.targetValue) {
const targetData = {
id: translations['amp.ndd.dashboard:me-target'],
value: aggregateValue.targetValue,
label: `${translations['amp.ndd.dashboard:me-target']} ${year}`,
color: TARGET_VALUE_COLOR
};
// collect date strings
const baseDates: string[] = collectItems.map((i: YearValues) => i.baseValueDate).filter(Boolean);
const targetDates: string[] = collectItems.map((i: YearValues) => i.targetValueDate).filter(Boolean);
const maxBaseDateStr = getMaxDateString(baseDates);
const maxTargetDateStr = getMaxDateString(targetDates);
const year = new Date().getFullYear();
const maxActualYearStr = getLatestYearForActualValues(collectItems.flatMap(i => i.actualValues));

const baseYearLabel = extractYear(maxBaseDateStr) || year;
const targetYearLabel = extractYear(maxTargetDateStr) || year;

if (aggregateValue.baseValue) {
const baseData = {
id: translations['amp.ndd.dashboard:me-baseline'],
value: aggregateValue.baseValue,
label: `${translations['amp.ndd.dashboard:me-baseline']} ${baseYearLabel}`.trim(),
color: BASE_VALUE_COLOR
};
finalDataSet.push(baseData);
}

finalDataSet.push(targetData);
}
if (aggregateValue.actualValue) {
const actualData = {
id: translations['amp.ndd.dashboard:me-current'],
value: aggregateValue.actualValue,
label: `${translations['amp.ndd.dashboard:me-current']} ${maxActualYearStr || year}`.trim(),
color: CURRENT_VALUE_COLOR
};
finalDataSet.push(actualData);
}

if (aggregateValue.targetValue) {
const targetData = {
id: translations['amp.ndd.dashboard:me-target'],
value: aggregateValue.targetValue,
label: `${translations['amp.ndd.dashboard:me-target']} ${targetYearLabel}`.trim(),
color: TARGET_VALUE_COLOR
};
finalDataSet.push(targetData);
}

return finalDataSet;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ public void renderHead(Component component, IHeaderResponse response) {
variables.put("onepagerMode", activityFormOnePager);
variables.put("onepagerPath", "/" + OnePagerConst.ONEPAGER_URL_PREFIX + "/" + OnePagerConst.ONEPAGER_URL_PARAMETER_ACTIVITY + "/");
variables.put("isTabView",FeaturesUtil.getGlobalSettingValueBoolean(GlobalSettingsConstants.ACTIVITY_FORM_FUNDING_SECTION_DESIGN));
variables.put("isMeTabView",FeaturesUtil.getGlobalSettingValueBoolean(GlobalSettingsConstants.IS_ME_TABVIEW));
variables.put("isRtl", SiteUtils.isEffectiveLangRTL());

PackageTextTemplate ptt = new PackageTextTemplate(DocumentReadyBehavior.class, JS_FILE_NAME);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
enableComputateVisibleSections = false;
onepagerMode = ${onepagerMode};
isTabView = ${isTabView};
var isMeTabView = ${isMeTabView};
var isRtl = ${isRtl};

//the distance between the content body and the menu should be 40px
Expand Down Expand Up @@ -208,7 +209,6 @@ function pageLeaveConfirmationEnabler(){
}

function switchTabs(lastIndex) {
if (isTabView) {
$('div[data-is_tab=true]').each(function(index) {
$(this).appendTo("#theContent");
});
Expand Down Expand Up @@ -239,11 +239,9 @@ function switchTabs(lastIndex) {
}
});
loader.insert();
}
}

function indicatorTabs(lastIndex) {
if (isTabView) {
$('div[data-is_location_tab=true]').each(function(index) {
$(this).appendTo("#theLocationIndicatorContent");
});
Expand Down Expand Up @@ -274,7 +272,6 @@ function indicatorTabs(lastIndex) {
}
});
loader.insert();
}
}

function getLeftPositionOfRightMenu(isAbsolutePosition) {
Expand Down Expand Up @@ -319,6 +316,9 @@ $(document).ready(function(){
pageLeaveConfirmationEnabler();
if(isTabView){
switchTabs();
}
if (isMeTabView)
{
indicatorTabs();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@
import org.dgfoundation.amp.onepager.util.AttributePrepender;
import org.dgfoundation.amp.onepager.yui.AmpAutocompleteFieldPanel;
import org.digijava.module.aim.dbentity.*;
import org.digijava.module.aim.helper.GlobalSettingsConstants;
import org.digijava.module.aim.util.DbUtil;
import org.digijava.module.aim.util.FeaturesUtil;

import java.util.ArrayList;
import java.util.HashSet;
Expand All @@ -43,7 +45,7 @@ public class AmpMEFormSectionFeature extends AmpFormSectionFeaturePanel {

private Map<AmpActivityLocation, AmpMEItemFeaturePanel> locationIndicatorItems = new TreeMap<>();

private boolean isTabsView = true;
private boolean isTabsView = FeaturesUtil.getGlobalSettingValueBoolean(GlobalSettingsConstants.IS_ME_TABVIEW);

final List<AmpActivityLocation> locations;

Expand Down Expand Up @@ -107,19 +109,21 @@ protected void populateItem(org.apache.wicket.markup.html.list.ListItem<AmpActiv
protected void populateItem(org.apache.wicket.markup.html.list.ListItem<AmpActivityLocation> item) {
AmpMEItemFeaturePanel indicatorLoc = null;
try {
indicatorLoc = new AmpMEItemFeaturePanel("indicatorLocation", "ME Item Location", item.getModel(), am, locations
);
indicatorLoc = new AmpMEItemFeaturePanel("indicatorLocation", "ME Item Location", item.getModel(), am, locations);
} catch (Exception e) {
throw new RuntimeException(e);
}
indicatorLoc.setTabIndex(item.getIndex());

// Apply tab id and data attribute to the ListItem's corresponding markup element (the placeholder div),
// because documentReady.js searches for div[data-is_location_tab=true]
item.add(new AttributePrepender("data-is_location_tab", new Model<String>("true"), ""));
locationIndicatorItems.put(item.getModelObject(), indicatorLoc);
item.setOutputMarkupId(true);
item.setMarkupId("tab" + (item.getIndex() + 1));

locationIndicatorItems.put(item.getModelObject(), indicatorLoc);
item.add(indicatorLoc);
}

};
indicatorLocationList.setOutputMarkupId(true);
add(indicatorLocationList);
Expand Down
Loading