Add datacenter with multiple emission source and inputs

This commit is contained in:
2025-08-18 06:12:19 +03:00
parent ebd997a33d
commit c7e60c25eb
2 changed files with 430 additions and 161 deletions

View File

@@ -251,8 +251,8 @@ export const createDataCenter = (dataCenterData) => {
emissionScopeId: dataCenterData.emissionScopeId || null,
sectorId: dataCenterData.sectorId || null,
subSectorId: dataCenterData.subSectorId || null,
emissionSourceId: dataCenterData.emissionSourceId || null,
consuptionUnitId: dataCenterData.consuptionUnitId || null,
dataCenterEmissionSources:
dataCenterData.dataCenterEmissionSources || [],
activitySubUnitId: dataCenterData.activitySubUnitId || null,
},
},
@@ -382,8 +382,8 @@ export const updateDataCenter = (id, dataCenterData) => {
emissionScopeId: dataCenterData.emissionScopeId || null,
sectorId: dataCenterData.sectorId || null,
subSectorId: dataCenterData.subSectorId || null,
emissionSourceId: dataCenterData.emissionSourceId || null,
consuptionUnitId: dataCenterData.consuptionUnitId || null,
dataCenterEmissionSources:
dataCenterData.dataCenterEmissionSources || [],
activitySubUnitId: dataCenterData.activitySubUnitId || null,
},
},

View File

