Skip to content

Commit

Permalink
link back-end source config to frontend
Browse files Browse the repository at this point in the history
  • Loading branch information
beygorghor committed May 30, 2024
1 parent 682272b commit e9f6bf1
Show file tree
Hide file tree
Showing 13 changed files with 310 additions and 96 deletions.
Original file line number Diff line number Diff line change
@@ -1,34 +1,34 @@
import React, { useCallback, useRef, useEffect, useState } from 'react';
import { string, number, object, arrayOf, func } from 'prop-types';
import { Grid, Box, Divider, Typography } from '@mui/material';
import { Box, Divider, Grid, Typography } from '@mui/material';
import { makeStyles } from '@mui/styles';
import { LoadingSpinner, useSafeIntl } from 'bluesquare-components';
import { arrayOf, func, number, object, string } from 'prop-types';
import React, { useCallback, useEffect, useRef, useState } from 'react';
import ConfirmCancelDialogComponent from '../../../components/dialogs/ConfirmCancelDialogComponent';
import InputComponent from '../../../components/forms/InputComponent.tsx';
import { ModalSubTitle } from '../../../components/forms/ModalSubTitle';
import { useFormState } from '../../../hooks/form';
import MESSAGES from '../messages';
import {
useDataSourceVersions,
useOrgUnitTypes,
postToDHIS2,
csvPreview,
useDataSourceForVersion,
} from '../requests';
import { useSnackMutation } from '../../../libs/apiHooks.ts';
import {
commaSeparatedIdsToArray,
commaSeparatedIdsToStringArray,
convertFormStateToDict,
} from '../../../utils/forms';
import { useGetValidationStatus } from '../../forms/hooks/useGetValidationStatus.ts';
import { OrgUnitTreeviewModal } from '../../orgUnits/components/TreeView/OrgUnitTreeviewModal';
import { ModalSubTitle } from '../../../components/forms/ModalSubTitle';
import MESSAGES from '../messages';
import {
csvPreview,
postToDHIS2,
useDataSourceForVersion,
useDataSourceVersions,
useOrgUnitTypes,
} from '../requests';
import {
useFieldsToExport,
FIELDS_TO_EXPORT,
dataSourceVersionsAsOptions,
useFieldsToExport,
versionsAsOptionsWithSourceName,
} from '../utils';
import { useSnackMutation } from '../../../libs/apiHooks.ts';
import { useGetValidationStatus } from '../../forms/hooks/useGetValidationStatus.ts';

const style = theme => ({
noCreds: {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/* eslint-disable camelcase */
import { UseQueryResult } from 'react-query';
import { getRequest } from '../../../libs/Api';
import { useSnackQuery } from '../../../libs/apiHooks';
import { Version } from '../types/dataSources';

const getDataSourceVersion = async (
version: string | undefined,
): Promise<Version> => {
return getRequest(`/api/sourceversions/${version}/`);
};

export const useGetDataSourceVersion = (
versionId: string | undefined,
): UseQueryResult<Version, Error> => {
const queryKey: any[] = ['sourceVersions', versionId];
return useSnackQuery({
queryKey,
queryFn: () => getDataSourceVersion(versionId),
snackErrorMsg: undefined,
options: {
staleTime: 60000,
cacheTime: 1000 * 60 * 5,
keepPreviousData: true,
enabled: !!versionId,
},
});
};
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export const useGetDataSource = (
staleTime: 60000,
cacheTime: 1000 * 60 * 5,
keepPreviousData: true,
enabled: !!sourceId,
},
});
};
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { OrgUnitStatus } from '../../orgUnits/types/orgUnit';

