forked from Abdulbari/sgeUpdated
Add 'sge-frontend/' from commit '5fa787e054b25ac53edc7ff0275ea7960a709401'
git-subtree-dir: sge-frontend git-subtree-mainline:876c278ac4git-subtree-split:5fa787e054
This commit is contained in:
922
sge-frontend/src/views/DataCenterManagement.js
Normal file
922
sge-frontend/src/views/DataCenterManagement.js
Normal file
@@ -0,0 +1,922 @@
|
||||
import React, { useState, useEffect, memo, useCallback } from "react";
|
||||
import { useSelector, useDispatch } from "react-redux";
|
||||
import ReactPaginate from "react-paginate";
|
||||
import { ChevronDown, MoreVertical, Plus, Trash } from "react-feather";
|
||||
import DataTable from "react-data-table-component";
|
||||
import {
|
||||
Card,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
Input,
|
||||
Label,
|
||||
Row,
|
||||
Col,
|
||||
Button,
|
||||
Modal,
|
||||
ModalHeader,
|
||||
ModalBody,
|
||||
ModalFooter,
|
||||
UncontrolledDropdown,
|
||||
DropdownToggle,
|
||||
DropdownMenu,
|
||||
DropdownItem,
|
||||
FormGroup,
|
||||
Form,
|
||||
} from "reactstrap";
|
||||
import Select from "react-select";
|
||||
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 } from "../redux/actions/dataCenter";
|
||||
import { useTranslation } from "react-i18next";
|
||||
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';
|
||||
|
||||
// Add Nominatim service configuration
|
||||
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
|
||||
}
|
||||
});
|
||||
|
||||
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')
|
||||
});
|
||||
|
||||
// Map marker component that handles clicks
|
||||
const MapMarker = ({ position, setPosition, setSelectedDataCenter }) => {
|
||||
useMapEvents({
|
||||
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 => {
|
||||
const address = response.data.display_name;
|
||||
setSelectedDataCenter(prev => ({
|
||||
...prev,
|
||||
address,
|
||||
latitude: e.latlng.lat,
|
||||
longitude: e.latlng.lng
|
||||
}));
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error getting address:', error);
|
||||
// Still update coordinates even if address lookup fails
|
||||
setSelectedDataCenter(prev => ({
|
||||
...prev,
|
||||
latitude: e.latlng.lat,
|
||||
longitude: e.latlng.lng
|
||||
}));
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Only render marker if position exists and has valid coordinates
|
||||
return position && position[0] && position[1] ? <Marker position={position} /> : null;
|
||||
};
|
||||
|
||||
const DataCenterManagement = () => {
|
||||
const { t } = useTranslation();
|
||||
const dispatch = useDispatch();
|
||||
const { enqueueSnackbar } = useSnackbar();
|
||||
|
||||
const [currentPage, setCurrentPage] = useState(1);
|
||||
const [rowsPerPage, setRowsPerPage] = useState(10);
|
||||
const [searchValue, setSearchValue] = useState("");
|
||||
const [showAddModal, setShowAddModal] = useState(false);
|
||||
const [selectedDataCenter, setSelectedDataCenter] = useState({
|
||||
name: "",
|
||||
externalId: "",
|
||||
number: "",
|
||||
address: "",
|
||||
latitude: null,
|
||||
longitude: null,
|
||||
ayposURL: "",
|
||||
city: "",
|
||||
emissionScopeId: null,
|
||||
sectorId: null,
|
||||
subSectorId: null,
|
||||
emissionSourceId: null,
|
||||
consuptionUnitId: null,
|
||||
activitySubUnitId: null
|
||||
});
|
||||
|
||||
const [mapPosition, setMapPosition] = useState(null);
|
||||
|
||||
const dataCenterStore = useSelector((state) => state.dataCenter);
|
||||
const datasStore = useSelector((state) => state.datas);
|
||||
const emissionSourceStore = useSelector((state) => state.emissionSources);
|
||||
const [sectorsOptions, setSectorsOptions] = useState([]);
|
||||
const [subSectorsOptions, setSubSectorsOptions] = useState([]);
|
||||
const [emissionSourcesOptions, setEmissionSourcesOptions] = useState([]);
|
||||
const [consuptionUnitsOptions, setConsuptionUnitsOptions] = useState([]);
|
||||
const [activitySubUnitsOptions, setActivitySubUnitsOptions] = useState([]);
|
||||
const [emissionScopesOptions, setEmissionScopesOptions] = useState([]);
|
||||
|
||||
// Add state for selected sector and sub sector like in data input
|
||||
const [selectedSector, setSelectedSector] = useState(null);
|
||||
const [selectedSubSector, setSelectedSubSector] = useState(null);
|
||||
|
||||
const [editingDataCenter, setEditingDataCenter] = useState(null);
|
||||
|
||||
const initialColumns = [
|
||||
{
|
||||
name: t("DataCenter.id"),
|
||||
selector: (row) => row.externalId,
|
||||
sortable: true,
|
||||
minWidth: "100px",
|
||||
cell: (row) => <span>{row.externalId}</span>,
|
||||
},
|
||||
{
|
||||
name: t("DataCenter.name"),
|
||||
selector: (row) => row.dataCenter,
|
||||
sortable: true,
|
||||
minWidth: "200px",
|
||||
},
|
||||
{
|
||||
name: "Dashboard",
|
||||
selector: (row) => row.ayposURL,
|
||||
sortable: false,
|
||||
minWidth: "150px",
|
||||
cell: (row) => (
|
||||
<div className="d-flex justify-content-center w-100">
|
||||
{row.ayposURL ? (
|
||||
<Button
|
||||
color="primary"
|
||||
size="sm"
|
||||
onClick={() => window.open(row.ayposURL, '_blank')}
|
||||
>
|
||||
Dashboard
|
||||
</Button>
|
||||
) : (
|
||||
<span>-</span>
|
||||
)}
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
name: t("Actions"),
|
||||
allowOverflow: false,
|
||||
maxWidth: "150px",
|
||||
cell: (row) => {
|
||||
return (
|
||||
<div className="d-flex">
|
||||
<UncontrolledDropdown>
|
||||
<DropdownToggle className="pl-1" tag="span">
|
||||
<MoreVertical size={15} />
|
||||
</DropdownToggle>
|
||||
<DropdownMenu container={"body"} end>
|
||||
{permissionCheck("datacenter_update") && (
|
||||
<DropdownItem
|
||||
tag="a"
|
||||
className="w-100"
|
||||
onClick={() => handleEditDataCenter(row)}
|
||||
>
|
||||
<Edit size={15} />
|
||||
<span className="align-middle ml-50">{t("Cruds.edit")}</span>
|
||||
</DropdownItem>
|
||||
)}
|
||||
{permissionCheck("datacenter_delete") && (
|
||||
<DropdownItem
|
||||
tag="a"
|
||||
className="w-100"
|
||||
onClick={() => handleDeleteDataCenter(row)}
|
||||
>
|
||||
<Trash size={15} />
|
||||
<span className="align-middle ml-50">{t("Cruds.delete")}</span>
|
||||
</DropdownItem>
|
||||
)}
|
||||
</DropdownMenu>
|
||||
</UncontrolledDropdown>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const [serverSideColumns, setServerSideColumns] = useState(initialColumns);
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(getDataCenters());
|
||||
dispatch(getSectors());
|
||||
}, [dispatch]);
|
||||
|
||||
useEffect(() => {
|
||||
setSectorsOptions(
|
||||
datasStore?.sectors?.map((sector) => ({
|
||||
value: sector?.id,
|
||||
label: sector?.tag,
|
||||
}))
|
||||
);
|
||||
}, [datasStore?.sectors]);
|
||||
|
||||
useEffect(() => {
|
||||
setSubSectorsOptions([]);
|
||||
setSubSectorsOptions(
|
||||
datasStore?.sector?.subSectors?.map((subSector) => ({
|
||||
value: subSector?.id,
|
||||
label: subSector?.tag,
|
||||
}))
|
||||
);
|
||||
}, [datasStore?.sector]);
|
||||
|
||||
useEffect(() => {
|
||||
setActivitySubUnitsOptions(
|
||||
datasStore?.subSector?.activitySubUnits?.map((activitySubUnit) => ({
|
||||
value: activitySubUnit?.id,
|
||||
label: activitySubUnit?.tag,
|
||||
}))
|
||||
);
|
||||
}, [datasStore?.subSector]);
|
||||
|
||||
useEffect(() => {
|
||||
setEmissionSourcesOptions(
|
||||
emissionSourceStore?.emissionSources
|
||||
?.filter((source) => source.convertUnitCheck != false)
|
||||
?.map((source) => ({
|
||||
value: source?.id,
|
||||
label: source?.tag,
|
||||
}))
|
||||
);
|
||||
}, [emissionSourceStore?.emissionSources]);
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedDataCenter?.emissionSourceId) {
|
||||
dispatch(
|
||||
getConsuptionUnits({
|
||||
id: selectedDataCenter?.emissionSourceId,
|
||||
sector: selectedDataCenter?.sectorId,
|
||||
})
|
||||
);
|
||||
}
|
||||
}, [selectedDataCenter?.emissionSourceId]);
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedSubSector != null) {
|
||||
dispatch(getAllEmissionSources(selectedSubSector));
|
||||
}
|
||||
}, [selectedSubSector]);
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedSector != null) {
|
||||
dispatch(getSectorById(selectedSector));
|
||||
}
|
||||
}, [selectedSector]);
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedSubSector != null) {
|
||||
dispatch(getSubSectorById(selectedSubSector));
|
||||
}
|
||||
}, [selectedSubSector]);
|
||||
|
||||
useEffect(() => {
|
||||
setConsuptionUnitsOptions(
|
||||
datasStore?.consuptionUnits?.map((consuptionUnit) => ({
|
||||
value: consuptionUnit?.unit?.id,
|
||||
label: consuptionUnit?.unit?.description,
|
||||
}))
|
||||
);
|
||||
}, [datasStore?.consuptionUnits]);
|
||||
|
||||
useEffect(() => {
|
||||
setEmissionScopesOptions([
|
||||
{
|
||||
label: "Şehir İçi",
|
||||
value: false,
|
||||
},
|
||||
{
|
||||
label: "Şehir Dışı",
|
||||
value: true,
|
||||
},
|
||||
]);
|
||||
}, []);
|
||||
|
||||
const handleEditDataCenter = (row) => {
|
||||
setEditingDataCenter(row);
|
||||
setSelectedDataCenter({
|
||||
name: row.dataCenter,
|
||||
externalId: row.externalId,
|
||||
number: row.number,
|
||||
address: row.address,
|
||||
latitude: row.latitude,
|
||||
longitude: row.longitude,
|
||||
ayposURL: row.ayposURL,
|
||||
city: row.city,
|
||||
emissionScopeId: row.emissionScope?.id,
|
||||
sectorId: row.sector?.id,
|
||||
subSectorId: row.subSector?.id,
|
||||
emissionSourceId: row.emissionSource?.id,
|
||||
consuptionUnitId: row.consuptionUnit?.id,
|
||||
activitySubUnitId: row.activitySubUnit?.id
|
||||
});
|
||||
|
||||
// Set the selected sector and sub sector for cascading dropdowns
|
||||
setSelectedSector(row.sector?.id);
|
||||
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);
|
||||
setShowAddModal(true);
|
||||
};
|
||||
|
||||
const handleDeleteDataCenter = async (row) => {
|
||||
const result = await Swal.fire({
|
||||
title: t("Common.areYouSure"),
|
||||
text: t("Common.cantRevert"),
|
||||
icon: "warning",
|
||||
showCancelButton: true,
|
||||
confirmButtonText: t("Common.yes"),
|
||||
cancelButtonText: t("Common.no"),
|
||||
customClass: {
|
||||
confirmButton: "btn btn-primary",
|
||||
cancelButton: "btn btn-outline-danger ms-1",
|
||||
},
|
||||
buttonsStyling: false,
|
||||
});
|
||||
|
||||
if (result.value) {
|
||||
try {
|
||||
await dispatch(deleteDataCenter(row.id));
|
||||
enqueueSnackbar(t("DataCenter.deleteSuccess"), { variant: "success" });
|
||||
} catch (error) {
|
||||
console.error("Delete error:", error);
|
||||
enqueueSnackbar(
|
||||
error?.message || t("DataCenter.deleteError"),
|
||||
{ variant: "error" }
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleSubmit = async () => {
|
||||
if (!selectedDataCenter.name || !selectedDataCenter.externalId) {
|
||||
enqueueSnackbar(t("Common.fillRequiredFields"), { variant: "error" });
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// Ensure number is set for new data centers
|
||||
const dataToSubmit = {
|
||||
...selectedDataCenter,
|
||||
number: selectedDataCenter.number || 1, // Default to 1 if not set
|
||||
city: selectedDataCenter.city, // Add city to the payload
|
||||
emissionScopeId: selectedDataCenter.emissionScopeId,
|
||||
sectorId: selectedDataCenter.sectorId,
|
||||
subSectorId: selectedDataCenter.subSectorId,
|
||||
emissionSourceId: selectedDataCenter.emissionSourceId,
|
||||
consuptionUnitId: selectedDataCenter.consuptionUnitId,
|
||||
activitySubUnitId: selectedDataCenter.activitySubUnitId
|
||||
};
|
||||
|
||||
if (editingDataCenter) {
|
||||
// Update existing data center
|
||||
await dispatch(updateDataCenter(editingDataCenter.id, dataToSubmit));
|
||||
enqueueSnackbar(t("DataCenter.updateSuccess"), { variant: "success" });
|
||||
} else {
|
||||
// Create new data center
|
||||
await dispatch(createDataCenter(dataToSubmit));
|
||||
enqueueSnackbar(t("DataCenter.createSuccess"), { variant: "success" });
|
||||
}
|
||||
|
||||
handleCloseModal();
|
||||
} catch (error) {
|
||||
console.error("Submit error:", error);
|
||||
enqueueSnackbar(
|
||||
error?.message || t("DataCenter.submitError"),
|
||||
{ variant: "error" }
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const handleCloseModal = () => {
|
||||
setShowAddModal(false);
|
||||
setSelectedDataCenter({
|
||||
name: "",
|
||||
externalId: "",
|
||||
number: "",
|
||||
address: "",
|
||||
latitude: null,
|
||||
longitude: null,
|
||||
ayposURL: "",
|
||||
city: ""
|
||||
});
|
||||
setMapPosition(null);
|
||||
setEditingDataCenter(null);
|
||||
};
|
||||
|
||||
const handleFilter = (e) => {
|
||||
setSearchValue(e.target.value);
|
||||
};
|
||||
|
||||
const CustomPagination = () => (
|
||||
<ReactPaginate
|
||||
previousLabel=""
|
||||
nextLabel=""
|
||||
forcePage={currentPage - 1}
|
||||
onPageChange={(page) => setCurrentPage(page.selected + 1)}
|
||||
pageCount={Math.ceil(dataCenterStore.total / rowsPerPage)}
|
||||
breakLabel="..."
|
||||
pageRangeDisplayed={2}
|
||||
marginPagesDisplayed={2}
|
||||
activeClassName="active"
|
||||
pageClassName="page-item"
|
||||
breakClassName="page-item"
|
||||
nextLinkClassName="page-link"
|
||||
pageLinkClassName="page-link"
|
||||
breakLinkClassName="page-link"
|
||||
previousLinkClassName="page-link"
|
||||
nextClassName="page-item next-item"
|
||||
previousClassName="page-item prev-item"
|
||||
containerClassName="pagination react-paginate separated-pagination pagination-sm justify-content-end pe-1 mt-1"
|
||||
/>
|
||||
);
|
||||
|
||||
// Add geocoding function
|
||||
const geocodeAddress = useCallback(async (address) => {
|
||||
if (!address || !address.trim()) {
|
||||
setMapPosition(null);
|
||||
setSelectedDataCenter(prev => ({
|
||||
...prev,
|
||||
latitude: null,
|
||||
longitude: null
|
||||
}));
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
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 => ({
|
||||
...prev,
|
||||
latitude: parseFloat(lat),
|
||||
longitude: parseFloat(lon)
|
||||
}));
|
||||
return true;
|
||||
}
|
||||
|
||||
// If no results found, clear the coordinates
|
||||
setMapPosition(null);
|
||||
setSelectedDataCenter(prev => ({
|
||||
...prev,
|
||||
latitude: null,
|
||||
longitude: null
|
||||
}));
|
||||
return false;
|
||||
} catch (error) {
|
||||
console.error('Error geocoding address:', error);
|
||||
// On error, clear the coordinates
|
||||
setMapPosition(null);
|
||||
setSelectedDataCenter(prev => ({
|
||||
...prev,
|
||||
latitude: null,
|
||||
longitude: null
|
||||
}));
|
||||
return false;
|
||||
}
|
||||
}, []);
|
||||
|
||||
// Update the address input handler
|
||||
const handleAddressChange = (e) => {
|
||||
const newAddress = e.target.value;
|
||||
setSelectedDataCenter(prev => ({
|
||||
...prev,
|
||||
address: newAddress
|
||||
}));
|
||||
|
||||
// If address is empty, clear the coordinates
|
||||
if (!newAddress.trim()) {
|
||||
setMapPosition(null);
|
||||
setSelectedDataCenter(prev => ({
|
||||
...prev,
|
||||
latitude: null,
|
||||
longitude: null
|
||||
}));
|
||||
} else {
|
||||
// If address is not empty, try to geocode it after a delay
|
||||
debouncedGeocode(newAddress);
|
||||
}
|
||||
};
|
||||
|
||||
// Debounced version of geocoding
|
||||
const debouncedGeocode = useCallback(
|
||||
debounce((address) => geocodeAddress(address), 1000),
|
||||
[geocodeAddress]
|
||||
);
|
||||
|
||||
const renderModal = () => {
|
||||
return (
|
||||
<Modal
|
||||
isOpen={showAddModal}
|
||||
toggle={handleCloseModal}
|
||||
className="modal-dialog-centered"
|
||||
size="lg"
|
||||
>
|
||||
<ModalHeader toggle={handleCloseModal}>
|
||||
{editingDataCenter
|
||||
? t("DataCenter.edit")
|
||||
: t("DataCenter.add")}
|
||||
</ModalHeader>
|
||||
<ModalBody>
|
||||
<Form>
|
||||
<Row>
|
||||
<Col sm="12">
|
||||
<FormGroup>
|
||||
<Label for="name">
|
||||
{t("DataCenter.name")} <span className="text-danger">*</span>
|
||||
</Label>
|
||||
<Input
|
||||
type="text"
|
||||
name="name"
|
||||
id="name"
|
||||
placeholder={t("DataCenter.name")}
|
||||
value={selectedDataCenter.name}
|
||||
onChange={(e) =>
|
||||
setSelectedDataCenter({
|
||||
...selectedDataCenter,
|
||||
name: e.target.value,
|
||||
})
|
||||
}
|
||||
/>
|
||||
</FormGroup>
|
||||
</Col>
|
||||
<Col sm="6">
|
||||
<FormGroup>
|
||||
<Label for="externalId">
|
||||
{t("DataCenter.externalId")} <span className="text-danger">*</span>
|
||||
</Label>
|
||||
<Input
|
||||
type="text"
|
||||
name="externalId"
|
||||
id="externalId"
|
||||
placeholder={t("DataCenter.externalId")}
|
||||
value={selectedDataCenter.externalId}
|
||||
onChange={(e) =>
|
||||
setSelectedDataCenter({
|
||||
...selectedDataCenter,
|
||||
externalId: e.target.value,
|
||||
})
|
||||
}
|
||||
/>
|
||||
</FormGroup>
|
||||
</Col>
|
||||
<Col sm="6">
|
||||
<FormGroup>
|
||||
<Label for="ayposURL">{t("DataCenter.ayposURL")}</Label>
|
||||
<Input
|
||||
type="text"
|
||||
name="ayposURL"
|
||||
id="ayposURL"
|
||||
placeholder={t("DataCenter.ayposURL")}
|
||||
value={selectedDataCenter.ayposURL}
|
||||
onChange={(e) =>
|
||||
setSelectedDataCenter({
|
||||
...selectedDataCenter,
|
||||
ayposURL: e.target.value,
|
||||
})
|
||||
}
|
||||
/>
|
||||
</FormGroup>
|
||||
</Col>
|
||||
<Col sm="6">
|
||||
<FormGroup>
|
||||
<Label for="city">{t("DataCenter.city")}</Label>
|
||||
<Input
|
||||
type="text"
|
||||
name="city"
|
||||
id="city"
|
||||
placeholder={t("DataCenter.city")}
|
||||
value={selectedDataCenter.city}
|
||||
onChange={(e) =>
|
||||
setSelectedDataCenter({
|
||||
...selectedDataCenter,
|
||||
city: e.target.value,
|
||||
})
|
||||
}
|
||||
/>
|
||||
</FormGroup>
|
||||
</Col>
|
||||
<Col sm="12">
|
||||
<FormGroup>
|
||||
<Label for="address">{t("DataCenter.address")}</Label>
|
||||
<div className="d-flex">
|
||||
<Input
|
||||
type="text"
|
||||
name="address"
|
||||
id="address"
|
||||
placeholder={t("DataCenter.address")}
|
||||
value={selectedDataCenter.address}
|
||||
onChange={handleAddressChange}
|
||||
/>
|
||||
<Button
|
||||
color="primary"
|
||||
className="ml-1"
|
||||
onClick={() => {
|
||||
if (selectedDataCenter.address) {
|
||||
geocodeAddress(selectedDataCenter.address);
|
||||
}
|
||||
}}
|
||||
>
|
||||
{t("DataCenter.findOnMap")}
|
||||
</Button>
|
||||
</div>
|
||||
</FormGroup>
|
||||
</Col>
|
||||
|
||||
{/* Emission Scope Section */}
|
||||
<Col sm="12">
|
||||
<h5 className="mt-3 mb-2 text-primary">Emission Scope Configuration</h5>
|
||||
</Col>
|
||||
<Col sm="6">
|
||||
<FormGroup>
|
||||
<Label for="emissionScope">Emission Scope</Label>
|
||||
<Select
|
||||
id="emissionScope"
|
||||
name="emissionScope"
|
||||
placeholder="Select emission scope"
|
||||
options={emissionScopesOptions}
|
||||
value={emissionScopesOptions?.find(
|
||||
(option) => option.value === selectedDataCenter.emissionScopeId
|
||||
)}
|
||||
onChange={(option) =>
|
||||
setSelectedDataCenter({
|
||||
...selectedDataCenter,
|
||||
emissionScopeId: option?.value,
|
||||
})
|
||||
}
|
||||
isClearable
|
||||
filterOption={customFilterForSelect}
|
||||
/>
|
||||
</FormGroup>
|
||||
</Col>
|
||||
<Col sm="6">
|
||||
<FormGroup>
|
||||
<Label for="sector">Sector</Label>
|
||||
<Select
|
||||
id="sector"
|
||||
name="sector"
|
||||
placeholder="Select sector"
|
||||
options={sectorsOptions}
|
||||
value={sectorsOptions?.find(
|
||||
(option) => option.value === selectedDataCenter.sectorId
|
||||
)}
|
||||
onChange={(option) => {
|
||||
setSelectedSector(option?.value);
|
||||
setSelectedDataCenter({
|
||||
...selectedDataCenter,
|
||||
sectorId: option?.value,
|
||||
subSectorId: null,
|
||||
emissionSourceId: null,
|
||||
consuptionUnitId: null,
|
||||
activitySubUnitId: null,
|
||||
});
|
||||
}}
|
||||
isClearable
|
||||
filterOption={customFilterForSelect}
|
||||
/>
|
||||
</FormGroup>
|
||||
</Col>
|
||||
<Col sm="6">
|
||||
<FormGroup>
|
||||
<Label for="subSector">Sub Sector</Label>
|
||||
<Select
|
||||
id="subSector"
|
||||
name="subSector"
|
||||
placeholder="Select sub sector"
|
||||
options={subSectorsOptions}
|
||||
value={subSectorsOptions?.find(
|
||||
(option) => option.value === selectedDataCenter.subSectorId
|
||||
)}
|
||||
onChange={(option) => {
|
||||
setSelectedSubSector(option?.value);
|
||||
setSelectedDataCenter({
|
||||
...selectedDataCenter,
|
||||
subSectorId: option?.value,
|
||||
emissionSourceId: null,
|
||||
consuptionUnitId: null,
|
||||
activitySubUnitId: null,
|
||||
});
|
||||
}}
|
||||
isClearable
|
||||
filterOption={customFilterForSelect}
|
||||
isDisabled={!selectedDataCenter.sectorId}
|
||||
/>
|
||||
</FormGroup>
|
||||
</Col>
|
||||
<Col sm="6">
|
||||
<FormGroup>
|
||||
<Label for="emissionSource">Emission Source</Label>
|
||||
<Select
|
||||
id="emissionSource"
|
||||
name="emissionSource"
|
||||
placeholder="Select emission source"
|
||||
options={emissionSourcesOptions}
|
||||
value={emissionSourcesOptions?.find(
|
||||
(option) => option.value === selectedDataCenter.emissionSourceId
|
||||
)}
|
||||
onChange={(option) => {
|
||||
setSelectedDataCenter({
|
||||
...selectedDataCenter,
|
||||
emissionSourceId: option?.value,
|
||||
consuptionUnitId: null,
|
||||
});
|
||||
}}
|
||||
isClearable
|
||||
filterOption={customFilterForSelect}
|
||||
isDisabled={!selectedDataCenter.subSectorId}
|
||||
/>
|
||||
</FormGroup>
|
||||
</Col>
|
||||
<Col sm="6">
|
||||
<FormGroup>
|
||||
<Label for="consuptionUnit">Consumption Unit</Label>
|
||||
<Select
|
||||
id="consuptionUnit"
|
||||
name="consuptionUnit"
|
||||
placeholder="Select consumption unit"
|
||||
options={consuptionUnitsOptions}
|
||||
value={consuptionUnitsOptions?.find(
|
||||
(option) => option.value === selectedDataCenter.consuptionUnitId
|
||||
)}
|
||||
onChange={(option) => {
|
||||
setSelectedDataCenter({
|
||||
...selectedDataCenter,
|
||||
consuptionUnitId: option?.value,
|
||||
});
|
||||
}}
|
||||
isClearable
|
||||
filterOption={customFilterForSelect}
|
||||
isDisabled={!selectedDataCenter.emissionSourceId}
|
||||
/>
|
||||
</FormGroup>
|
||||
</Col>
|
||||
<Col sm="12">
|
||||
<FormGroup>
|
||||
<Label for="activitySubUnit">Activity Sub Unit</Label>
|
||||
<Select
|
||||
id="activitySubUnit"
|
||||
name="activitySubUnit"
|
||||
placeholder="Select activity sub unit"
|
||||
options={activitySubUnitsOptions}
|
||||
value={activitySubUnitsOptions?.find(
|
||||
(option) => option.value === selectedDataCenter.activitySubUnitId
|
||||
)}
|
||||
onChange={(option) => {
|
||||
setSelectedDataCenter({
|
||||
...selectedDataCenter,
|
||||
activitySubUnitId: option?.value,
|
||||
});
|
||||
}}
|
||||
isClearable
|
||||
filterOption={customFilterForSelect}
|
||||
isDisabled={!selectedDataCenter.subSectorId}
|
||||
/>
|
||||
</FormGroup>
|
||||
</Col>
|
||||
|
||||
<Col sm="12">
|
||||
<FormGroup>
|
||||
<Label>{t("DataCenter.location")}</Label>
|
||||
<div style={{ height: "400px", width: "100%" }}>
|
||||
<MapContainer
|
||||
center={mapPosition || [39.9334, 32.8597]} // Default to Ankara
|
||||
zoom={13}
|
||||
style={{ height: "100%", width: "100%" }}
|
||||
>
|
||||
<TileLayer
|
||||
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
|
||||
attribution='© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
|
||||
/>
|
||||
<MapMarker
|
||||
position={mapPosition}
|
||||
setPosition={(pos) => {
|
||||
setMapPosition(pos);
|
||||
setSelectedDataCenter({
|
||||
...selectedDataCenter,
|
||||
latitude: pos[0],
|
||||
longitude: pos[1]
|
||||
});
|
||||
}}
|
||||
setSelectedDataCenter={setSelectedDataCenter}
|
||||
/>
|
||||
</MapContainer>
|
||||
</div>
|
||||
</FormGroup>
|
||||
</Col>
|
||||
</Row>
|
||||
</Form>
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
<Button
|
||||
color="primary"
|
||||
onClick={handleSubmit}
|
||||
disabled={!selectedDataCenter.name || !selectedDataCenter.externalId}
|
||||
>
|
||||
{t("Common.save")}
|
||||
</Button>
|
||||
<Button
|
||||
color="secondary"
|
||||
onClick={handleCloseModal}
|
||||
>
|
||||
{t("Common.cancel")}
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<CardHeader className="border-bottom">
|
||||
<CardTitle tag="h4">{t("DataCenter.title")}</CardTitle>
|
||||
{permissionCheck("datacenter_create") && (
|
||||
<Button
|
||||
className="ml-2"
|
||||
color="primary"
|
||||
onClick={() => setShowAddModal(true)}
|
||||
>
|
||||
<Plus size={15} />
|
||||
<span className="align-middle ml-50">{t("DataCenter.create")}</span>
|
||||
</Button>
|
||||
)}
|
||||
</CardHeader>
|
||||
<Row className="mx-0 mt-1 mb-50">
|
||||
<Col sm="6">
|
||||
<div className="d-flex align-items-center">
|
||||
<Label for="sort-select">{t("Show")}</Label>
|
||||
<Input
|
||||
className="dataTable-select"
|
||||
type="select"
|
||||
id="sort-select"
|
||||
value={rowsPerPage}
|
||||
onChange={(e) => setRowsPerPage(Number(e.target.value))}
|
||||
>
|
||||
<option value={10}>10</option>
|
||||
<option value={25}>25</option>
|
||||
<option value={50}>50</option>
|
||||
<option value={75}>75</option>
|
||||
<option value={100}>100</option>
|
||||
</Input>
|
||||
</div>
|
||||
</Col>
|
||||
<Col
|
||||
className="d-flex align-items-center justify-content-sm-end mt-sm-0 mt-1"
|
||||
sm="6"
|
||||
>
|
||||
<Label className="me-1" for="search-input">
|
||||
{t("Filter")}
|
||||
</Label>
|
||||
<Input
|
||||
className="dataTable-filter"
|
||||
type="text"
|
||||
bsSize="sm"
|
||||
id="search-input"
|
||||
value={searchValue}
|
||||
onChange={handleFilter}
|
||||
placeholder={t("DataCenter.searchPlaceholder")}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
<div className="react-dataTable">
|
||||
<DataTable
|
||||
noHeader
|
||||
pagination
|
||||
columns={serverSideColumns}
|
||||
paginationPerPage={rowsPerPage}
|
||||
className="react-dataTable"
|
||||
sortIcon={<ChevronDown size={10} />}
|
||||
paginationDefaultPage={currentPage}
|
||||
paginationComponent={CustomPagination}
|
||||
data={dataCenterStore.dataCenters}
|
||||
noDataComponent={
|
||||
<div className="p-2 text-center">
|
||||
{t("Common.noDataAvailable")}
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
{renderModal()}
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(DataCenterManagement);
|
||||
Reference in New Issue
Block a user