@@ -28,26 +28,37 @@ import { Edit } from "@mui/icons-material";
import { useSnackbar } from "notistack";
import { default as SweetAlert } from "sweetalert2";
import withReactContent from "sweetalert2-react-content";
import { getDataCenters, createDataCenter, updateDataCenter, deleteDataCenter, getEmissionScopes } from "../redux/actions/dataCenter";
import {
getDataCenters,
createDataCenter,
updateDataCenter,
deleteDataCenter,
getEmissionScopes,
} from "../redux/actions/dataCenter";
import { getAreas, getAreasWithCriteria } from "../redux/actions/areas";
import { useTranslation } from "react-i18next";
import { getSectors, getSectorById, getSubSectorById, getConsuptionUnits } from "../redux/actions/datas";
import {
getSectors,
getSectorById,
getSubSectorById,
getConsuptionUnits,
} from "../redux/actions/datas";
import { getAllEmissionSources } from "../redux/actions/emissionSources";
import { permissionCheck } from "../components/permission-check";
import { customFilterForSelect } from "../utility/Utils";
import { MapContainer, TileLayer, Marker, useMapEvents } from 'react-leaflet';
import 'leaflet/dist/leaflet.css';
import L from 'leaflet';
import axios from 'axios';
import { debounce } from 'lodash';
import { MapContainer, TileLayer, Marker, useMapEvents } from "react-leaflet";
import "leaflet/dist/leaflet.css";
import L from "leaflet";
import axios from "axios";
import { debounce } from "lodash";
// Add Nominatim service configuration
const NOMINATIM_BASE_URL = 'https://nominatim.openstreetmap.org';
const NOMINATIM_BASE_URL = "https://nominatim.openstreetmap.org";
const nominatimAxios = axios.create({
baseURL: NOMINATIM_BASE_URL,
headers: {
'User-Agent': 'SGE-DataCenter-Management' // Required by Nominatim's usage policy
}
"User-Agent": "SGE-DataCenter-Management", // Required by Nominatim's usage policy
},
});
const Swal = withReactContent(SweetAlert);
@@ -55,9 +66,9 @@ const Swal = withReactContent(SweetAlert);
// Fix Leaflet marker icon issue
delete L.Icon.Default.prototype._getIconUrl;
L.Icon.Default.mergeOptions({
iconRetinaUrl: require('leaflet/dist/images/marker-icon-2x.png'),
iconUrl: require('leaflet/dist/images/marker-icon.png'),
shadowUrl: require('leaflet/dist/images/marker-shadow.png')
iconRetinaUrl: require("leaflet/dist/images/marker-icon-2x.png"),
iconUrl: require("leaflet/dist/images/marker-icon.png"),
shadowUrl: require("leaflet/dist/images/marker-shadow.png"),
});
// Map marker component that handles clicks
@@ -66,30 +77,33 @@ const MapMarker = ({ position, setPosition, setSelectedDataCenter }) => {
click(e) {
setPosition([e.latlng.lat, e.latlng.lng]);
// Use Nominatim reverse geocoding directly
nominatimAxios.get(`/reverse?format=json&lat=${e.latlng.lat}&lon=${e.latlng.lng}`)
.then(response => {
nominatimAxios
.get(`/reverse?format=json&lat=${e.latlng.lat}&lon=${e.latlng.lng}`)
.then((response) => {
const address = response.data.display_name;
setSelectedDataCenter(prev => ({
setSelectedDataCenter((prev) => ({
...prev,
address,
latitude: e.latlng.lat,
longitude: e.latlng.lng
longitude: e.latlng.lng,
}));
})
.catch(error => {
console.error('Error getting address:', error);
.catch((error) => {
console.error("Error getting address:", error);
// Still update coordinates even if address lookup fails
setSelectedDataCenter(prev => ({
setSelectedDataCenter((prev) => ({
...prev,
latitude: e.latlng.lat,
longitude: e.latlng.lng
longitude: e.latlng.lng,
}));
});
}
},
});
// Only render marker if position exists and has valid coordinates
return position && position[0] && position[1] ? <Marker position={position} /> : null;
return position && position[0] && position[1] ? (
<Marker position={position} />
) : null;
};
const DataCenterManagement = () => {
@@ -115,15 +129,14 @@ const DataCenterManagement = () => {
emissionScopeId: null,
sectorId: null,
subSectorId: null,
emissionSourceId: null,
consuptionUnitId: null,
activitySubUnitId: null
dataCenterEmissionSources: [], // Array of emission sources with consumption units
activitySubUnitId: null,
});
const [mapPosition, setMapPosition] = useState(null);
const dataCenterStore = useSelector((state) => {
console.log('DataCenter Store:', state.dataCenter);
console.log("DataCenter Store:", state.dataCenter);
return state.dataCenter;
});
const emissionScopeStore = useSelector((state) => state.emissionScope);
@@ -170,7 +183,7 @@ const DataCenterManagement = () => {
<Button
color="primary"
size="sm"
onClick={() => window.open(row.ayposURL, '_blank')}
onClick={() => window.open(row.ayposURL, "_blank")}
>
Dashboard
</Button>
@@ -200,7 +213,9 @@ const DataCenterManagement = () => {
onClick={() => handleEditDataCenter(row)}
>
<Edit size={15} />
<span className="align-middle ml-50">{t("Cruds.edit")}</span>
<span className="align-middle ml-50">
{t("Cruds.edit")}
</span>
</DropdownItem>
)}
{permissionCheck("data_center_delete") && (
@@ -210,7 +225,9 @@ const DataCenterManagement = () => {
onClick={() => handleDeleteDataCenter(row)}
>
<Trash size={15} />
<span className="align-middle ml-50">{t("Cruds.delete")}</span>
<span className="align-middle ml-50">
{t("Cruds.delete")}
</span>
</DropdownItem>
)}
</DropdownMenu>
@@ -269,16 +286,41 @@ const DataCenterManagement = () => {
);
}, [emissionSourceStore?.emissionSources]);
// Remove the old emission source effect since we now handle it in the emission sources component
// useEffect(() => {
// if (selectedDataCenter?.emissionSourceId) {
// dispatch(
// getConsuptionUnits({
// id: selectedDataCenter?.emissionSourceId,
// sector: selectedDataCenter?.sectorId,
// })
// );
// }
// }, [selectedDataCenter?.emissionSourceId]);
// Ensure there's always at least one emission source entry for new data centers
useEffect(() => {
if (selectedDataCenter?.emissionSourceId) {
dispatch(
getConsuptionUnits({
id: selectedDataCenter?.emissionSourceId,
sector: selectedDataCenter?.sectorId,
})
);
if (
showAddModal &&
!editingDataCenter &&
selectedDataCenter.dataCenterEmissionSources.length === 0
) {
setSelectedDataCenter((prev) => ({
...prev,
dataCenterEmissionSources: [
{
emissionSourceId: null,
consuptionUnitId: null,
isDefault: true,
},
],
}));
}
}, [selectedDataCenter?.emissionSourceId]);
}, [
showAddModal,
editingDataCenter,
selectedDataCenter.dataCenterEmissionSources.length,
]);
useEffect(() => {
if (selectedSubSector != null) {
@@ -352,8 +394,18 @@ const DataCenterManagement = () => {
}, [selectedDataCenter.areaId, areasStore?.areas]);
const handleEditDataCenter = (row) => {
console.log('Editing data center:', row);
console.log("Editing data center:", row);
setEditingDataCenter(row);
// Convert dataCenterEmissionSources to the format expected by the form
const emissionSources = row.dataCenterEmissionSources
? row.dataCenterEmissionSources.map((dces) => ({
emissionSourceId: dces.emissionSource?.id,
consuptionUnitId: dces.consuptionUnit?.id,
isDefault: dces.isDefault || false,
}))
: [];
setSelectedDataCenter({
name: row.dataCenter,
externalId: row.externalId?.toString(),
@@ -368,9 +420,8 @@ const DataCenterManagement = () => {
emissionScopeId: row.emissionScope?.id || null,
sectorId: row.sector?.id || null,
subSectorId: row.subSector?.id || null,
emissionSourceId: row.emissionSource?.id || null,
consuptionUnitId: row.consuptionUnit?.id || null,
activitySubUnitId: row.activitySubUnit?.id || null
dataCenterEmissionSources: emissionSources,
activitySubUnitId: row.activitySubUnit?.id || null,
});
// Set the selected sector and sub sector for cascading dropdowns
@@ -378,7 +429,11 @@ const DataCenterManagement = () => {
setSelectedSubSector(row.subSector?.id);
// Only set map position if we have both address and valid coordinates
setMapPosition(row.address && row.latitude && row.longitude ? [row.latitude, row.longitude] : null);
setMapPosition(
row.address && row.latitude && row.longitude
? [row.latitude, row.longitude]
: null
);
setShowAddModal(true);
};
@@ -403,10 +458,9 @@ const DataCenterManagement = () => {
enqueueSnackbar(t("DataCenter.deleteSuccess"), { variant: "success" });
} catch (error) {
console.error("Delete error:", error);
enqueueSnackbar(
error?.message || t("DataCenter.deleteError"),
{ variant: "error" }
);
enqueueSnackbar(error?.message || t("DataCenter.deleteError"), {
variant: "error",
});
}
}
};
@@ -473,23 +527,60 @@ const DataCenterManagement = () => {
if (selectedDataCenter.subSectorId && !selectedDataCenter.sectorId) {
errors.push(t("DataCenter.sectorRequired"));
}
if (selectedDataCenter.emissionSourceId && !selectedDataCenter.subSectorId) {
errors.push(t("DataCenter.subSectorRequired"));
}
if (selectedDataCenter.consuptionUnitId && !selectedDataCenter.emissionSourceId) {
errors.push(t("DataCenter.emissionSourceRequired"));
}
if (selectedDataCenter.activitySubUnitId && !selectedDataCenter.subSectorId) {
if (
selectedDataCenter.activitySubUnitId &&
!selectedDataCenter.subSectorId
) {
errors.push(t("DataCenter.subSectorRequiredForActivity"));
}
// Emission sources validations
if (selectedDataCenter.dataCenterEmissionSources.length > 0) {
const validSources = selectedDataCenter.dataCenterEmissionSources.filter(
(source) => source.emissionSourceId && source.consuptionUnitId
);
if (validSources.length === 0) {
errors.push(t("DataCenter.atLeastOneEmissionSource"));
}
// Check for incomplete emission sources
selectedDataCenter.dataCenterEmissionSources.forEach((source, index) => {
if (
(source.emissionSourceId && !source.consuptionUnitId) ||
(!source.emissionSourceId && source.consuptionUnitId)
) {
errors.push(
t("DataCenter.incompleteEmissionSource", { index: index + 1 })
);
}
});
// Check for duplicate emission sources
const sourceIds = validSources.map((s) => s.emissionSourceId);
const duplicates = sourceIds.filter(
(id, index) => sourceIds.indexOf(id) !== index
);
if (duplicates.length > 0) {
errors.push(t("DataCenter.duplicateEmissionSources"));
}
// Ensure exactly one default emission source
const defaultSources = validSources.filter((s) => s.isDefault);
if (defaultSources.length === 0) {
errors.push(t("DataCenter.oneDefaultEmissionSourceRequired"));
} else if (defaultSources.length > 1) {
errors.push(t("DataCenter.onlyOneDefaultEmissionSourceAllowed"));
}
}
return errors;
};
const handleSubmit = async () => {
const validationErrors = validateForm();
if (validationErrors.length > 0) {
validationErrors.forEach(error => {
validationErrors.forEach((error) => {
enqueueSnackbar(error, { variant: "error" });
});
return;
@@ -498,20 +589,26 @@ const DataCenterManagement = () => {
try {
// Format data according to GraphQL input type
const dataToSubmit = {
dataCenter: selectedDataCenter.name,
name: selectedDataCenter.name,
externalId: parseInt(selectedDataCenter.externalId),
number: parseInt(selectedDataCenter.number || "1"),
address: selectedDataCenter.address,
areaId: selectedDataCenter.areaId,
latitude: selectedDataCenter.latitude ? parseFloat(selectedDataCenter.latitude) : null,
longitude: selectedDataCenter.longitude ? parseFloat(selectedDataCenter.longitude) : null,
latitude: selectedDataCenter.latitude
? parseFloat(selectedDataCenter.latitude)
: null,
longitude: selectedDataCenter.longitude
? parseFloat(selectedDataCenter.longitude)
: null,
ayposURL: selectedDataCenter.ayposURL,
emissionScopeId: selectedDataCenter.emissionScopeId,
sectorId: selectedDataCenter.sectorId,
subSectorId: selectedDataCenter.subSectorId,
emissionSourceId: selectedDataCenter.emissionSourceId,
consuptionUnitId: selectedDataCenter.consuptionUnitId,
activitySubUnitId: selectedDataCenter.activitySubUnitId
dataCenterEmissionSources:
selectedDataCenter.dataCenterEmissionSources.filter(
(source) => source.emissionSourceId && source.consuptionUnitId
),
activitySubUnitId: selectedDataCenter.activitySubUnitId,
};
if (editingDataCenter) {
@@ -533,16 +630,17 @@ const DataCenterManagement = () => {
// Handle specific error cases
if (error.message?.includes("duplicate")) {
enqueueSnackbar(t("DataCenter.duplicateExternalId"), { variant: "error" });
enqueueSnackbar(t("DataCenter.duplicateExternalId"), {
variant: "error",
});
} else if (error.message?.includes("permission")) {
enqueueSnackbar(t("Common.noPermission"), { variant: "error" });
} else if (error.message?.includes("not found")) {
enqueueSnackbar(t("DataCenter.resourceNotFound"), { variant: "error" });
} else {
enqueueSnackbar(
error?.message || t("DataCenter.submitError"),
{ variant: "error" }
);
enqueueSnackbar(error?.message || t("DataCenter.submitError"), {
variant: "error",
});
}
}
};
@@ -554,13 +652,28 @@ const DataCenterManagement = () => {
externalId: "",
number: "",
address: "",
areaId: null,
cityId: null,
latitude: null,
longitude: null,
ayposURL: "",
city: ""
city: "",
emissionScopeId: null,
sectorId: null,
subSectorId: null,
dataCenterEmissionSources: [
{
emissionSourceId: null,
consuptionUnitId: null,
isDefault: true,
},
],
activitySubUnitId: null,
});
setMapPosition(null);
setEditingDataCenter(null);
setSelectedSector(null);
setSelectedSubSector(null);
};
const handleFilter = (e) => {
@@ -594,45 +707,47 @@ const DataCenterManagement = () => {
const geocodeAddress = useCallback(async (address) => {
if (!address || !address.trim()) {
setMapPosition(null);
setSelectedDataCenter(prev => ({
setSelectedDataCenter((prev) => ({
...prev,
latitude: null,
longitude: null
longitude: null,
}));
return false;
}
try {
const response = await nominatimAxios.get(`/search?format=json&q=${encodeURIComponent(address)}`);
const response = await nominatimAxios.get(
`/search?format=json&q=${encodeURIComponent(address)}`
);
if (response.data && response.data[0]) {
const { lat, lon } = response.data[0];
const newPosition = [parseFloat(lat), parseFloat(lon)];
setMapPosition(newPosition);
setSelectedDataCenter(prev => ({
setSelectedDataCenter((prev) => ({
...prev,
latitude: parseFloat(lat),
longitude: parseFloat(lon)
longitude: parseFloat(lon),
}));
return true;
}
// If no results found, clear the coordinates
setMapPosition(null);
setSelectedDataCenter(prev => ({
setSelectedDataCenter((prev) => ({
...prev,
latitude: null,
longitude: null
longitude: null,
}));
return false;
} catch (error) {
console.error('Error geocoding address:', error);
console.error("Error geocoding address:", error);
// On error, clear the coordinates
setMapPosition(null);
setSelectedDataCenter(prev => ({
setSelectedDataCenter((prev) => ({
...prev,
latitude: null,
longitude: null
longitude: null,
}));
return false;
}
@@ -641,18 +756,18 @@ const DataCenterManagement = () => {
// Update the address input handler
const handleAddressChange = (e) => {
const newAddress = e.target.value;
setSelectedDataCenter(prev => ({
setSelectedDataCenter((prev) => ({
...prev,
address: newAddress
address: newAddress,
}));
// If address is empty, clear the coordinates
if (!newAddress.trim()) {
setMapPosition(null);
setSelectedDataCenter(prev => ({
setSelectedDataCenter((prev) => ({
...prev,
latitude: null,
longitude: null
longitude: null,
}));
} else {
// If address is not empty, try to geocode it after a delay
@@ -675,9 +790,7 @@ const DataCenterManagement = () => {
size="lg"
>
<ModalHeader toggle={handleCloseModal}>
{editingDataCenter
? t("DataCenter.edit")
: t("DataCenter.add")}
{editingDataCenter ? t("DataCenter.edit") : t("DataCenter.add")}
</ModalHeader>
<ModalBody>
<Form>
@@ -685,7 +798,8 @@ const DataCenterManagement = () => {
<Col sm="12">
<FormGroup>
<Label for="name">
{t("DataCenter.name")} <span className="text-danger">*</span>
{t("DataCenter.name")}{" "}
<span className="text-danger">*</span>
</Label>
<Input
type="text"
@@ -705,7 +819,8 @@ const DataCenterManagement = () => {
<Col sm="6">
<FormGroup>
<Label for="externalId">
{t("DataCenter.externalId")} <span className="text-danger">*</span>
{t("DataCenter.externalId")}{" "}
<span className="text-danger">*</span>
</Label>
<Input
type="text"
@@ -817,7 +932,9 @@ const DataCenterManagement = () => {
{/* Emission Scope Section */}
<Col sm="12">
<h5 className="mt-3 mb-2 text-primary">Emission Scope Configuration</h5>
<h5 className="mt-3 mb-2 text-primary">
Emission Scope Configuration
</h5>
</Col>
<Col sm="6">
<FormGroup>
@@ -828,7 +945,8 @@ const DataCenterManagement = () => {
placeholder="Select emission scope"
options={emissionScopesOptions}
value={emissionScopesOptions?.find(
(option) => option.value === selectedDataCenter.emissionScopeId
(option) =>
option.value === selectedDataCenter.emissionScopeId
)}
onChange={(option) =>
setSelectedDataCenter({
@@ -843,7 +961,9 @@ const DataCenterManagement = () => {
</Col>
<Col sm="6">
<FormGroup>
<Label for="sector">Sector <span className="text-danger">*</span></Label>
<Label for="sector">
Sector <span className="text-danger">*</span>
</Label>
<Select
id="sector"
name="sector"
@@ -858,8 +978,13 @@ const DataCenterManagement = () => {
...selectedDataCenter,
sectorId: option?.value,
subSectorId: null,
dataCenterEmissionSources: [
{
emissionSourceId: null,
consuptionUnitId: null,
isDefault: true,
},
],
activitySubUnitId: null,
});
}}
@@ -877,15 +1002,21 @@ const DataCenterManagement = () => {
placeholder="Select sub sector"
options={subSectorsOptions}
value={subSectorsOptions?.find(
(option) => option.value === selectedDataCenter.subSectorId
(option) =>
option.value === selectedDataCenter.subSectorId
)}
onChange={(option) => {
setSelectedSubSector(option?.value);
setSelectedDataCenter({
...selectedDataCenter,
subSectorId: option?.value,
dataCenterEmissionSources: [
{
emissionSourceId: null,
consuptionUnitId: null,
isDefault: true,
},
],
activitySubUnitId: null,
});
}}
@@ -895,51 +1026,191 @@ const DataCenterManagement = () => {
/>
</FormGroup>
</Col>
<Col sm="6">
<Col sm="12">
<FormGroup>
<Label for="emissionSource">Emission Source</Label>
<Label>Emission Sources & Consumption Units</Label>
<div className="border p-3 rounded bg-light">
<small className="text-muted mb-2 d-block">
Configure emission sources for this data center. At least
one emission source with consumption unit is required.
</small>
{selectedDataCenter.dataCenterEmissionSources.map(
(source, index) => (
<Row key={index} className="mb-2 align-items-end">
<Col sm="5">
<Label
for={`emissionSource-${index}`}
className="form-label"
>
Emission Source *
</Label>
<Select
id="emissionSource"
name="emissionSource"
placeholder="Select emission source"
id={`emissionSource-${index}`}
placeholder="Select emission source..."
options={emissionSourcesOptions}
value={emissionSourcesOptions?.find(
(option) => option.value === selectedDataCenter.emissionSourceId
(option) =>
option.value === source.emissionSourceId
)}
onChange={(option) => {
const updatedSources = [
...selectedDataCenter.dataCenterEmissionSources,
];
updatedSources[index] = {
...updatedSources[index],
emissionSourceId: option?.value,
consuptionUnitId: null, // Reset consumption unit when emission source changes
};
setSelectedDataCenter({
...selectedDataCenter,
emissionSourceId: option?.value,
consuptionUnitId: null,
dataCenterEmissionSources: updatedSources,
});
// Fetch consumption units for the selected emission source
if (option?.value) {
dispatch(
getConsuptionUnits({
id: option.value,
sector: selectedDataCenter?.sectorId,
})
);
}
}}
isClearable
filterOption={customFilterForSelect}
isDisabled={!selectedDataCenter.subSectorId}
styles={{
placeholder: (provided) => ({
...provided,
color: "#6e6b7b",
}),
}}
/>
</FormGroup>
</Col>
<Col sm="6">
<FormGroup>
<Label for="consuptionUnit">Consumption Unit</Label>
<Col sm="4">
<Label
for={`consuptionUnit-${index}`}
className="form-label"
>
Consumption Unit *
</Label>
<Select
id="consuptionUnit"
name="consuptionUnit"
placeholder="Select consumption unit"
id={`consuptionUnit-${index}`}
placeholder="Select consumption unit..."
options={consuptionUnitsOptions}
value={consuptionUnitsOptions?.find(
(option) => option.value === selectedDataCenter.consuptionUnitId
(option) =>
option.value === source.consuptionUnitId
)}
onChange={(option) => {
const updatedSources = [
...selectedDataCenter.dataCenterEmissionSources,
];
updatedSources[index] = {
...updatedSources[index],
consuptionUnitId: option?.value,
};
setSelectedDataCenter({
...selectedDataCenter,
consuptionUnitId: option?.value,
dataCenterEmissionSources: updatedSources,
});
}}
isClearable
filterOption={customFilterForSelect}
isDisabled={!selectedDataCenter.emissionSourceId}
isDisabled={!source.emissionSourceId}
styles={{
placeholder: (provided) => ({
...provided,
color: "#6e6b7b",
}),
}}
/>
</Col>
<Col sm="3">
<Label className="form-label d-block">
Actions
</Label>
<div className="d-flex gap-2">
<Button
color={
source.isDefault
? "primary"
: "outline-secondary"
}
size="sm"
onClick={() => {
const updatedSources = [
...selectedDataCenter.dataCenterEmissionSources,
];
// First, set all sources to not default
updatedSources.forEach(
(s) => (s.isDefault = false)
);
// Then set the selected one as default
updatedSources[index].isDefault = true;
setSelectedDataCenter({
...selectedDataCenter,
dataCenterEmissionSources: updatedSources,
});
}}
title="Set as default emission source"
>
{source.isDefault ? "★ Default" : "☆ Default"}
</Button>
<Button
color="outline-danger"
size="sm"
onClick={() => {
const updatedSources =
selectedDataCenter.dataCenterEmissionSources.filter(
(_, i) => i !== index
);
// If we're removing the default source and there are other sources, make the first one default
if (
source.isDefault &&
updatedSources.length > 0
) {
updatedSources[0].isDefault = true;
}
setSelectedDataCenter({
...selectedDataCenter,
dataCenterEmissionSources: updatedSources,
});
}}
disabled={
selectedDataCenter.dataCenterEmissionSources
.length === 1
}
title="Remove emission source"
>
<Trash size={14} />
</Button>
</div>
</Col>
</Row>
)
)}
<Button
color="primary"
size="sm"
onClick={() => {
setSelectedDataCenter({
...selectedDataCenter,
dataCenterEmissionSources: [
...selectedDataCenter.dataCenterEmissionSources,
{
emissionSourceId: null,
consuptionUnitId: null,
isDefault: false,
},
],
});
}}
disabled={!selectedDataCenter.subSectorId}
>
<Plus size={14} className="me-1" />
Add Emission Source
</Button>
</div>
</FormGroup>
</Col>
<Col sm="12">
@@ -951,7 +1222,8 @@ const DataCenterManagement = () => {
placeholder="Select activity sub unit"
options={activitySubUnitsOptions}
value={activitySubUnitsOptions?.find(
(option) => option.value === selectedDataCenter.activitySubUnitId
(option) =>
option.value === selectedDataCenter.activitySubUnitId
)}
onChange={(option) => {
setSelectedDataCenter({
@@ -986,7 +1258,7 @@ const DataCenterManagement = () => {
setSelectedDataCenter({
...selectedDataCenter,
latitude: pos[0],
longitude: pos[1]
longitude: pos[1],
});
}}
setSelectedDataCenter={setSelectedDataCenter}
@@ -1002,14 +1274,13 @@ const DataCenterManagement = () => {
<Button
color="primary"
onClick={handleSubmit}
disabled={!selectedDataCenter.name || !selectedDataCenter.externalId}
disabled={
!selectedDataCenter.name || !selectedDataCenter.externalId
}
>
{t("Common.save")}
</Button>
<Button
color="secondary"
onClick={handleCloseModal}
>
<Button color="secondary" onClick={handleCloseModal}>
{t("Common.cancel")}
</Button>
</ModalFooter>
@@ -1083,9 +1354,7 @@ const DataCenterManagement = () => {
progressPending={dataCenterStore?.loading}
progressComponent={<div className="text-center p-3">Loading...</div>}
noDataComponent={
<div className="p-2 text-center">
{t("Common.noDataAvailable")}
</div>
<div className="p-2 text-center">{t("Common.noDataAvailable")}</div>
}
/>
</div>