/* eslint-disable camelcase */
export type Project = {
name: string;
Expand All @@ -15,9 +17,14 @@ export type Version = {
created_at: string;
updated_at: string;
org_units_count: number;
data_source_name: string;
data_source: number;
tree_config_status_fields: OrgUnitStatus[];
is_default: boolean;
};

export type DataSource = {
id: number;
name: string;
read_only: boolean;
description: string;
Expand All @@ -26,4 +33,5 @@ export type DataSource = {
projects: Project[];
default_version: Version;
credentials: Credentials;
tree_config_status_fields: OrgUnitStatus[];
};
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,20 @@ import React, {
FunctionComponent,
useCallback,
useEffect,
useMemo,
useRef,
useState,
} from 'react';
import ConfirmCancelDialogComponent from '../../../../components/dialogs/ConfirmCancelDialogComponent';
import { OrgUnit, OrgUnitStatus } from '../../types/orgUnit';
import { OrgUnit } from '../../types/orgUnit';
import { getOrgUnitAncestors } from '../../utils';
import { OrgUnitLabel } from '../OrgUnitLabel';
import { OrgUnitTreeviewPicker } from './OrgUnitTreeviewPicker';
import { SettingsPopper } from './SettingsPopper';
import { Settings, SettingsPopper } from './SettingsPopper';
import { SourceDescription } from './SourceDescription';
import { TreeViewLabel } from './TreeViewLabel';
import { MESSAGES } from './messages';
import { getChildrenData, getRootData, searchOrgUnits } from './requests';
import { DEFAULT_CONFIG, useSourceConfig } from './useSourceConfig';
import {
formatInitialSelectedIds,
formatInitialSelectedParents,
Expand Down Expand Up @@ -71,15 +72,10 @@ const OrgUnitTreeviewModal: FunctionComponent<Props> = ({
useIcon = false,
}) => {
const theme = useTheme();
const [settings, setSettings] = useState({
const [settings, setSettings] = useState<Settings>({
displayTypes: true,
// those three need to be prefilled with source config
displayValid: true,
displayRejected: false,
displayNew: false,
statusSettings: DEFAULT_CONFIG,
});
console.log('source', source);

const [selectedOrgUnits, setSelectedOrgUnits] = useState(initialSelection);

const [selectedOrgUnitsIds, setSelectedOrgUnitsIds] = useState(
Expand Down Expand Up @@ -147,23 +143,16 @@ const OrgUnitTreeviewModal: FunctionComponent<Props> = ({
},
[selectedOrgUnitsIdsCopy, selectedOrgUnitParentsCopy],
);

const { displayTypes, displayValid, displayRejected, displayNew } =
settings;

const validationStatus = useMemo(() => {
return [
...(displayValid ? ['VALID'] : []),
...(displayRejected ? ['REJECTED'] : []),
...(displayNew ? ['NEW'] : []),
] as OrgUnitStatus[];
}, [displayValid, displayRejected, displayNew]);

const { displayTypes, statusSettings } = settings;
const { sourceSettings, isFetchingSource, sourceInfos } = useSourceConfig(
source,
version,
);
const getRootDataWithSource = useCallback(async () => {
const key = version ? 'version' : 'source';
const value = version || source;
return getRootData(value, key, validationStatus);
}, [source, version, validationStatus]);
return getRootData(value, key, statusSettings);
}, [source, version, statusSettings]);

const searchOrgUnitsWithSource = useCallback(
async (value, count) => {
Expand All @@ -172,10 +161,10 @@ const OrgUnitTreeviewModal: FunctionComponent<Props> = ({
count,
source,
version,
validationStatus,
statusSettings,
});
},
[source, version, validationStatus],
[source, version, statusSettings],
);

const resetSelection = useCallback(() => {
Expand Down Expand Up @@ -217,6 +206,18 @@ const OrgUnitTreeviewModal: FunctionComponent<Props> = ({
resetSelection();
}
}, [resetTrigger, hardReset, resetSelection]);

useEffect(() => {
if (sourceSettings && !isFetchingSource) {
setSettings({
...settings,
statusSettings: sourceSettings,
});
}
// only update status settings if source settings are changed
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isFetchingSource, sourceSettings]);

return (
// @ts-ignore
<ConfirmCancelDialogComponent
Expand All @@ -241,7 +242,7 @@ const OrgUnitTreeviewModal: FunctionComponent<Props> = ({
multiselect={multiselect}
placeholder={titleMessage}
required={required}
disabled={disabled}
disabled={disabled || isFetchingSource}
label={(orgUnit: OrgUnit) => (
<TreeViewLabel
orgUnit={orgUnit}
Expand Down Expand Up @@ -274,9 +275,7 @@ const OrgUnitTreeviewModal: FunctionComponent<Props> = ({
</Box>
<Box mt={1}>
<TreeViewWithSearch
getChildrenData={id =>
getChildrenData(id, validationStatus)
}
getChildrenData={id => getChildrenData(id, statusSettings)}
getRootData={getRootDataWithSource}
label={(orgUnit: OrgUnit) => (
<TreeViewLabel
Expand Down Expand Up @@ -304,9 +303,20 @@ const OrgUnitTreeviewModal: FunctionComponent<Props> = ({
if (allowedTypes.length === 0) return true;
return allowedTypes.includes(item.org_unit_type_id);
}}
dependency={validationStatus}
childrenDependency={validationStatus}
dependency={statusSettings}
childrenDependency={statusSettings}
/>
<Box
sx={{
position: 'absolute',
width: '60%',
display: 'flex',
bottom: theme.spacing(2),
left: theme.spacing(3),
}}
>
<SourceDescription sourceInfos={sourceInfos} />
</Box>
</Box>
</ConfirmCancelDialogComponent>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,12 @@ import React, {
useState,
} from 'react';
import { SxStyles } from '../../../../types/general';
import { OrgUnitStatus } from '../../types/orgUnit';
import { MESSAGES } from './messages';

export type Settings = {
displayTypes: boolean;
displayValid: boolean;
displayRejected: boolean;
displayNew: boolean;
statusSettings: OrgUnitStatus[];
};

const styles: SxStyles = {
Expand All @@ -44,12 +43,10 @@ const styles: SxStyles = {
position: 'relative',
},
};

const settingKeys: string[] = [
'displayTypes',
'displayValid',
'displayRejected',
'displayNew',
const POSSIBLE_ORG_UNIT_STATUSES: OrgUnitStatus[] = [
'VALID',
'REJECTED',
'NEW',
];

type Props = {
Expand All @@ -71,12 +68,31 @@ export const SettingsPopper: FunctionComponent<Props> = ({
[anchorEl],
);

const handleChangeSettings = useCallback(
(setting: string) => {
setSettings(prevSettings => ({
...prevSettings,
[setting]: !prevSettings[setting],
}));
const handleChangeTypes = useCallback(() => {
setSettings(prevSettings => ({
...prevSettings,
displayTypes: !prevSettings.displayTypes,
}));
}, [setSettings]);

const handleChangeVisibleStatus = useCallback(
(status: OrgUnitStatus) => {
setSettings(prevSettings => {
const currentStatuses = prevSettings.statusSettings;
const statusIndex = currentStatuses.indexOf(status);
if (statusIndex === -1) {
// Status not in array, add it
return {
...prevSettings,
statusSettings: [...currentStatuses, status],
};
}
// Status in array, remove it
return {
...prevSettings,
statusSettings: currentStatuses.filter(s => s !== status),
};
});
},
[setSettings],
);
Expand Down Expand Up @@ -107,20 +123,39 @@ export const SettingsPopper: FunctionComponent<Props> = ({
}}
>
<Paper sx={styles.paper} elevation={1}>
{settingKeys.map(settingKey => (
<Box key={settingKey} py={0.5}>
<Box py={0.5}>
<FormControlLabel
control={
<Switch
size="small"
checked={settings.displayTypes}
onChange={handleChangeTypes}
color="primary"
/>
}
label={formatMessage(MESSAGES.displayTypes)}
/>
</Box>
{POSSIBLE_ORG_UNIT_STATUSES.map(status => (
<Box py={0.5} key={status}>
<FormControlLabel
control={
<Switch
size="small"
checked={settings[settingKey]}
checked={settings.statusSettings.includes(
status,
)}
onChange={() =>
handleChangeSettings(settingKey)
handleChangeVisibleStatus(
status,
)
}
color="primary"
/>
}
label={formatMessage(MESSAGES[settingKey])}
label={formatMessage(
MESSAGES[`display${status}`],
)}
/>
</Box>
))}
Expand Down
Loading

0 comments on commit e9f6bf1

Please sign in to comment.