forked from BLC/sgeUpdated
922 lines
30 KiB
JavaScript
922 lines
30 KiB
JavaScript
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);
|