From b8d6d1fc21cb9b9ac173229cd3a9e31cf0b588b0 Mon Sep 17 00:00:00 2001 From: Diogo Sousa Date: Tue, 12 Dec 2023 10:49:58 +0000 Subject: [PATCH] Revert "Merge branch 'DCMFOSS-26' into Spike_analysis" This reverts commit 8e74ac3967c9e50d6f27b85cf3cc67f7480ccc11, reversing changes made to 3bb827c79a6371241db430f604a18c349eab43d5. --- .../controllers/AlertController.java | 67 --- .../entities/AlertEntity.java | 51 -- .../entities/DedicatedAlertEntity.java | 33 -- .../entities/MaterialDemandEntity.java | 7 +- .../entities/TriggeredAlertEntity.java | 52 -- .../entities/enums/AlertThresholdType.java | 6 - .../enums/AlertsMonitoredObjects.java | 8 - .../repositories/AlertsRepository.java | 36 -- .../MaterialDemandRepository.java | 6 +- .../services/AlertService.java | 41 -- .../services/impl/AlertServiceImpl.java | 259 --------- .../impl/CapacityGroupServiceImpl.java | 2 - .../services/impl/DemandServiceImpl.java | 58 +- .../services/impl/FavoriteServiceImpl.java | 13 +- .../impl/SecurityTokenServiceImpl.java | 17 +- .../services/impl/StatusManagerImpl.java | 87 +-- demand-capacity-mgmt-frontend/package.json | 1 - .../capacitygroup/CapacityGroupChronogram.tsx | 140 ++--- .../capacitygroup/CapacityGroupDetails.tsx | 30 +- .../capacitygroup/CapacityGroupSumView.tsx | 542 ++++++++++-------- .../CapacityGroupWizardModal.tsx | 138 +++-- .../capacitygroup/CapacityGroupsList.tsx | 73 +-- .../CapacityGroupsTableHeaders.tsx | 48 +- .../src/components/common/CompanyOptions.tsx | 7 +- .../src/components/common/Pagination.tsx | 4 +- .../src/components/common/TopMenu.tsx | 3 +- .../src/components/dcm/AppComponent.tsx | 12 +- .../src/components/demands/DemandAddForm.tsx | 6 +- .../src/components/demands/DemandList.tsx | 89 ++- .../components/demands/DemandManagement.tsx | 55 +- .../components/demands/DemandsOverview.tsx | 424 ++++++++------ .../src/components/events/EventsTable.tsx | 1 - .../favorites/FavoritesTableAddressBook.tsx | 76 +-- .../favorites/FavoritesTableCapacityGroup.tsx | 20 +- .../favorites/FavoritesTableCompanies.tsx | 11 +- .../favorites/FavoritesTableEvents.tsx | 6 +- .../FavoritesTableMaterialDemands.tsx | 12 +- .../src/components/pages/AdminPage.tsx | 11 +- .../pages/CapacityGroupDetailsPage.tsx | 26 +- .../components/pages/CapacityGroupPage.tsx | 16 +- .../src/components/pages/EventsPage.tsx | 26 +- .../src/components/pages/FavoritesPage.tsx | 2 +- .../src/components/pages/TodoListPage.tsx | 6 +- .../src/contexts/CompanyContextProvider.tsx | 11 +- .../src/contexts/FavoritesContextProvider.tsx | 5 +- .../src/custom-bootstrap.scss | 11 - demand-capacity-mgmt-frontend/src/index.css | 32 +- .../src/interfaces/user_interface.tsx | 27 +- .../src/util/WeeksUtils.tsx | 114 ---- demand-capacity-mgmt-frontend/yarn.lock | 21 +- .../src/main/resources/openapi.yml | 182 ------ 51 files changed, 976 insertions(+), 1955 deletions(-) delete mode 100644 demand-capacity-mgmt-backend/src/main/java/org/eclipse/tractusx/demandcapacitymgmt/demandcapacitymgmtbackend/controllers/AlertController.java delete mode 100644 demand-capacity-mgmt-backend/src/main/java/org/eclipse/tractusx/demandcapacitymgmt/demandcapacitymgmtbackend/entities/AlertEntity.java delete mode 100644 demand-capacity-mgmt-backend/src/main/java/org/eclipse/tractusx/demandcapacitymgmt/demandcapacitymgmtbackend/entities/DedicatedAlertEntity.java delete mode 100644 demand-capacity-mgmt-backend/src/main/java/org/eclipse/tractusx/demandcapacitymgmt/demandcapacitymgmtbackend/entities/TriggeredAlertEntity.java delete mode 100644 demand-capacity-mgmt-backend/src/main/java/org/eclipse/tractusx/demandcapacitymgmt/demandcapacitymgmtbackend/entities/enums/AlertThresholdType.java delete mode 100644 demand-capacity-mgmt-backend/src/main/java/org/eclipse/tractusx/demandcapacitymgmt/demandcapacitymgmtbackend/entities/enums/AlertsMonitoredObjects.java delete mode 100644 demand-capacity-mgmt-backend/src/main/java/org/eclipse/tractusx/demandcapacitymgmt/demandcapacitymgmtbackend/repositories/AlertsRepository.java delete mode 100644 demand-capacity-mgmt-backend/src/main/java/org/eclipse/tractusx/demandcapacitymgmt/demandcapacitymgmtbackend/services/AlertService.java delete mode 100644 demand-capacity-mgmt-backend/src/main/java/org/eclipse/tractusx/demandcapacitymgmt/demandcapacitymgmtbackend/services/impl/AlertServiceImpl.java rename demand-capacity-mgmt-backend/src/main/java/org/eclipse/tractusx/demandcapacitymgmt/demandcapacitymgmtbackend/repositories/TriggeredAlertsRepository.java => demand-capacity-mgmt-frontend/src/components/capacitygroup/CapacityGroupDetails.tsx (61%) delete mode 100644 demand-capacity-mgmt-frontend/src/util/WeeksUtils.tsx diff --git a/demand-capacity-mgmt-backend/src/main/java/org/eclipse/tractusx/demandcapacitymgmt/demandcapacitymgmtbackend/controllers/AlertController.java b/demand-capacity-mgmt-backend/src/main/java/org/eclipse/tractusx/demandcapacitymgmt/demandcapacitymgmtbackend/controllers/AlertController.java deleted file mode 100644 index 3080c226..00000000 --- a/demand-capacity-mgmt-backend/src/main/java/org/eclipse/tractusx/demandcapacitymgmt/demandcapacitymgmtbackend/controllers/AlertController.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * ****************************************************************************** - * Copyright (c) 2023 BMW AG - * Copyright (c) 2023 Contributors to the Eclipse Foundation - * - * See the NOTICE file(s) distributed with this work for additional - * information regarding copyright ownership. - * - * This program and the accompanying materials are made available under the - * terms of the Apache License, Version 2.0 which is available at - * https://www.apache.org/licenses/LICENSE-2.0. - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * ******************************************************************************* - */ -package org.eclipse.tractusx.demandcapacitymgmt.demandcapacitymgmtbackend.controllers; - -import eclipse.tractusx.demand_capacity_mgmt_specification.api.AlertsApi; -import eclipse.tractusx.demand_capacity_mgmt_specification.model.*; -import jakarta.servlet.http.HttpServletRequest; -import java.util.List; -import lombok.AllArgsConstructor; -import org.eclipse.tractusx.demandcapacitymgmt.demandcapacitymgmtbackend.services.AlertService; -import org.eclipse.tractusx.demandcapacitymgmt.demandcapacitymgmtbackend.utils.UserUtil; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.RestController; - -@RestController -@AllArgsConstructor -//@RequestMapping("/alerts") -public class AlertController implements AlertsApi { - - private HttpServletRequest request; - private final AlertService alertService; - - @Override - public ResponseEntity configureAlert(AlertRequest alertRequest) throws Exception { - AlertResponse responseDto = alertService.configureAlert(alertRequest); - return ResponseEntity.status(HttpStatus.CREATED).body(responseDto); - } - - @Override - public ResponseEntity configureTriggeredAlert(TriggeredAlertRequest triggeredAlertRequest) - throws Exception { - TriggeredAlertResponse responseDto = alertService.postTriggeredAlerts(triggeredAlertRequest); - return ResponseEntity.status(HttpStatus.CREATED).body(responseDto); - } - - @Override - public ResponseEntity> getAlerts() throws Exception { - String userID = UserUtil.getUserID(request); - return ResponseEntity.status(HttpStatus.OK).body(alertService.getAlerts(userID)); - } - - @Override - public ResponseEntity> getTriggeredAlerts() throws Exception { - String userID = UserUtil.getUserID(request); - return ResponseEntity.status(HttpStatus.OK).body(alertService.getTriggeredAlerts(userID)); // - } -} diff --git a/demand-capacity-mgmt-backend/src/main/java/org/eclipse/tractusx/demandcapacitymgmt/demandcapacitymgmtbackend/entities/AlertEntity.java b/demand-capacity-mgmt-backend/src/main/java/org/eclipse/tractusx/demandcapacitymgmt/demandcapacitymgmtbackend/entities/AlertEntity.java deleted file mode 100644 index 6af4f346..00000000 --- a/demand-capacity-mgmt-backend/src/main/java/org/eclipse/tractusx/demandcapacitymgmt/demandcapacitymgmtbackend/entities/AlertEntity.java +++ /dev/null @@ -1,51 +0,0 @@ -package org.eclipse.tractusx.demandcapacitymgmt.demandcapacitymgmtbackend.entities; - -import jakarta.persistence.*; -import java.util.List; -import java.util.UUID; -import lombok.*; -import org.eclipse.tractusx.demandcapacitymgmt.demandcapacitymgmtbackend.entities.enums.AlertThresholdType; -import org.eclipse.tractusx.demandcapacitymgmt.demandcapacitymgmtbackend.entities.enums.AlertsMonitoredObjects; - -@Entity -@Table(name = "alerts") -@Builder -@Data -@NoArgsConstructor -@AllArgsConstructor -public class AlertEntity { - - @Id - @GeneratedValue - @Column(columnDefinition = "uuid", updatable = false, name = "id") - private UUID id; - - @Column(name = "user_id") - private UUID userID; - - @Column(name = "alert_name") - private String alertName; - - @Column(name = "monitored_objects") - @Enumerated(EnumType.STRING) - private AlertsMonitoredObjects monitoredObjects; - - @Column(name = "created") - private String created; - - @Column(name = "type") - @Enumerated(EnumType.STRING) - private AlertThresholdType type; - - @Column(name = "threshold") - private double threshold; - - @Column(name = "description") - private String description; - - @ToString.Exclude - @EqualsAndHashCode.Exclude - @OneToMany(cascade = { CascadeType.ALL }, fetch = FetchType.LAZY) - @JoinColumn(name = "alert_id") - private List dedicatedAlerts; -} diff --git a/demand-capacity-mgmt-backend/src/main/java/org/eclipse/tractusx/demandcapacitymgmt/demandcapacitymgmtbackend/entities/DedicatedAlertEntity.java b/demand-capacity-mgmt-backend/src/main/java/org/eclipse/tractusx/demandcapacitymgmt/demandcapacitymgmtbackend/entities/DedicatedAlertEntity.java deleted file mode 100644 index 98f933fd..00000000 --- a/demand-capacity-mgmt-backend/src/main/java/org/eclipse/tractusx/demandcapacitymgmt/demandcapacitymgmtbackend/entities/DedicatedAlertEntity.java +++ /dev/null @@ -1,33 +0,0 @@ -package org.eclipse.tractusx.demandcapacitymgmt.demandcapacitymgmtbackend.entities; - -import jakarta.persistence.*; -import java.util.List; -import java.util.UUID; -import lombok.*; -import org.eclipse.tractusx.demandcapacitymgmt.demandcapacitymgmtbackend.entities.enums.EventObjectType; - -@Entity -@Table(name = "dedicated_alerts") -@Builder -@Data -@NoArgsConstructor -@AllArgsConstructor -public class DedicatedAlertEntity { - - @Id - @GeneratedValue - @Column(columnDefinition = "uuid", updatable = false, name = "id") - private UUID id; - - @Column(name = "object_id") - private UUID objectId; - - @Column(name = "type") - @Enumerated(EnumType.STRING) - private EventObjectType type; - - @ManyToOne(fetch = FetchType.LAZY) - @ToString.Exclude - @EqualsAndHashCode.Exclude - private AlertEntity alertEntity; -} diff --git a/demand-capacity-mgmt-backend/src/main/java/org/eclipse/tractusx/demandcapacitymgmt/demandcapacitymgmtbackend/entities/MaterialDemandEntity.java b/demand-capacity-mgmt-backend/src/main/java/org/eclipse/tractusx/demandcapacitymgmt/demandcapacitymgmtbackend/entities/MaterialDemandEntity.java index a54cb04f..2f7bfc10 100644 --- a/demand-capacity-mgmt-backend/src/main/java/org/eclipse/tractusx/demandcapacitymgmt/demandcapacitymgmtbackend/entities/MaterialDemandEntity.java +++ b/demand-capacity-mgmt-backend/src/main/java/org/eclipse/tractusx/demandcapacitymgmt/demandcapacitymgmtbackend/entities/MaterialDemandEntity.java @@ -25,13 +25,14 @@ import com.fasterxml.jackson.annotation.JsonIdentityInfo; import com.fasterxml.jackson.annotation.ObjectIdGenerators; import jakarta.persistence.*; -import java.time.LocalDateTime; -import java.util.List; -import java.util.UUID; import lombok.*; import org.eclipse.tractusx.demandcapacitymgmt.demandcapacitymgmtbackend.entities.enums.EventType; import org.eclipse.tractusx.demandcapacitymgmt.demandcapacitymgmtbackend.entities.enums.MaterialDemandStatus; +import java.time.LocalDateTime; +import java.util.List; +import java.util.UUID; + @Entity @Cacheable(false) @Table(name = "material_demand") diff --git a/demand-capacity-mgmt-backend/src/main/java/org/eclipse/tractusx/demandcapacitymgmt/demandcapacitymgmtbackend/entities/TriggeredAlertEntity.java b/demand-capacity-mgmt-backend/src/main/java/org/eclipse/tractusx/demandcapacitymgmt/demandcapacitymgmtbackend/entities/TriggeredAlertEntity.java deleted file mode 100644 index ccbfafca..00000000 --- a/demand-capacity-mgmt-backend/src/main/java/org/eclipse/tractusx/demandcapacitymgmt/demandcapacitymgmtbackend/entities/TriggeredAlertEntity.java +++ /dev/null @@ -1,52 +0,0 @@ -package org.eclipse.tractusx.demandcapacitymgmt.demandcapacitymgmtbackend.entities; - -import jakarta.persistence.*; -import java.util.UUID; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; -import org.eclipse.tractusx.demandcapacitymgmt.demandcapacitymgmtbackend.entities.enums.AlertThresholdType; -import org.eclipse.tractusx.demandcapacitymgmt.demandcapacitymgmtbackend.entities.enums.AlertsMonitoredObjects; - -@Entity -@Table(name = "triggered_alerts") -@Builder -@Data -@NoArgsConstructor -@AllArgsConstructor -public class TriggeredAlertEntity { - - @Id - @Column(name = "id") - private UUID id; - - @Column(name = "user_id") - private UUID userID; - - @Column(name = "alert_name") - private String alertName; - - @Column(name = "monitored_objects") - @Enumerated(EnumType.STRING) - private AlertsMonitoredObjects monitoredObjects; - - @Column(name = "created") - private String created; - - @Column(name = "trigger_times") - private int triggerTimes; - - @Column(name = "trigger_times_in_three_months") - private int triggerTimesInThreeMonths; - - @Column(name = "type") - @Enumerated(EnumType.STRING) - private AlertThresholdType type; - - @Column(name = "threshold") - private double threshold; - - @Column(name = "description") - private String description; -} diff --git a/demand-capacity-mgmt-backend/src/main/java/org/eclipse/tractusx/demandcapacitymgmt/demandcapacitymgmtbackend/entities/enums/AlertThresholdType.java b/demand-capacity-mgmt-backend/src/main/java/org/eclipse/tractusx/demandcapacitymgmt/demandcapacitymgmtbackend/entities/enums/AlertThresholdType.java deleted file mode 100644 index 2fa6d896..00000000 --- a/demand-capacity-mgmt-backend/src/main/java/org/eclipse/tractusx/demandcapacitymgmt/demandcapacitymgmtbackend/entities/enums/AlertThresholdType.java +++ /dev/null @@ -1,6 +0,0 @@ -package org.eclipse.tractusx.demandcapacitymgmt.demandcapacitymgmtbackend.entities.enums; - -public enum AlertThresholdType { - ABSOLUTE, - RELATIVE, -} diff --git a/demand-capacity-mgmt-backend/src/main/java/org/eclipse/tractusx/demandcapacitymgmt/demandcapacitymgmtbackend/entities/enums/AlertsMonitoredObjects.java b/demand-capacity-mgmt-backend/src/main/java/org/eclipse/tractusx/demandcapacitymgmt/demandcapacitymgmtbackend/entities/enums/AlertsMonitoredObjects.java deleted file mode 100644 index ccc83fa0..00000000 --- a/demand-capacity-mgmt-backend/src/main/java/org/eclipse/tractusx/demandcapacitymgmt/demandcapacitymgmtbackend/entities/enums/AlertsMonitoredObjects.java +++ /dev/null @@ -1,8 +0,0 @@ -package org.eclipse.tractusx.demandcapacitymgmt.demandcapacitymgmtbackend.entities.enums; - -public enum AlertsMonitoredObjects { - ALL_DEMANDS, - ALL_CAPACITIES, - ALL_OBJECTS, - DEDICATED, -} diff --git a/demand-capacity-mgmt-backend/src/main/java/org/eclipse/tractusx/demandcapacitymgmt/demandcapacitymgmtbackend/repositories/AlertsRepository.java b/demand-capacity-mgmt-backend/src/main/java/org/eclipse/tractusx/demandcapacitymgmt/demandcapacitymgmtbackend/repositories/AlertsRepository.java deleted file mode 100644 index 066b46ac..00000000 --- a/demand-capacity-mgmt-backend/src/main/java/org/eclipse/tractusx/demandcapacitymgmt/demandcapacitymgmtbackend/repositories/AlertsRepository.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * ******************************************************************************* - * Copyright (c) 2023 BMW AG - * Copyright (c) 2023 Contributors to the Eclipse Foundation - * - * See the NOTICE file(s) distributed with this work for additional - * information regarding copyright ownership. - * - * This program and the accompanying materials are made available under the - * terms of the Apache License, Version 2.0 which is available at - * https://www.apache.org/licenses/LICENSE-2.0. - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * ******************************************************************************** - */ - -package org.eclipse.tractusx.demandcapacitymgmt.demandcapacitymgmtbackend.repositories; - -import java.util.List; -import java.util.Optional; -import java.util.UUID; -import org.eclipse.tractusx.demandcapacitymgmt.demandcapacitymgmtbackend.entities.AlertEntity; -import org.eclipse.tractusx.demandcapacitymgmt.demandcapacitymgmtbackend.entities.StatusesEntity; -import org.springframework.data.jpa.repository.JpaRepository; - -public interface AlertsRepository extends JpaRepository { - Optional findByUserID(UUID userID); - List findAllByUserID(UUID userID); - void deleteByUserID(UUID userID); -} diff --git a/demand-capacity-mgmt-backend/src/main/java/org/eclipse/tractusx/demandcapacitymgmt/demandcapacitymgmtbackend/repositories/MaterialDemandRepository.java b/demand-capacity-mgmt-backend/src/main/java/org/eclipse/tractusx/demandcapacitymgmt/demandcapacitymgmtbackend/repositories/MaterialDemandRepository.java index 375a7b3a..437dc8db 100644 --- a/demand-capacity-mgmt-backend/src/main/java/org/eclipse/tractusx/demandcapacitymgmt/demandcapacitymgmtbackend/repositories/MaterialDemandRepository.java +++ b/demand-capacity-mgmt-backend/src/main/java/org/eclipse/tractusx/demandcapacitymgmt/demandcapacitymgmtbackend/repositories/MaterialDemandRepository.java @@ -23,19 +23,19 @@ package org.eclipse.tractusx.demandcapacitymgmt.demandcapacitymgmtbackend.repositories; import jakarta.persistence.Cacheable; -import java.util.List; -import java.util.UUID; import org.eclipse.tractusx.demandcapacitymgmt.demandcapacitymgmtbackend.entities.MaterialDemandEntity; import org.eclipse.tractusx.demandcapacitymgmt.demandcapacitymgmtbackend.entities.enums.MaterialDemandStatus; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.stereotype.Repository; +import java.util.List; +import java.util.UUID; + @Repository @Cacheable(false) public interface MaterialDemandRepository extends JpaRepository { List findBySupplierId_Id(UUID id); - @Query("select m from MaterialDemandEntity m where m.customerId.id = ?1") List findByCustomerId_Id(UUID id); diff --git a/demand-capacity-mgmt-backend/src/main/java/org/eclipse/tractusx/demandcapacitymgmt/demandcapacitymgmtbackend/services/AlertService.java b/demand-capacity-mgmt-backend/src/main/java/org/eclipse/tractusx/demandcapacitymgmt/demandcapacitymgmtbackend/services/AlertService.java deleted file mode 100644 index 40cf9395..00000000 --- a/demand-capacity-mgmt-backend/src/main/java/org/eclipse/tractusx/demandcapacitymgmt/demandcapacitymgmtbackend/services/AlertService.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * ******************************************************************************* - * Copyright (c) 2023 BMW AG - * Copyright (c) 2023 Contributors to the Eclipse Foundation - * - * See the NOTICE file(s) distributed with this work for additional - * information regarding copyright ownership. - * - * This program and the accompanying materials are made available under the - * terms of the Apache License, Version 2.0 which is available at - * https://www.apache.org/licenses/LICENSE-2.0. - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * ******************************************************************************** - */ - -package org.eclipse.tractusx.demandcapacitymgmt.demandcapacitymgmtbackend.services; - -import eclipse.tractusx.demand_capacity_mgmt_specification.model.*; -import java.util.List; -import java.util.concurrent.atomic.AtomicReference; - -public interface AlertService { - AlertResponse configureAlert(AlertRequest alertRequest); - void triggerDemandAlertsIfNeeded( - String userID, - boolean isMaterialDemandChange, - double oldDemandValue, - double newDemandValue, - String materialDemandId - ); - List getAlerts(String userID); - List getTriggeredAlerts(String userID); - TriggeredAlertResponse postTriggeredAlerts(TriggeredAlertRequest triggeredAlertRequest); -} diff --git a/demand-capacity-mgmt-backend/src/main/java/org/eclipse/tractusx/demandcapacitymgmt/demandcapacitymgmtbackend/services/impl/AlertServiceImpl.java b/demand-capacity-mgmt-backend/src/main/java/org/eclipse/tractusx/demandcapacitymgmt/demandcapacitymgmtbackend/services/impl/AlertServiceImpl.java deleted file mode 100644 index bb3903bb..00000000 --- a/demand-capacity-mgmt-backend/src/main/java/org/eclipse/tractusx/demandcapacitymgmt/demandcapacitymgmtbackend/services/impl/AlertServiceImpl.java +++ /dev/null @@ -1,259 +0,0 @@ -/* - * ****************************************************************************** - * Copyright (c) 2023 BMW AG - * Copyright (c) 2023 Contributors to the Eclipse Foundation - * - * See the NOTICE file(s) distributed with this work for additional - * information regarding copyright ownership. - * - * This program and the accompanying materials are made available under the - * terms of the Apache License, Version 2.0 which is available at - * https://www.apache.org/licenses/LICENSE-2.0. - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * ******************************************************************************* - */ -package org.eclipse.tractusx.demandcapacitymgmt.demandcapacitymgmtbackend.services.impl; - -import eclipse.tractusx.demand_capacity_mgmt_specification.model.*; -import java.sql.Timestamp; -import java.time.LocalDateTime; -import java.util.List; -import java.util.Objects; -import java.util.UUID; -import java.util.concurrent.atomic.AtomicReference; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.eclipse.tractusx.demandcapacitymgmt.demandcapacitymgmtbackend.entities.*; -import org.eclipse.tractusx.demandcapacitymgmt.demandcapacitymgmtbackend.entities.enums.AlertThresholdType; -import org.eclipse.tractusx.demandcapacitymgmt.demandcapacitymgmtbackend.entities.enums.AlertsMonitoredObjects; -import org.eclipse.tractusx.demandcapacitymgmt.demandcapacitymgmtbackend.entities.enums.EventObjectType; -import org.eclipse.tractusx.demandcapacitymgmt.demandcapacitymgmtbackend.repositories.AlertsRepository; -import org.eclipse.tractusx.demandcapacitymgmt.demandcapacitymgmtbackend.repositories.TriggeredAlertsRepository; -import org.eclipse.tractusx.demandcapacitymgmt.demandcapacitymgmtbackend.services.AlertService; -import org.springframework.context.annotation.Lazy; -import org.springframework.stereotype.Service; - -@Lazy -@RequiredArgsConstructor -@Service -@Slf4j -public class AlertServiceImpl implements AlertService { - - private final AlertsRepository alertsRepository; - private final TriggeredAlertsRepository triggeredAlertsRepository; - - @Override - public AlertResponse configureAlert(AlertRequest alertRequest) { - AlertEntity alertEntity = convertDtoToEntity(alertRequest); - alertsRepository.save(alertEntity); - return convertAlertsResponseDto(alertEntity); - } - - @Override - public void triggerDemandAlertsIfNeeded( - String userID, - boolean isMaterialDemandChange, - double oldValue, - double newValue, - String materialDemandId - ) { - List alerts = alertsRepository.findAll(); // TODO : only bring my alerts - alerts.forEach( - alertEntity -> { - TriggeredAlertEntity triggeredAlertEntity = new TriggeredAlertEntity(); - triggeredAlertEntity.setId(UUID.randomUUID()); - triggeredAlertEntity.setAlertName(alertEntity.getAlertName()); - triggeredAlertEntity.setDescription(alertEntity.getDescription()); - triggeredAlertEntity.setType(alertEntity.getType()); - triggeredAlertEntity.setUserID(alertEntity.getUserID()); - triggeredAlertEntity.setMonitoredObjects(alertEntity.getMonitoredObjects()); - triggeredAlertEntity.setThreshold(alertEntity.getThreshold()); - LocalDateTime currentLocalDateTime = LocalDateTime.now(); - triggeredAlertEntity.setCreated(Timestamp.valueOf(currentLocalDateTime).toString()); - // TODO : Adjust trigger times - if (isGlobalAlert(isMaterialDemandChange, alertEntity)) { - if (alertEntity.getType().equals(AlertThresholdType.RELATIVE)) { - double threshold = alertEntity.getThreshold(); - double demandDelta = threshold * oldValue; - if ( - threshold >= 0 && - (newValue - oldValue >= demandDelta) || - (threshold < 0 && (newValue - oldValue <= demandDelta)) - ) { - // TODO : adjust the demand description , trigger times here - triggeredAlertsRepository.save(triggeredAlertEntity); - } - } - } else if (alertEntity.getMonitoredObjects().equals(AlertsMonitoredObjects.DEDICATED)) { - alertEntity - .getDedicatedAlerts() - .forEach( - dedicatedAlert -> { - if (Objects.equals(materialDemandId, dedicatedAlert.getObjectId().toString())) { - if (alertEntity.getType().equals(AlertThresholdType.ABSOLUTE)) { - double threshold = alertEntity.getThreshold(); - if ( - threshold >= 0 && - (newValue - oldValue >= threshold) || - (threshold < 0 && (newValue - oldValue <= threshold)) - ) { - // TODO : adjust the demand description , trigger times here - triggeredAlertsRepository.save(triggeredAlertEntity); - } - } else { - double threshold = alertEntity.getThreshold(); - double demandDelta = alertEntity.getThreshold() * oldValue; - if ( - threshold >= 0 && - (newValue - oldValue >= demandDelta) || - (threshold < 0 && (newValue - oldValue <= demandDelta)) - ) { - // TODO : adjust the demand description , trigger times here - triggeredAlertsRepository.save(triggeredAlertEntity); - } - } - } - } - ); - } - } - ); - } - - private static boolean isGlobalAlert(boolean isMaterialDemandChange, AlertEntity alertEntity) { - return ( - alertEntity.getMonitoredObjects().equals(AlertsMonitoredObjects.ALL_DEMANDS) || - ( - alertEntity.getMonitoredObjects().equals(AlertsMonitoredObjects.ALL_CAPACITIES) && - !isMaterialDemandChange - ) || - alertEntity.getMonitoredObjects().equals(AlertsMonitoredObjects.ALL_OBJECTS) - ); - } - - @Override - public List getAlerts(String userID) { - List alerts = alertsRepository.findAll(); - - getAlertByUserId(userID, alerts); - return alerts.stream().map(this::convertAlertsResponseDto).toList(); - } - - private static void getTriggeredAlertByUserId(String userID, List alerts) { - alerts - .stream() - .filter( - alertEntity -> { - if (alertEntity.getUserID().toString().equals(userID)) { - alerts.add(alertEntity); - } - return false; - } - ); - } - - private static void getAlertByUserId(String userID, List alerts) { - alerts - .stream() - .filter( - alertEntity -> { - if (alertEntity.getUserID().toString().equals(userID)) { - alerts.add(alertEntity); - } - return false; - } - ); - } - - @Override - public List getTriggeredAlerts(String userID) { - List alerts = triggeredAlertsRepository.findAll(); - - getTriggeredAlertByUserId(userID, alerts); - return alerts.stream().map(this::convertTriggeredAlertsResponseDto).toList(); - } - - @Override - public TriggeredAlertResponse postTriggeredAlerts(TriggeredAlertRequest triggeredAlertRequest) { - return null; - } - - private AlertResponse convertAlertsResponseDto(AlertEntity alertEntity) { - List dedicatedAlerts = alertEntity - .getDedicatedAlerts() - .stream() - .map(this::enrichDedicateAlertResponse) - .toList(); - - AlertResponse responseDto = new AlertResponse(); - responseDto.setType(alertEntity.getType().name()); - responseDto.setAlertId("" + alertEntity.getId()); - responseDto.setAlertName(alertEntity.getAlertName()); - responseDto.setCreated(alertEntity.getCreated()); - responseDto.setDescription(alertEntity.getDescription()); - responseDto.setMonitoredObjects(alertEntity.getMonitoredObjects().name()); - responseDto.setThreshold(String.valueOf(alertEntity.getThreshold())); - responseDto.setUser(alertEntity.getUserID().toString()); - responseDto.setDedicatedAlerts(dedicatedAlerts); - return responseDto; - } - - DedicatedAlert enrichDedicateAlertResponse(DedicatedAlertEntity alertEntity) { - DedicatedAlert dedicatedAlert = new DedicatedAlert(); - dedicatedAlert.setId(alertEntity.getId().toString()); - dedicatedAlert.setType(alertEntity.getType().toString()); - dedicatedAlert.setObjectId(alertEntity.getObjectId().toString()); - return dedicatedAlert; - } - - private TriggeredAlertResponse convertTriggeredAlertsResponseDto(TriggeredAlertEntity alertEntity) { - //TODO: Set triggerTimes - TriggeredAlertResponse responseDto = new TriggeredAlertResponse(); - responseDto.setType(alertEntity.getType().name()); - responseDto.setAlertId("" + alertEntity.getId()); - responseDto.setAlertName(alertEntity.getAlertName()); - responseDto.setCreated(alertEntity.getCreated()); - responseDto.setDescription(alertEntity.getDescription()); - responseDto.setMonitoredObjects(alertEntity.getMonitoredObjects().name()); - responseDto.setThreshold(String.valueOf(alertEntity.getThreshold())); - responseDto.setUser(alertEntity.getUserID().toString()); - return responseDto; - } - - DedicatedAlertEntity convertDedicatedAlertsDtoToEntity(DedicatedAlert dedicatedAlert) { - return DedicatedAlertEntity - .builder() - .id(UUID.fromString(dedicatedAlert.getId())) - .type(EventObjectType.valueOf(dedicatedAlert.getType())) - .objectId(UUID.fromString(dedicatedAlert.getObjectId())) - .build(); - } - - private AlertEntity convertDtoToEntity(AlertRequest alertRequest) { - List dedicatedAlertEntities = alertRequest - .getDedicatedAlerts() - .stream() - .map(this::convertDedicatedAlertsDtoToEntity) - .toList(); - - return AlertEntity - .builder() - .id(UUID.randomUUID()) - .alertName(alertRequest.getAlertName()) - .created(alertRequest.getCreated()) - .description(alertRequest.getDescription()) - .monitoredObjects(AlertsMonitoredObjects.valueOf(alertRequest.getMonitoredObjects())) - .threshold(Double.parseDouble(alertRequest.getThreshold().toString())) - .userID(UUID.fromString(alertRequest.getUser())) - .type(AlertThresholdType.valueOf(alertRequest.getType())) - .dedicatedAlerts(dedicatedAlertEntities) - .build(); - } -} diff --git a/demand-capacity-mgmt-backend/src/main/java/org/eclipse/tractusx/demandcapacitymgmt/demandcapacitymgmtbackend/services/impl/CapacityGroupServiceImpl.java b/demand-capacity-mgmt-backend/src/main/java/org/eclipse/tractusx/demandcapacitymgmt/demandcapacitymgmtbackend/services/impl/CapacityGroupServiceImpl.java index 3c236329..fb1ca5c4 100644 --- a/demand-capacity-mgmt-backend/src/main/java/org/eclipse/tractusx/demandcapacitymgmt/demandcapacitymgmtbackend/services/impl/CapacityGroupServiceImpl.java +++ b/demand-capacity-mgmt-backend/src/main/java/org/eclipse/tractusx/demandcapacitymgmt/demandcapacitymgmtbackend/services/impl/CapacityGroupServiceImpl.java @@ -59,7 +59,6 @@ public class CapacityGroupServiceImpl implements CapacityGroupService { private final LoggingHistoryService loggingHistoryService; private final FavoriteService favoriteService; private final StatusManagerImpl statusManager; - private final AlertService alertService; private final UserRepository userRepository; @@ -90,7 +89,6 @@ public CapacityGroupResponse createCapacityGroup(CapacityGroupRequest capacityGr capacityGroupRepository.save(capacityGroupEntity); } statusManager.calculateTodos(userID); - return convertCapacityGroupDto(capacityGroupEntity); } diff --git a/demand-capacity-mgmt-backend/src/main/java/org/eclipse/tractusx/demandcapacitymgmt/demandcapacitymgmtbackend/services/impl/DemandServiceImpl.java b/demand-capacity-mgmt-backend/src/main/java/org/eclipse/tractusx/demandcapacitymgmt/demandcapacitymgmtbackend/services/impl/DemandServiceImpl.java index 647a5c5b..4c1598a0 100644 --- a/demand-capacity-mgmt-backend/src/main/java/org/eclipse/tractusx/demandcapacitymgmt/demandcapacitymgmtbackend/services/impl/DemandServiceImpl.java +++ b/demand-capacity-mgmt-backend/src/main/java/org/eclipse/tractusx/demandcapacitymgmt/demandcapacitymgmtbackend/services/impl/DemandServiceImpl.java @@ -27,9 +27,11 @@ import java.math.BigDecimal; import java.time.LocalDate; import java.time.LocalDateTime; -import java.util.*; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.UUID; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicReference; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.eclipse.tractusx.demandcapacitymgmt.demandcapacitymgmtbackend.entities.*; @@ -65,8 +67,6 @@ public class DemandServiceImpl implements DemandService { private final DemandSeriesRepository demandSeriesRepository; - private final AlertService alertService; - private final CapacityGroupRepository capacityGroupRepository; private final LinkedCapacityGroupMaterialDemandRepository linkedCapacityGroupMaterialDemandRepository; private final HttpServletRequest request; @@ -165,9 +165,6 @@ public MaterialDemandResponse updateDemand( } } ); - - //triggerDemandAlertsIfNeeded(demandId, userID, demand); - demand = materialDemandRepository.save(demand); postLogs(demandId, "MATERIAL DEMAND Updated", EventType.GENERAL_EVENT, userID); statusManager.calculateBottleneck(userID, true); @@ -175,53 +172,6 @@ public MaterialDemandResponse updateDemand( return convertDemandResponseDto(demand); } - private void triggerDemandAlertsIfNeeded(String demandId, String userID, MaterialDemandEntity demand) { - List oldDemandValues = new ArrayList<>(List.of()); - List newDemandValues = new ArrayList<>(List.of()); - - demand - .getDemandSeries() - .forEach( - demandSeries -> { - demandSeries - .getDemandSeriesValues() - .forEach( - demandSeriesValues -> { - newDemandValues.add(demandSeriesValues.getDemand()); - } - ); - } - ); - - materialDemandRepository - .findById(UUID.fromString(demandId)) - .get() - .getDemandSeries() - .forEach( - demandSeries1 -> { - demandSeries1 - .getDemandSeriesValues() - .forEach( - demandSeriesValues -> { - oldDemandValues.add(demandSeriesValues.getDemand()); - } - ); - } - ); - - for (int i = 0; i < newDemandValues.size(); i++) { - if (!Objects.equals(oldDemandValues.get(i), newDemandValues.get(i))) { - alertService.triggerDemandAlertsIfNeeded( - userID, - true, - oldDemandValues.get(i), - newDemandValues.get(i), - demandId - ); - } - } - } - private List getAllDemands() { return materialDemandRepository.findAll(); } diff --git a/demand-capacity-mgmt-backend/src/main/java/org/eclipse/tractusx/demandcapacitymgmt/demandcapacitymgmtbackend/services/impl/FavoriteServiceImpl.java b/demand-capacity-mgmt-backend/src/main/java/org/eclipse/tractusx/demandcapacitymgmt/demandcapacitymgmtbackend/services/impl/FavoriteServiceImpl.java index 30b7459b..9044f84c 100644 --- a/demand-capacity-mgmt-backend/src/main/java/org/eclipse/tractusx/demandcapacitymgmt/demandcapacitymgmtbackend/services/impl/FavoriteServiceImpl.java +++ b/demand-capacity-mgmt-backend/src/main/java/org/eclipse/tractusx/demandcapacitymgmt/demandcapacitymgmtbackend/services/impl/FavoriteServiceImpl.java @@ -23,12 +23,6 @@ package org.eclipse.tractusx.demandcapacitymgmt.demandcapacitymgmtbackend.services.impl; import eclipse.tractusx.demand_capacity_mgmt_specification.model.*; -import java.sql.Timestamp; -import java.time.Instant; -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; -import java.util.UUID; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.eclipse.tractusx.demandcapacitymgmt.demandcapacitymgmtbackend.entities.*; @@ -38,6 +32,13 @@ import org.eclipse.tractusx.demandcapacitymgmt.demandcapacitymgmtbackend.services.FavoriteService; import org.springframework.stereotype.Service; +import java.sql.Timestamp; +import java.time.Instant; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.UUID; + @RequiredArgsConstructor @Service @Slf4j diff --git a/demand-capacity-mgmt-backend/src/main/java/org/eclipse/tractusx/demandcapacitymgmt/demandcapacitymgmtbackend/services/impl/SecurityTokenServiceImpl.java b/demand-capacity-mgmt-backend/src/main/java/org/eclipse/tractusx/demandcapacitymgmt/demandcapacitymgmtbackend/services/impl/SecurityTokenServiceImpl.java index 2a3efb4f..187e3c1e 100644 --- a/demand-capacity-mgmt-backend/src/main/java/org/eclipse/tractusx/demandcapacitymgmt/demandcapacitymgmtbackend/services/impl/SecurityTokenServiceImpl.java +++ b/demand-capacity-mgmt-backend/src/main/java/org/eclipse/tractusx/demandcapacitymgmt/demandcapacitymgmtbackend/services/impl/SecurityTokenServiceImpl.java @@ -30,7 +30,6 @@ import eclipse.tractusx.demand_capacity_mgmt_specification.model.Role; import eclipse.tractusx.demand_capacity_mgmt_specification.model.TokenResponse; import eclipse.tractusx.demand_capacity_mgmt_specification.model.User; -import java.util.*; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.eclipse.tractusx.demandcapacitymgmt.demandcapacitymgmtbackend.entities.UserEntity; @@ -47,6 +46,8 @@ import org.springframework.web.reactive.function.client.WebClient; import reactor.core.publisher.Mono; +import java.util.*; + @RequiredArgsConstructor @Service @Slf4j @@ -216,17 +217,17 @@ private UserEntity generateUser(String userID, DecodedJWT decodedJWT) { newUserEntity.setEmail(Optional.ofNullable(decodedJWT.getClaim("email")).map(Claim::asString).orElse("")); newUserEntity.setName(Optional.ofNullable(decodedJWT.getClaim("given_name")).map(Claim::asString).orElse("")); newUserEntity.setLastName( - Optional.ofNullable(decodedJWT.getClaim("family_name")).map(Claim::asString).orElse("") + Optional.ofNullable(decodedJWT.getClaim("family_name")).map(Claim::asString).orElse("") ); newUserEntity.setUsername( - Optional.ofNullable(decodedJWT.getClaim("preferred_username")).map(Claim::asString).orElse("") + Optional.ofNullable(decodedJWT.getClaim("preferred_username")).map(Claim::asString).orElse("") ); Claim rolesClaim = decodedJWT.getClaim("realm_access"); Map realmAccessMap = Optional - .ofNullable(rolesClaim) - .map(Claim::asMap) - .orElse(Collections.emptyMap()); + .ofNullable(rolesClaim) + .map(Claim::asMap) + .orElse(Collections.emptyMap()); Object rolesObject = realmAccessMap.get("roles"); @@ -237,7 +238,7 @@ private UserEntity generateUser(String userID, DecodedJWT decodedJWT) { String roleStr = (String) roleObj; try { org.eclipse.tractusx.demandcapacitymgmt.demandcapacitymgmtbackend.entities.enums.Role role = org.eclipse.tractusx.demandcapacitymgmt.demandcapacitymgmtbackend.entities.enums.Role.valueOf( - roleStr + roleStr ); newUserEntity.setRole(role); break; @@ -261,7 +262,7 @@ private User convertUserEntity(UserEntity userEntity, String accessToken, String user.setAccessToken(accessToken); user.setRefreshToken(refreshToken); user.setExpiresIn(expiresIn); - user.setCompanyID(userEntity.getCompanyID().toString()); + user.setCompanyID(user.getCompanyID()); statusManager.calculateBottleneck(user.getUserID(), false); statusManager.calculateTodos(user.getUserID()); return user; diff --git a/demand-capacity-mgmt-backend/src/main/java/org/eclipse/tractusx/demandcapacitymgmt/demandcapacitymgmtbackend/services/impl/StatusManagerImpl.java b/demand-capacity-mgmt-backend/src/main/java/org/eclipse/tractusx/demandcapacitymgmt/demandcapacitymgmtbackend/services/impl/StatusManagerImpl.java index 42d37ba2..72d7bb7d 100644 --- a/demand-capacity-mgmt-backend/src/main/java/org/eclipse/tractusx/demandcapacitymgmt/demandcapacitymgmtbackend/services/impl/StatusManagerImpl.java +++ b/demand-capacity-mgmt-backend/src/main/java/org/eclipse/tractusx/demandcapacitymgmt/demandcapacitymgmtbackend/services/impl/StatusManagerImpl.java @@ -22,12 +22,6 @@ package org.eclipse.tractusx.demandcapacitymgmt.demandcapacitymgmtbackend.services.impl; -import java.sql.Timestamp; -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.util.*; -import java.util.stream.Collectors; - import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.tuple.Pair; @@ -40,6 +34,12 @@ import org.eclipse.tractusx.demandcapacitymgmt.demandcapacitymgmtbackend.services.StatusManager; import org.springframework.stereotype.Service; +import java.sql.Timestamp; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.*; +import java.util.stream.Collectors; + @RequiredArgsConstructor @Service @Slf4j @@ -60,9 +60,11 @@ public void calculateTodos(String userID) { .ifPresent( user -> { List demands = fetchDemandsBasedOnRole(user, userID); + StatusesEntity statusesEntity = statusesRepository .findByUserID(UUID.fromString(userID)) .orElseGet(() -> generateNewEntity(userID)); + statusesEntity.setTodosCount(demands.size()); statusesRepository.save(statusesEntity); } @@ -77,35 +79,20 @@ private List fetchDemandsBasedOnRole(UserEntity user, Stri List demands = new ArrayList<>(); if (user.getRole().equals(Role.CUSTOMER)) { - demands = - materialDemandRepository - .findAll() //TODO SUPPLIER AQUI findbysupplierID - .stream() - .filter( - d -> - d - .getDemandSeries() - .stream() - .allMatch( - series -> - series - .getDemandSeriesValues() - .stream() - .allMatch(value -> value.getDemand() == 0) - ) - ) - .collect(Collectors.toList()); + demands = materialDemandRepository.findAll() //TODO SUPPLIER AQUI findbysupplierID + .stream() + .filter(d -> d.getDemandSeries().stream().allMatch(series -> series.getDemandSeriesValues().stream().allMatch(value -> value.getDemand() == 0))) + .collect(Collectors.toList()); } else if (user.getRole().equals(Role.SUPPLIER)) { - demands = - materialDemandRepository - .findAll() //TODO CUSTOMER AQUI findbycustomerID - .stream() - .filter(d -> d.getLinkStatus() == EventType.UN_LINKED) - .collect(Collectors.toList()); + demands = materialDemandRepository.findAll() //TODO CUSTOMER AQUI findbycustomerID + .stream() + .filter(d -> d.getLinkStatus() == EventType.UN_LINKED) + .collect(Collectors.toList()); } return demands; } + @Override public void calculateBottleneck(String userID, boolean postLog) { UserEntity user = getUser(userID).orElseThrow(() -> new IllegalArgumentException("User not found")); @@ -130,26 +117,6 @@ private void updateAndLogStatus(String userID, boolean postLog, Pair createInitialStatus(userID)); - - if (improvements > 0) { - logEvent( - EventType.STATUS_IMPROVEMENT, - userID, - postLog, - "Status improved for " + improvements + " weeks", - cgID - ); - } - if (degradations > 0) { - logEvent( - EventType.STATUS_REDUCTION, - userID, - postLog, - "Status degraded for " + degradations + " weeks", - cgID - ); - } - status.setStatusImprovementCount(improvements); status.setStatusDegradationCount(degradations); statusesRepository.save(status); @@ -181,27 +148,17 @@ private WeekColor getWeekColorForEventType(EventType eventType) { } private Pair processCapacityGroup(String userID, CapacityGroupEntity cgs, boolean postLog) { - List matchedEntities = matchedDemandsRepository.findByCapacityGroupID( - cgs.getId() - ); + List matchedEntities = matchedDemandsRepository.findByCapacityGroupID(cgs.getId()); int weeklyImprovements = 0; int weeklyDegradations = 0; for (LinkedCapacityGroupMaterialDemandEntity entity : matchedEntities) { - Optional materialDemand = materialDemandRepository.findById( - entity.getMaterialDemandID() - ); - if (materialDemand.isPresent()) { - Map weeklyDemands = getWeeklyDemands(materialDemand.get().getDemandSeries()); - for (Map.Entry entry : weeklyDemands.entrySet()) { - EventType eventType = determineEventType(cgs, entry.getValue()); - - updateCapacityGroupStatus(cgs, weeklyImprovements, weeklyDegradations); - return Pair.of(weeklyImprovements, weeklyDegradations); - } - } + Pair results = processEachDemandEntity(entity, userID, cgs, postLog); + weeklyImprovements += results.getKey(); + weeklyDegradations += results.getValue(); } + updateCapacityGroupStatus(cgs, weeklyImprovements, weeklyDegradations); return Pair.of(weeklyImprovements, weeklyDegradations); } diff --git a/demand-capacity-mgmt-frontend/package.json b/demand-capacity-mgmt-frontend/package.json index 55fff6b4..8a8aa515 100644 --- a/demand-capacity-mgmt-frontend/package.json +++ b/demand-capacity-mgmt-frontend/package.json @@ -31,7 +31,6 @@ "prop-types": "^15.8.1", "qs": "^6.11.2", "react": "^18.2.0", - "react-datepicker": "^4.23.0", "react-dom": "^18.2.0", "react-icons": "^4.10.1", "react-native": "^0.72.4", diff --git a/demand-capacity-mgmt-frontend/src/components/capacitygroup/CapacityGroupChronogram.tsx b/demand-capacity-mgmt-frontend/src/components/capacitygroup/CapacityGroupChronogram.tsx index 46c1bce3..e2d258b7 100644 --- a/demand-capacity-mgmt-frontend/src/components/capacitygroup/CapacityGroupChronogram.tsx +++ b/demand-capacity-mgmt-frontend/src/components/capacitygroup/CapacityGroupChronogram.tsx @@ -20,57 +20,50 @@ * ******************************************************************************** */ import { useEffect, useRef, useState } from "react"; -import { Bar, BarChart, Brush, CartesianGrid, ComposedChart, Legend, Line, ReferenceArea, Tooltip, XAxis, YAxis } from "recharts"; +import { + Bar, + BarChart, + Brush, + CartesianGrid, + ComposedChart, + Legend, + Line, + ReferenceArea, + Tooltip, + XAxis, + YAxis +} from "recharts"; import { CapacityGroupData, SingleCapacityGroup } from "../../interfaces/capacitygroup_interfaces"; import { DemandProp } from "../../interfaces/demand_interfaces"; -import { getWeekNumber } from "../../util/WeeksUtils"; interface CapacityGroupChronogramProps { - capacityGroup: SingleCapacityGroup | null | undefined; + capacityGroup: SingleCapacityGroup | null; materialDemands: DemandProp[] | null; - startDate: Date; - endDate: Date; } function CapacityGroupChronogram(props: CapacityGroupChronogramProps) { - const { capacityGroup, materialDemands, startDate, endDate } = props; type SelectedRangeType = { start: string | null; end: string | null; - } - - const rawCapacities = capacityGroup?.capacities || []; - + }; - // Generate a list of dates between the minDate and maxDate - const generatedDates: string[] = []; - const currentDate = new Date(startDate); - while (currentDate <= endDate) { - generatedDates.push(currentDate.toISOString().split('T')[0]); - currentDate.setDate(currentDate.getDate() + 7); - } - // Check for missing dates in the capacities list - const missingDates = generatedDates.filter( - (date) => !rawCapacities.find((c) => c.calendarWeek === date) - ); + const [capacityGroup] = useState(props.capacityGroup); + const [demands, setDemands] = useState(props.materialDemands); - // Create capacity entries with actualCapacity and maximumCapacity as 0 for missing dates - const missingCapacities = missingDates.map((date) => ({ - calendarWeek: date, - actualCapacity: 0, - maximumCapacity: 0, - })); + useEffect(() => { + // Update the component's state when materialDemands prop changes + setDemands(props.materialDemands); + }, [props.materialDemands]); - // Merge missing capacities with the original capacities list - const processedCapacities = [...rawCapacities, ...missingCapacities]; + const rawCapacities = capacityGroup?.capacities || []; // Calculate demand sums by week const demandSumsByWeek: { [key: string]: number } = {}; - if (materialDemands) { - materialDemands.forEach((demand) => { + if (demands) { + demands.forEach((demand) => { demand.demandSeries?.forEach((demandSeries) => { demandSeries.demandSeriesValues.forEach((demandSeriesValue) => { const week = demandSeriesValue.calendarWeek; @@ -80,34 +73,34 @@ function CapacityGroupChronogram(props: CapacityGroupChronogramProps) { }); } - const demandSumsMapRef = useRef<{ [key: string]: number }>({}); + // Create a mapping of demand sums by calendarWeek + const demandSumsMap: { [key: string]: number } = {}; + Object.keys(demandSumsByWeek).forEach((week) => { + const simplifiedDate = new Date(week).toISOString().split('T')[0]; + demandSumsMap[simplifiedDate] = demandSumsByWeek[week]; + }); + + // Create data for the chart by matching calendarWeek with demand sums + const data: CapacityGroupData[] = rawCapacities.map((d) => { + const simplifiedDate = new Date(d.calendarWeek).toISOString().split('T')[0]; + return { + ...d, + Demand: demandSumsMap[simplifiedDate] || 0, + dateEpoch: new Date(simplifiedDate).getTime(), + calendarWeek: simplifiedDate, + }; + }).sort((a, b) => a.dateEpoch - b.dateEpoch); - useEffect(() => { - Object.keys(demandSumsByWeek).forEach((week) => { - const simplifiedDate = new Date(week).toISOString().split('T')[0]; - demandSumsMapRef.current[simplifiedDate] = demandSumsByWeek[week]; - }); - }, [demandSumsByWeek, startDate, endDate]); + const getWeekNumber = (d: Date) => { + d = new Date(Date.UTC(d.getFullYear(), d.getMonth(), d.getDate())); + d.setUTCDate(d.getUTCDate() + 4 - (d.getUTCDay() || 7)); + const yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1)); - const [filteredData, setFilteredData] = useState([]); + // Convert the dates to milliseconds for the arithmetic operation + return Math.ceil((((d.getTime() - yearStart.getTime()) / 86400000) + 1) / 7); + + }; - useEffect(() => { - if (startDate && endDate) { - const newData = processedCapacities.map((d) => { - const simplifiedDate = new Date(d.calendarWeek).toISOString().split('T')[0]; - return { - ...d, - Demand: demandSumsMapRef.current[simplifiedDate] || 0, - dateEpoch: new Date(simplifiedDate).getTime(), - calendarWeek: simplifiedDate, - }; - }).sort((a, b) => a.dateEpoch - b.dateEpoch); - - setFilteredData(newData.filter((d) => { - return d.dateEpoch >= startDate.getTime() && d.dateEpoch <= endDate.getTime(); - })); - } - }, [demandSumsMapRef, startDate, endDate]); const weekTickFormatter = (tick: string) => { const dateParts = tick.split("-").map((part) => parseInt(part, 10)); @@ -167,40 +160,21 @@ function CapacityGroupChronogram(props: CapacityGroupChronogramProps) { useEffect(() => { const interval = setInterval(() => { if (brushIndexesRef.current?.startIndex !== undefined && brushIndexesRef.current?.endIndex !== undefined) { - const start = filteredData[brushIndexesRef.current.startIndex].calendarWeek; - const end = filteredData[brushIndexesRef.current.endIndex].calendarWeek; + const start = data[brushIndexesRef.current.startIndex].calendarWeek; + const end = data[brushIndexesRef.current.endIndex].calendarWeek; setSelectedRange({ start, end }); } }, timer.current); return () => clearInterval(interval); - }, [filteredData]); - - const [containerWidth, setContainerWidth] = useState(0); - - useEffect(() => { - const handleResize = () => { - const container = document.getElementById('chart-container'); - if (container) { - setContainerWidth(container.clientWidth); - } - }; - - window.addEventListener('resize', handleResize); - handleResize(); // Initial width - - return () => { - window.removeEventListener('resize', handleResize); - }; - }, []); - + }, [data]); return ( -
+
{} + return ( + <> +
+
+
+
+ + + +
+
+
+ + + ); +} + +export default CapacityGroupDetails; \ No newline at end of file diff --git a/demand-capacity-mgmt-frontend/src/components/capacitygroup/CapacityGroupSumView.tsx b/demand-capacity-mgmt-frontend/src/components/capacitygroup/CapacityGroupSumView.tsx index b3c951b2..0357f2b9 100644 --- a/demand-capacity-mgmt-frontend/src/components/capacitygroup/CapacityGroupSumView.tsx +++ b/demand-capacity-mgmt-frontend/src/components/capacitygroup/CapacityGroupSumView.tsx @@ -20,58 +20,92 @@ * ******************************************************************************** */ -import { addWeeks, formatISO, getISOWeek, startOfDay, subWeeks } from 'date-fns'; -import React, { useContext, useEffect, useMemo, useState } from 'react'; +import React, { useContext, useEffect, useMemo, useRef, useState } from 'react'; import { OverlayTrigger, Tooltip } from 'react-bootstrap'; -import DatePicker from 'react-datepicker'; -import { FaArrowDown, FaArrowRight, FaRegCalendarCheck } from 'react-icons/fa'; import '../../../src/index.css'; import { DemandCategoryContext } from '../../contexts/DemandCategoryProvider'; + +import { addDays, addMonths, addWeeks, format, getISOWeek, startOfMonth } from 'date-fns'; +import { FaArrowDown, FaArrowRight } from 'react-icons/fa'; import { SingleCapacityGroup } from '../../interfaces/capacitygroup_interfaces'; import { DemandProp } from "../../interfaces/demand_interfaces"; -import { generateWeeksForDateRange, getWeekDates } from '../../util/WeeksUtils'; interface WeeklyViewProps { capacityGroup: SingleCapacityGroup | null | undefined; materialDemands: DemandProp[] | null; - updateParentDateRange: (start: Date, end: Date) => void; } -const CapacityGroupSumView: React.FC = ({ capacityGroup, - materialDemands, - updateParentDateRange -}) => { - const { demandcategories } = useContext(DemandCategoryContext) || {}; +function getISOWeekMonday(year: number, isoWeek: number): Date { + const january4 = new Date(year, 0, 4); + const diff = (isoWeek - 1) * 7 + (1 - january4.getDay()); + return addDays(january4, diff); +} - const currentDate = startOfDay(new Date()); - const defaultStartDateString = formatISO(subWeeks(currentDate, 8), { representation: 'date' }); - const defaultEndDateString = formatISO(addWeeks(currentDate, 53), { representation: 'date' }); +function getWeeksInMonth(year: number, monthIndex: number): number[] { + const firstDayOfMonth = startOfMonth(new Date(year, monthIndex)); + const nextMonth = startOfMonth(addMonths(firstDayOfMonth, 1)); - const [startDate, setStartDate] = useState(new Date(defaultStartDateString)); - const [endDate, setEndDate] = useState(new Date(defaultEndDateString)); + let weeks = []; + let currentDay = firstDayOfMonth; - const [weeksForDateRange, setWeeksForDateRange] = useState< - { name: string; year: number; weeks: number[]; monthIndex: number }[] - >([]); + while (currentDay < nextMonth) { + weeks.push(getISOWeek(currentDay)); + currentDay = addWeeks(currentDay, 1); + } - const handleStartDateChange = (date: Date | null) => { - if (date) { - const adjustedEndDate = endDate && date.getTime() > endDate.getTime() ? date : endDate; - setStartDate(date); - setEndDate(adjustedEndDate); - setWeeksForDateRange(generateWeeksForDateRange(date, adjustedEndDate)); - } - }; + return weeks; +} + +const CapacityGroupSumView: React.FC = ({ capacityGroup, materialDemands }) => { + + const { demandcategories } = useContext(DemandCategoryContext) || {}; + const currentYear = new Date().getFullYear(); + + const monthsCurrentYear = Array.from({ length: 12 }, (_, monthIndex) => { + const monthStart = new Date(currentYear, monthIndex, 1); + const monthName = format(monthStart, 'MMM'); + const weeks = getWeeksInMonth(currentYear, monthIndex); + + + return { + name: monthName, + year: currentYear, + weeks: weeks, + monthIndex: monthIndex, + }; + }); + + const monthsPreviousYear = Array.from({ length: 1 }, (_, monthIndex) => { + const monthStart = new Date(currentYear - 1, monthIndex + 11, 1); + const monthName = format(monthStart, 'MMM'); + const weeks = getWeeksInMonth(currentYear - 1, monthIndex + 11); + + return { + name: monthName, + year: currentYear - 1, + weeks: weeks, + monthIndex: monthIndex + 11, + }; + }); + + const monthsNextYear = Array.from({ length: 1 }, (_, monthIndex) => { + const monthStart = new Date(currentYear + 1, monthIndex, 1); + const monthName = format(monthStart, 'MMM'); + const weeks = getWeeksInMonth(currentYear + 1, monthIndex); + + return { + name: monthName, + year: currentYear + 1, + weeks: weeks, + monthIndex: monthIndex, + }; + }); + + const totalWeeksPreviousYear = monthsPreviousYear.reduce((total, month) => total + month.weeks.length, 0); + const totalWeeksCurrentYear = monthsCurrentYear.reduce((total, month) => total + month.weeks.length, 0); + const totalWeeksNextYear = monthsNextYear.reduce((total, month) => total + month.weeks.length, 0); - const handleEndDateChange = (date: Date | null) => { - if (date) { - const adjustedStartDate = startDate && date.getTime() < startDate.getTime() ? date : startDate; - setStartDate(adjustedStartDate); - setEndDate(date); - setWeeksForDateRange(generateWeeksForDateRange(adjustedStartDate, date)); - } - }; //Mapping of categories const idToNumericIdMap: Record = {}; @@ -93,43 +127,76 @@ const CapacityGroupSumView: React.FC = ({ capacityGroup, })); }; - const { demandSums, computedSums } = useMemo(() => { - const demandSums: Record> = {}; - const computedSums: Record> = {}; + const demandSumsByWeek: Record = {}; + const computedDemandSums: Record = useMemo(() => { + // Populate demandSumsByWeek if (capacityGroup && materialDemands) { materialDemands.forEach((demand) => { demand.demandSeries?.forEach((demandSeries) => { demandSeries.demandSeriesValues.forEach((demandSeriesValue) => { - const year = new Date(demandSeriesValue.calendarWeek).getFullYear(); const week = getISOWeek(new Date(demandSeriesValue.calendarWeek)); + demandSumsByWeek[week] = (demandSumsByWeek[week] || 0) + demandSeriesValue.demand; + }); + }); + }); + } - // Populate demandSums - if (!demandSums[year]) { - demandSums[year] = {}; - } - demandSums[year][week] = (demandSums[year][week] || 0) + demandSeriesValue.demand; + const computedSums: Record = {}; - // Populate computedSums - if (!computedSums[year]) { - computedSums[year] = {}; - } - if (!computedSums[year][week]) { - computedSums[year][week] = 0; + for (const week in demandSumsByWeek) { + computedSums[week] = 0; + materialDemands?.forEach((demand) => { + demand.demandSeries?.forEach((demandSeries) => { + demandSeries.demandSeriesValues.forEach((demandSeriesValue) => { + const seriesWeek = getISOWeek(new Date(demandSeriesValue.calendarWeek)); + if (seriesWeek.toString() === week) { + computedSums[week] += demandSeriesValue.demand; } - computedSums[year][week] += demandSeriesValue.demand; }); }); }); } - return { demandSums, computedSums }; + return computedSums; }, [capacityGroup, materialDemands]); + const demandSums = useMemo(() => { + + + // Populate demandSumsByWeek + if (capacityGroup && materialDemands) { + materialDemands.forEach((demand) => { + demand.demandSeries?.forEach((demandSeries) => { + demandSeries.demandSeriesValues.forEach((demandSeriesValue) => { + const week = getISOWeek(new Date(demandSeriesValue.calendarWeek)); + demandSumsByWeek[week] = (demandSumsByWeek[week] || 0) + demandSeriesValue.demand; + }); + }); + }); + } + + // Iterate over demandSumsByWeek to populate computedDemandSums + for (const week in demandSumsByWeek) { + computedDemandSums[week] = 0; + materialDemands?.forEach((demand) => { + demand.demandSeries?.forEach((demandSeries) => { + demandSeries.demandSeriesValues.forEach((demandSeriesValue) => { + const seriesWeek = getISOWeek(new Date(demandSeriesValue.calendarWeek)); + if (seriesWeek.toString() === week) { + computedDemandSums[week] += demandSeriesValue.demand; + } + }); + }); + }); + } + + return computedDemandSums; + }, [capacityGroup, materialDemands]); // Calculate demand sums for each demand name - const demandSumsByDemandAndWeek: Record>> = {}; + const demandSumsByDemandAndWeek: Record> = {}; if (capacityGroup && materialDemands) { materialDemands.forEach((demand) => { @@ -138,170 +205,199 @@ const CapacityGroupSumView: React.FC = ({ capacityGroup, demand.demandSeries?.forEach((demandSeries) => { demandSeries.demandSeriesValues.forEach((demandSeriesValue) => { - const year = new Date(demandSeriesValue.calendarWeek).getFullYear(); const week = getISOWeek(new Date(demandSeriesValue.calendarWeek)); - - if (!demandSumsByDemandAndWeek[demandName][year]) { - demandSumsByDemandAndWeek[demandName][year] = {}; - } - - demandSumsByDemandAndWeek[demandName][year][week] = (demandSumsByDemandAndWeek[demandName][year][week] || 0) + demandSeriesValue.demand; + const demandSum = demandSeriesValue.demand; + demandSumsByDemandAndWeek[demandName][week] = (demandSumsByDemandAndWeek[demandName][week] || 0) + demandSum; }); }); }); } + /*To focus on the first value on the table*/ + const firstNonZeroDemandRef = useRef(null); + + useEffect(() => { + let firstNonZeroDemandWeek: number | null = null; + + // Iterate over demandSums object to find the first non-zero demand week + for (const week in demandSums) { + if (demandSums[week] !== 0) { + firstNonZeroDemandWeek = parseInt(week); + break; + } + } + + if (firstNonZeroDemandWeek !== null) { + const cellElement = document.getElementById(`cell-${firstNonZeroDemandWeek}`); + + // Check if the element exists before focusing + if (cellElement && firstNonZeroDemandRef.current) { + // Focus on the first non-zero demand sum cell + cellElement.focus(); + cellElement.scrollIntoView({ behavior: 'smooth', block: 'center', inline: 'center' }); + } + } + }, [demandSums]); - // Batch update actualCapacityMap with year mapping - const actualCapacityMap: Record> = useMemo(() => { - const capacityMap: Record> = {}; + // Batch update actualCapacityMap + const actualCapacityMap: Record = useMemo(() => { + const capacityMap: Record = {}; if (capacityGroup && capacityGroup.capacities) { capacityGroup.capacities.forEach((capacity) => { - const year = new Date(capacity.calendarWeek).getFullYear(); const week = getISOWeek(new Date(capacity.calendarWeek)); - - if (!capacityMap[year]) { - capacityMap[year] = {}; - } - - capacityMap[year][week] = capacity.actualCapacity; + capacityMap[week] = capacity.actualCapacity; }); } return capacityMap; - }, [capacityGroup]); + }, [computedDemandSums]); // Calculate deltaMap directly based on demandSumsByWeek and actualCapacityMap const deltaMap: Record> = useMemo(() => { const calculatedDeltaMap: Record> = {}; - // Calculate deltas for each month in weeksForDateRange - weeksForDateRange.forEach((month) => { - calculatedDeltaMap[month.year] = calculatedDeltaMap[month.year] || {}; // Set up year if not present + // Calculate deltas for the previous year + monthsPreviousYear.forEach((month) => { + calculatedDeltaMap[month.year] = calculatedDeltaMap[month.year] || {}; + month.weeks.forEach((week) => { + calculatedDeltaMap[month.year][week] = + (actualCapacityMap[week] || 0) - (computedDemandSums[week] || 0); + }); + }); + + // Calculate deltas for the current year + monthsCurrentYear.forEach((month) => { + calculatedDeltaMap[month.year] = calculatedDeltaMap[month.year] || {}; + month.weeks.forEach((week) => { + calculatedDeltaMap[month.year][week] = + (actualCapacityMap[week] || 0) - (computedDemandSums[week] || 0); + }); + }); - // Ensure the correct assignment of capacity and demand sums by week + // Calculate deltas for the next year + monthsNextYear.forEach((month) => { + calculatedDeltaMap[month.year] = calculatedDeltaMap[month.year] || {}; month.weeks.forEach((week) => { calculatedDeltaMap[month.year][week] = - (actualCapacityMap[month.year]?.[week] || 0) - - (computedSums[month.year]?.[week] || 0); + (actualCapacityMap[week] || 0) - (computedDemandSums[week] || 0); }); }); return calculatedDeltaMap; - }, [computedSums, actualCapacityMap, weeksForDateRange]); + }, [computedDemandSums]); // Empty dependency array ensures that this useMemo runs only once - useEffect(() => { - setWeeksForDateRange(generateWeeksForDateRange(startDate, endDate)); - updateParentDateRange(startDate, endDate); - }, [startDate, endDate]); + // Function to get the beginning and end dates of the week + const getWeekDates = (year: number, month: string, week: number) => { + const startDate = getISOWeekMonday(year, week); + + const endDate = new Date(startDate); + endDate.setDate(endDate.getDate() + 6); // Assuming weeks end on Saturdays + + return { + startDate: startDate.toDateString(), + endDate: endDate.toDateString(), + }; + }; return ( -
-
-
-
Data Range
-
- handleStartDateChange(date)} - selectsStart - startDate={startDate} - endDate={endDate} - placeholderText="Select a Start Date" - showYearDropdown - showMonthDropdown - showWeekNumbers - /> - - - handleEndDateChange(date)} - selectsEnd - startDate={startDate} - endDate={endDate} - minDate={startDate} - placeholderText="Select a End Date" - showMonthDropdown - showYearDropdown - showWeekNumbers - /> -
-
-
+
- - {weeksForDateRange.reduce((acc: { year: number; weeks: number }[], monthData) => { - const existingYearIndex = acc.findIndex((data) => data.year === monthData.year); - if (existingYearIndex === -1) { - acc.push({ year: monthData.year as number, weeks: monthData.weeks.length as number }); - } else { - acc[existingYearIndex].weeks += monthData.weeks.length; - } - return acc; - }, []).map((yearData, index) => ( - - ))} + + + - {/* Render headers based on data */} - {weeksForDateRange.map((monthData) => ( - + ))} + {monthsCurrentYear.map((month) => ( + + ))} + {monthsNextYear.map((month) => ( + ))} - - - {weeksForDateRange.reduce((acc, curr) => acc.concat(curr.weeks), []).map((week) => { - // Find the relevant monthData for the current week - const monthData = weeksForDateRange.find((month) => month.weeks.includes(week)); - - if (!monthData) { - // Handle the case where monthData is not found - return null; - } - - return ( - - - ); - })} + )) + )} + {monthsCurrentYear.map((month) => + month.weeks.map((week) => ( + + )) + )} + {monthsNextYear.map((month) => + month.weeks.map((week) => ( + + )) + )} @@ -310,25 +406,21 @@ const CapacityGroupSumView: React.FC = ({ capacityGroup, {expandedDemandRows['total'] ? : } Demands (Sum) - {weeksForDateRange.map((month) => - month.weeks.map((week) => { - const demandSum = demandSums[month.year]?.[week] || 0; - const computedSum = computedSums[month.year]?.[week] || 0; - - return ( - - ); - }) + {monthsPreviousYear.concat(monthsCurrentYear, monthsNextYear).map((month) => + month.weeks.map((week) => ( + + )) )} - {expandedDemandRows['total'] && ( <> {capacityGroup && @@ -344,10 +436,10 @@ const CapacityGroupSumView: React.FC = ({ capacityGroup, {expandedDemandRows[demand.id] ? : } {demand.materialDescriptionCustomer} - {weeksForDateRange.map((month) => + {monthsPreviousYear.concat(monthsCurrentYear, monthsNextYear).map((month) => month.weeks.map((week) => { const demandSum = - demandSumsByDemandAndWeek[demand.materialDescriptionCustomer]?.[month.year]?.[week] || null; + demandSumsByDemandAndWeek[demand.materialDescriptionCustomer]?.[week] || null; return ( ); }) @@ -392,7 +476,6 @@ const CapacityGroupSumView: React.FC = ({ capacityGroup, ))} )} - ))} @@ -401,29 +484,28 @@ const CapacityGroupSumView: React.FC = ({ capacityGroup, - - {weeksForDateRange - .reduce((acc, curr) => acc.concat(curr.weeks), []) - .map((weekNumber) => ( - - ))} + )) + )} - {weeksForDateRange.map((month) => + {monthsPreviousYear.concat(monthsCurrentYear, monthsNextYear).map((month) => month.weeks.map((week) => { const matchingCapacity = capacityGroup?.capacities.find((capacity) => { const capacityWeek = new Date(capacity.calendarWeek); - return getISOWeek(capacityWeek) === week && capacityWeek.getFullYear() === month.year; + return getISOWeek(capacityWeek) === week; }); const actualCapacity = matchingCapacity?.actualCapacity ?? '-'; return ( - ); @@ -434,16 +516,16 @@ const CapacityGroupSumView: React.FC = ({ capacityGroup, - {weeksForDateRange.map((month) => + {monthsPreviousYear.concat(monthsCurrentYear, monthsNextYear).map((month) => month.weeks.map((week) => { const matchingCapacity = capacityGroup?.capacities.find((capacity) => { const capacityWeek = new Date(capacity.calendarWeek); - return getISOWeek(capacityWeek) === week && capacityWeek.getFullYear() === month.year; + return getISOWeek(capacityWeek) === week; }); const maximumCapacity = matchingCapacity?.maximumCapacity ?? '-'; return ( - ); @@ -454,43 +536,29 @@ const CapacityGroupSumView: React.FC = ({ capacityGroup, - {weeksForDateRange - .reduce((acc, curr) => acc.concat(curr.weeks), []) - .map((weekNumber) => ( - - ))} + )) + )} - - {weeksForDateRange.map((month) => - month.weeks.map((week) => { - const deltaValue = deltaMap[month.year]?.[week]; - const deltaClass = - deltaValue !== undefined && deltaValue !== null - ? deltaValue < 0 - ? 'bg-light-red' - : deltaValue > 0 - ? 'bg-light-green' - : '' - : ''; - - return ( - - ); - }) + {monthsPreviousYear.concat(monthsCurrentYear, monthsNextYear).map((month) => + month.weeks.map((week) => ( + + )) )} -
- {yearData.year} - + {currentYear - 1} + + {currentYear} + + {currentYear + 1} +
- {monthData.name} + {monthsPreviousYear.map((month) => ( + + {month.name} + + {month.name} + + {month.name}
+ {monthsPreviousYear.map((month) => + month.weeks.map((week) => ( + - {`Week ${week} - ${getWeekDates(monthData.year, monthData.name, week).startDate} to ${getWeekDates( - monthData.year, - monthData.name, + + {`Week ${week} - ${getWeekDates(month.year, month.name, week).startDate} to ${getWeekDates( + month.year, + month.name, week ).endDate}`} } > - {week} + {week} + + {`Week ${week} - ${getWeekDates(month.year, month.name, week).startDate} to ${getWeekDates( + month.year, + month.name, + week + ).endDate}`} + + } + > + {week} + + + + {`Week ${week} - ${getWeekDates(month.year, month.name, week).startDate} to ${getWeekDates( + month.year, + month.name, + week + ).endDate}`} + + } + > + {week} + +
- {demandSum !== 0 ? computedSum : '-'} - + {demandSums[week] !== 0 ? demandSums[week] : '-'} {/*Todo Stylize */} +
{demandSum !== null ? (demandSum || 0) : '-'} @@ -366,23 +458,15 @@ const CapacityGroupSumView: React.FC = ({ capacityGroup, {demandSeries.demandCategory.demandCategoryName} - {weeksForDateRange.map((month) => + {monthsPreviousYear.concat(monthsCurrentYear, monthsNextYear).map((month) => month.weeks.map((week) => { - const demandValue = demandSeries.demandSeriesValues.find((demandValue) => { - const valueDate = new Date(demandValue.calendarWeek); - const valueYear = valueDate.getFullYear(); - const valueWeek = getISOWeek(valueDate); - return valueYear === month.year && valueWeek === week; - }); - + const demandValue = demandSeries.demandSeriesValues.find( + (demandValue) => getISOWeek(new Date(demandValue.calendarWeek)) === week + ); const demandSum = demandValue?.demand || null; - return ( - - {demandSum !== null ? demandSum || 0 : '-'} + + {demandSum !== null ? (demandSum || 0) : '-'}
-
+ {monthsPreviousYear.concat(monthsCurrentYear, monthsNextYear).map((month) => + month.weeks.map((week) => ( + {' '}
Actual Capacity
+ {actualCapacity.toString()}
Maximum Capacity
+ {maximumCapacity.toString()}
-
+ {monthsPreviousYear.concat(monthsCurrentYear, monthsNextYear).map((month) => + month.weeks.map((week) => ( + {' '}
Delta
- {typeof deltaValue === 'number' && deltaValue > 0 ? `+${deltaValue}` : deltaValue ?? '-'} - 0 ? 'bg-light-green' : ''}`} + > + {deltaMap[month.year][week] > 0 ? `+${deltaMap[month.year][week]}` : deltaMap[month.year][week]} +
diff --git a/demand-capacity-mgmt-frontend/src/components/capacitygroup/CapacityGroupWizardModal.tsx b/demand-capacity-mgmt-frontend/src/components/capacitygroup/CapacityGroupWizardModal.tsx index 11e12da5..0204f2fc 100644 --- a/demand-capacity-mgmt-frontend/src/components/capacitygroup/CapacityGroupWizardModal.tsx +++ b/demand-capacity-mgmt-frontend/src/components/capacitygroup/CapacityGroupWizardModal.tsx @@ -19,7 +19,7 @@ * SPDX-License-Identifier: Apache-2.0 * ******************************************************************************** */ -import { useCallback, useContext, useEffect, useRef, useState } from 'react'; +import { useContext, useEffect, useState } from 'react'; import { Alert, Button, Col, Container, Row } from 'react-bootstrap'; import Form from 'react-bootstrap/Form'; import Modal from 'react-bootstrap/Modal'; @@ -29,7 +29,6 @@ import Select from 'react-select'; import { CapacityGroupContext } from '../../contexts/CapacityGroupsContextProvider'; import { FavoritesContext } from '../../contexts/FavoritesContextProvider'; import { UnitsofMeasureContext } from '../../contexts/UnitsOfMeasureContextProvider'; -import { useUser } from '../../contexts/UserContext'; import CustomOption from '../../interfaces/customoption_interface'; import { DemandProp } from '../../interfaces/demand_interfaces'; import { FavoriteType } from '../../interfaces/favorite_interfaces'; @@ -44,7 +43,6 @@ interface CapacityGroupWizardModalProps { } function CapacityGroupWizardModal({ show, onHide, checkedDemands, demands }: CapacityGroupWizardModalProps) { - const { user } = useUser(); const [step, setStep] = useState(0); const [groupName, setGroupName] = useState(''); const [defaultActualCapacity, setDefaultActualCapacity] = useState(''); @@ -66,6 +64,7 @@ function CapacityGroupWizardModal({ show, onHide, checkedDemands, demands }: Cap // Function to get the unit measure description based on id const getUnitMeasureDescription = (unitMeasureId: string) => { + console.log(unitMeasureId) const unitMeasure = unitsofmeasureContext?.unitsofmeasure.find(unit => unit.id === unitMeasureId); return unitMeasure ? `${unitMeasure.dimension} - ${unitMeasure.description} (${unitMeasure.unSymbol})` : 'N/A'; }; @@ -164,7 +163,7 @@ function CapacityGroupWizardModal({ show, onHide, checkedDemands, demands }: Cap startDate: earliestDate, endDate: latestDate, customer: selectedDemands.length > 0 ? selectedDemands[0].customer.id : '', - supplier: user?.companyID || '', + supplier: selectedDemands.length > 0 ? selectedDemands[0].supplier.id : '', linkMaterialDemandIds: selectedDemands.map((demand) => demand.id), }; @@ -199,32 +198,60 @@ function CapacityGroupWizardModal({ show, onHide, checkedDemands, demands }: Cap }; const [options, setOptions] = useState([]); // State to store options for Creatable component - - const fetchFavoritesByTypeRef = useRef(fetchFavoritesByType); - const fetchData = useCallback(async () => { - try { - setIsLoading(true); - const favoriteIdsSet = new Set(); // Set to store unique favorite material demand IDs - const fetchFavoritesByType = fetchFavoritesByTypeRef.current; - let materialDemandOptions: any[] = []; - - // Fetch material demands from favorites - const favoritesResponse = await fetchFavoritesByType(FavoriteType.MATERIAL_DEMAND); - const favoriteMaterialDemands = favoritesResponse?.materialDemands || []; - - // Filter and map favorite material demands to options, ensuring uniqueness based on IDs - const favoriteOptions = favoriteMaterialDemands - .filter((md: any) => { + useEffect(() => { + const fetchData = async () => { + try { + setIsLoading(true); + const favoriteIdsSet = new Set(); // Set to store unique favorite material demand IDs + let materialDemandOptions: any[] = []; + + // Fetch material demands from favorites + const favoritesResponse = await fetchFavoritesByType(FavoriteType.MATERIAL_DEMAND); + const favoriteMaterialDemands = favoritesResponse?.materialDemands || []; + + // Filter and map favorite material demands to options, ensuring uniqueness based on IDs + const favoriteOptions = favoriteMaterialDemands + .filter((md: any) => { + if (favoriteIdsSet.has(md.id)) { + return false; // Skip duplicate favorites + } + favoriteIdsSet.add(md.id); // Add favorite ID to set + return true; // Include only unique favorites + }) + .map((md: any) => { + const label = ( +
+ {md.materialNumberCustomer || 'N/A'} - {md.materialNumberSupplier || 'N/A'} - {md.materialDescriptionCustomer || 'N/A'} +
+ ); + return { + value: md, + label: label, + }; + }); + + // Fetch material demands from demands prop + const demandMaterialDemands = demands || []; + + // Filter demand material demands to exclude those with IDs present in favorites + const filteredDemandOptions = demandMaterialDemands.filter((md: any) => { + // Exclude demand if its ID is present in favorites if (favoriteIdsSet.has(md.id)) { - return false; // Skip duplicate favorites + return false; } - favoriteIdsSet.add(md.id); // Add favorite ID to set - return true; // Include only unique favorites - }) - .map((md: any) => { + // Exclude demand if its linkStatus is neither 'TODO' nor 'UNLINKED' + if (md.linkStatus !== 'TODO' && md.linkStatus !== 'UNLINKED') { + return false; + } + // else + return true; + }); + + // Map demand material demands to options + const demandOptions = filteredDemandOptions.map((md: any) => { const label = (
- {md.materialNumberCustomer || 'N/A'} - {md.materialNumberSupplier || 'N/A'} - {md.materialDescriptionCustomer || 'N/A'} + {md.materialNumberCustomer || 'N/A'} - {md.materialNumberSupplier || 'N/A'} - {md.materialDescriptionCustomer || 'N/A'}
); return { @@ -233,50 +260,22 @@ function CapacityGroupWizardModal({ show, onHide, checkedDemands, demands }: Cap }; }); - // Fetch material demands from demands prop - const demandMaterialDemands = demands || []; - - // Filter demand material demands to exclude those with IDs present in favorites - const filteredDemandOptions = demandMaterialDemands.filter((md: any) => { - // Exclude demand if its ID is present in favorites - if (favoriteIdsSet.has(md.id)) { - return false; - } - // Exclude demand if its linkStatus is neither 'TODO' nor 'UNLINKED' - if (md.linkStatus !== 'TODO' && md.linkStatus !== 'UNLINKED') { - return false; - } - // else - return true; - }); + // Combine favorite options and demand options + materialDemandOptions = [...favoriteOptions, ...demandOptions]; - // Map demand material demands to options - const demandOptions = filteredDemandOptions.map((md: any) => { - const label = ( -
- {md.materialNumberCustomer || 'N/A'} - {md.materialNumberSupplier || 'N/A'} - {md.materialDescriptionCustomer || 'N/A'} -
- ); - return { - value: md, - label: label, - }; - }); + console.log(materialDemandOptions); - // Combine favorite options and demand options - materialDemandOptions = [...favoriteOptions, ...demandOptions]; + setOptions(materialDemandOptions); // Update options state with combined material demands + } catch (error) { + console.error('Error fetching filtered capacity groups:', error); + } finally { + setIsLoading(false); + } + }; + fetchData(); - setOptions(materialDemandOptions); // Update options state with combined material demands - } catch (error) { - console.error('Error fetching filtered capacity groups:', error); - } finally { - setIsLoading(false); - } - }, [demands, fetchFavoritesByTypeRef]); + }, [demands]); - useEffect(() => { - fetchData(); - }, [fetchData]); return ( <> @@ -290,12 +289,11 @@ function CapacityGroupWizardModal({ show, onHide, checkedDemands, demands }: Cap Capacity Group Wizard - {isLoading && <> } + {isLoading && <> } {isSuccess ? (
- Capacity group created ! - It can now be found on the window.open(`/details/${createdgroupid}`, '_blank')}> Capacity group list. - You can now close this prompt. + Capacity group created. + It can now be found on the Capacity group list.
) : ( <> diff --git a/demand-capacity-mgmt-frontend/src/components/capacitygroup/CapacityGroupsList.tsx b/demand-capacity-mgmt-frontend/src/components/capacitygroup/CapacityGroupsList.tsx index 63cfd324..8bd25f72 100644 --- a/demand-capacity-mgmt-frontend/src/components/capacitygroup/CapacityGroupsList.tsx +++ b/demand-capacity-mgmt-frontend/src/components/capacitygroup/CapacityGroupsList.tsx @@ -21,12 +21,11 @@ */ -import React, { useCallback, useContext, useEffect, useMemo, useState } from 'react'; +import React, { useContext, useEffect, useMemo, useState } from 'react'; import { Button, Col, Dropdown, Form, OverlayTrigger, Row, Tooltip } from 'react-bootstrap'; import { FaCopy, FaEllipsisV, FaEye, FaRedo } from 'react-icons/fa'; import { LuStar } from 'react-icons/lu'; import { CapacityGroupContext } from '../../contexts/CapacityGroupsContextProvider'; -import { CompanyContext } from '../../contexts/CompanyContextProvider'; import { FavoritesContext } from "../../contexts/FavoritesContextProvider"; import { useUser } from '../../contexts/UserContext'; import '../../index.css'; @@ -53,7 +52,6 @@ const CapacityGroupsList: React.FC = () => { const [sortOrder, setSortOrder] = useState('asc'); const [capacitygroupsPerPage, setcapacitygroupsPerPage] = useState(20); // Set the default value here const { addFavorite, fetchFavoritesByType, deleteFavorite } = useContext(FavoritesContext)!; - const { findCompanyByCompanyID } = useContext(CompanyContext)!; const [favoriteCapacityGroups, setFavoriteCapacityGroups] = useState([]); const handleSort = (column: string) => { @@ -66,7 +64,7 @@ const CapacityGroupsList: React.FC = () => { setSortOrder('asc'); } }; - const fetchFavorites = useCallback(async () => { + const fetchFavorites = async () => { try { const favorites = await fetchFavoritesByType(FavoriteType.CAPACITY_GROUP); if (favorites && favorites.capacityGroups) { @@ -75,14 +73,13 @@ const CapacityGroupsList: React.FC = () => { } catch (error) { console.error('Error fetching favorites by type in DemandList:', error); } - }, [fetchFavoritesByType]); - - const handleRefreshClick = useCallback(async () => { + }; + const handleRefreshClick = async () => { await fetchCapacityGroupsWithRetry(); await fetchFavorites(); - }, [fetchCapacityGroupsWithRetry, fetchFavorites]); + }; - const toggleFavorite = useCallback(async (capacityGroupID: string) => { + const toggleFavorite = async (capacityGroupID: string) => { if (favoriteCapacityGroups.includes(capacityGroupID)) { await deleteFavorite(capacityGroupID) setFavoriteCapacityGroups(prev => prev.filter(id => id !== capacityGroupID)); @@ -91,19 +88,14 @@ const CapacityGroupsList: React.FC = () => { setFavoriteCapacityGroups(prev => [...prev, capacityGroupID]); } handleRefreshClick(); - }, [favoriteCapacityGroups, handleRefreshClick, addFavorite, deleteFavorite]); - - + }; useEffect(() => { fetchFavorites(); - }, [capacitygroups, fetchFavorites]); + }, [capacitygroups]); - const isCapacityGroupFavorite = useMemo(() => { - const isFavorited = (capacityGroupID: string) => favoriteCapacityGroups.includes(capacityGroupID); - return isFavorited; - }, [favoriteCapacityGroups]); + const isCapacityGroupFavorite = (capacityGroupID: string) => favoriteCapacityGroups.includes(capacityGroupID); useMemo(() => { let filteredcapacitygroups = [...capacitygroups]; @@ -125,6 +117,12 @@ const CapacityGroupsList: React.FC = () => { const favoriteCapacityGroups = filteredcapacitygroups.filter((capacitygroup) => isCapacityGroupFavorite(capacitygroup.internalId)); const unfavoritedCapacityGroups = filteredcapacitygroups.filter((capacitygroup) => !isCapacityGroupFavorite(capacitygroup.internalId)); + // Sort favorited demands by changedAt timestamp in descending order + //favoriteCapacityGroups.sort((a, b) => new Date(b.changedAt).getTime() - new Date(a.changedAt).getTime()); + + // Sort unfavorited demands by changedAt timestamp in descending order + //unfavoritedCapacityGroups.sort((a, b) => new Date(b.changedAt).getTime() - new Date(a.changedAt).getTime()); + // Concatenate favorited and unfavorited demands const sortedCapacityGroups = [...favoriteCapacityGroups, ...unfavoritedCapacityGroups]; @@ -143,7 +141,7 @@ const CapacityGroupsList: React.FC = () => { } setFilteredCapacityGroups(sortedCapacityGroups); - }, [capacitygroups, isCapacityGroupFavorite, searchQuery, sortColumn, sortOrder]); + }, [capacitygroups, searchQuery, sortColumn, sortOrder]); const slicedcapacitygroups = useMemo(() => { const indexOfLastCapacityGroup = currentPage * capacitygroupsPerPage; @@ -170,7 +168,7 @@ const CapacityGroupsList: React.FC = () => { /> -
+ Go to Details} @@ -181,9 +179,8 @@ const CapacityGroupsList: React.FC = () => {
- -
+ {capacitygroup.internalId}} @@ -197,23 +194,14 @@ const CapacityGroupsList: React.FC = () => { > -
+ {capacitygroup.name} - {user?.role === 'SUPPLIER' && ( - <> - {capacitygroup.customerBPNL} - {capacitygroup.customerName} - - )} - - {user?.role === 'CUSTOMER' && ( - <> - {capacitygroup.supplierBNPL} - - )} - + {capacitygroup.customerBPNL} + {capacitygroup.customerName} + {capacitygroup.supplierBNPL} {capacitygroup.numberOfMaterials} + {capacitygroup.favoritedBy} {capacitygroup.linkStatus === EventType.TODO ? ( @@ -250,7 +238,7 @@ const CapacityGroupsList: React.FC = () => { )), - [slicedcapacitygroups, favoriteCapacityGroups, toggleFavorite] + [slicedcapacitygroups] ); return ( @@ -259,7 +247,6 @@ const CapacityGroupsList: React.FC = () => {

{getUserGreeting(user)}!

- {findCompanyByCompanyID(user?.companyID || '')?.companyName || ''}
@@ -267,10 +254,8 @@ const CapacityGroupsList: React.FC = () => {
-
@@ -311,11 +296,7 @@ const CapacityGroupsList: React.FC = () => { htmlSize={10} max={100} value={capacitygroupsPerPage} - onChange={(e) => { - const value = e.target.value; - const newValue = value === '' ? 1 : Math.max(1, parseInt(value)); // Ensure it's not empty and not less than 1 - setcapacitygroupsPerPage(newValue); - }} + onChange={(e) => setcapacitygroupsPerPage(Number(e.target.value))} /> diff --git a/demand-capacity-mgmt-frontend/src/components/capacitygroup/CapacityGroupsTableHeaders.tsx b/demand-capacity-mgmt-frontend/src/components/capacitygroup/CapacityGroupsTableHeaders.tsx index 25b55540..4df75bc5 100644 --- a/demand-capacity-mgmt-frontend/src/components/capacitygroup/CapacityGroupsTableHeaders.tsx +++ b/demand-capacity-mgmt-frontend/src/components/capacitygroup/CapacityGroupsTableHeaders.tsx @@ -22,7 +22,6 @@ import React from 'react'; import { BiCaretDown, BiCaretUp } from 'react-icons/bi'; -import { useUser } from '../../contexts/UserContext'; type CapacityGroupsTableProps = { sortColumn: string; @@ -31,10 +30,7 @@ type CapacityGroupsTableProps = { capacitygroupsItems: React.ReactNode; }; - - const CapacityGroupsTable: React.FC = ({ sortColumn, sortOrder, handleSort, capacitygroupsItems }) => { - const { user } = useUser(); return ( @@ -51,35 +47,31 @@ const CapacityGroupsTable: React.FC = ({ sortColumn, s {sortColumn === 'name' && sortOrder === 'asc' && } {sortColumn === 'name' && sortOrder === 'desc' && } - {user?.role === 'SUPPLIER' && ( - <> - - - - )} - - {user?.role === 'CUSTOMER' && ( - <> - - - )} + + + + )), - [slicedDemands, favoriteDemands, toggleFavorite, selectedDemands, handleCheckboxChange] + [slicedDemands, selectedDemands, handleCheckboxChange] ); @@ -412,11 +415,7 @@ const DemandList: React.FC<{ htmlSize={10} max={100} value={demandsPerPage} - onChange={(e) => { - const value = e.target.value; - const newValue = value === '' ? 1 : Math.max(1, parseInt(value)); // Ensure it's not empty and not less than 1 - setDemandsPerPage(newValue); - }} + onChange={(e) => setDemandsPerPage(Number(e.target.value))} /> diff --git a/demand-capacity-mgmt-frontend/src/components/demands/DemandManagement.tsx b/demand-capacity-mgmt-frontend/src/components/demands/DemandManagement.tsx index 1d72d7c0..4e712345 100644 --- a/demand-capacity-mgmt-frontend/src/components/demands/DemandManagement.tsx +++ b/demand-capacity-mgmt-frontend/src/components/demands/DemandManagement.tsx @@ -20,7 +20,7 @@ * ******************************************************************************** */ -import React, { useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react'; +import React, { useCallback, useContext, useEffect, useMemo, useState } from 'react'; import { Button, Col, Dropdown, Form, Modal, Row } from 'react-bootstrap'; import { FaCopy, FaEllipsisV, FaInfoCircle, FaRedo, FaSearch, FaTrashAlt } from 'react-icons/fa'; import CompanyContextProvider from '../../contexts/CompanyContextProvider'; @@ -66,10 +66,16 @@ const DemandManagement: React.FC = () => { const [sortOrder, setSortOrder] = useState<'asc' | 'desc'>('asc'); const [demandsPerPage, setDemandsPerPage] = useState(6); //Only show 5 items by default + const [filteredDemands, setFilteredDemands] = useState([]); const { addFavorite, fetchFavoritesByType, deleteFavorite } = useContext(FavoritesContext)!; const [favoriteDemands, setFavoriteDemands] = useState([]); - const fetchFavorites = useCallback(async () => { + const handleRefreshClick = async () => { + await fetchDemandProps(); // Call your fetchEvents function to refresh the data + await fetchFavorites(); + }; + + const fetchFavorites = async () => { try { const favorites = await fetchFavoritesByType(FavoriteType.MATERIAL_DEMAND); if (favorites && favorites.materialDemands) { @@ -78,14 +84,9 @@ const DemandManagement: React.FC = () => { } catch (error) { console.error('Error fetching favorites by type in DemandList:', error); } - }, [fetchFavoritesByType, setFavoriteDemands]); - - const handleRefreshClick = useCallback(async () => { - await fetchDemandProps(); - await fetchFavorites(); - }, [fetchDemandProps, fetchFavorites]); + }; - const toggleFavorite = useCallback(async (demandID: string) => { + const toggleFavorite = async (demandID: string) => { if (favoriteDemands.includes(demandID)) { await deleteFavorite(demandID) setFavoriteDemands(prev => prev.filter(id => id !== demandID)); @@ -94,13 +95,11 @@ const DemandManagement: React.FC = () => { setFavoriteDemands(prev => [...prev, demandID]); } handleRefreshClick(); - }, [favoriteDemands, handleRefreshClick, addFavorite, deleteFavorite]); + }; - const fetchFavoritesRef = useRef(fetchFavorites); useEffect(() => { - fetchFavoritesRef.current(); - fetchDemandProps(); - }, [searchQuery, fetchDemandProps]); + fetchFavorites(); + }, []); const handleSort = (column: string | null) => { @@ -164,12 +163,9 @@ const DemandManagement: React.FC = () => { } }; - const isDemandFavorited = useMemo(() => { - const isFavorited = (demandId: string) => favoriteDemands.includes(demandId); - return isFavorited; - }, [favoriteDemands]); + const isDemandFavorited = (demandId: string) => favoriteDemands.includes(demandId); - const filteredDemands = useMemo(() => { + useMemo(() => { let filteredDemands = [...demandprops]; if (searchQuery !== '') { @@ -193,7 +189,7 @@ const DemandManagement: React.FC = () => { unfavoritedDemands.sort((a, b) => new Date(b.changedAt).getTime() - new Date(a.changedAt).getTime()); // Concatenate favorited and unfavorited demands - let sortedDemands = [...favoritedDemands, ...unfavoritedDemands]; + const sortedDemands = [...favoritedDemands, ...unfavoritedDemands]; if (sortColumn) { // Sort the concatenated array by the specified column @@ -221,9 +217,8 @@ const DemandManagement: React.FC = () => { } } - return sortedDemands; - }, [demandprops, isDemandFavorited, searchQuery, sortColumn, sortOrder]); - + setFilteredDemands(sortedDemands); + }, [demandprops, searchQuery, sortColumn, sortOrder]); const slicedDemands = useMemo(() => { @@ -337,7 +332,7 @@ const DemandManagement: React.FC = () => { )), - [slicedDemands, favoriteDemands, toggleFavorite, user] + [slicedDemands] ); return ( @@ -353,10 +348,8 @@ const DemandManagement: React.FC = () => { onClick={() => setShowAddModal(true)}> New Material Demand )} - @@ -397,11 +390,7 @@ const DemandManagement: React.FC = () => { htmlSize={10} max={100} value={demandsPerPage} - onChange={(e) => { - const value = e.target.value; - const newValue = value === '' ? 1 : Math.max(1, parseInt(value)); // Ensure it's not empty and not less than 1 - setDemandsPerPage(newValue); - }} + onChange={(e) => setDemandsPerPage(Number(e.target.value))} /> diff --git a/demand-capacity-mgmt-frontend/src/components/demands/DemandsOverview.tsx b/demand-capacity-mgmt-frontend/src/components/demands/DemandsOverview.tsx index 82e9242f..ffcbe173 100644 --- a/demand-capacity-mgmt-frontend/src/components/demands/DemandsOverview.tsx +++ b/demand-capacity-mgmt-frontend/src/components/demands/DemandsOverview.tsx @@ -22,30 +22,71 @@ import moment from 'moment'; import 'moment-weekday-calc'; -import React, { useCallback, useContext, useEffect, useState } from 'react'; +import React, { useCallback, useContext, useEffect, useRef, useState } from 'react'; import { Button, ButtonGroup, OverlayTrigger, ToggleButton, Tooltip } from 'react-bootstrap'; import { DemandCategoryContext } from '../../contexts/DemandCategoryProvider'; import { DemandContext } from '../../contexts/DemandContextProvider'; import '../../index.css'; import { Demand, DemandCategory, DemandProp, DemandSeriesValue, MaterialDemandSery } from '../../interfaces/demand_interfaces'; -import { addWeeks, formatISO, getISOWeek, subWeeks } from 'date-fns'; -import { startOfDay } from 'date-fns/esm'; -import DatePicker from 'react-datepicker'; -import 'react-datepicker/dist/react-datepicker.css'; -import { FaRegCalendarCheck } from 'react-icons/fa'; + +import { format, getISOWeek, } from 'date-fns'; import { useNavigate } from 'react-router-dom'; import { useUser } from '../../contexts/UserContext'; -import { generateWeeksForDateRange, getISOWeekMonday } from '../../util/WeeksUtils'; import { LoadingGatheringDataMessage } from '../common/LoadingMessages'; interface WeeklyViewProps { demandId: string; } +function getISOWeekMonday(year: number, isoWeek: number): moment.Moment { + return moment().year(year).isoWeek(isoWeek).startOf('isoWeek'); +} + +function getYearOfWeek(date: moment.Moment): number { + return date.add(3, 'days').year(); +} + + +function getWeeksInMonth(year: number, monthIndex: number, knownNextMonthWeeks?: Set): number[] { + const weeks: Set = new Set(); + + const firstDayOfMonth = moment().year(year).month(monthIndex).startOf('month'); + const lastDayOfMonth = moment().year(year).month(monthIndex).endOf('month'); + // Fetch weeks of the next month if not provided. + if (!knownNextMonthWeeks && monthIndex < 11) { + knownNextMonthWeeks = new Set(getWeeksInMonth(year, monthIndex + 1)); + } + + let currentDay = firstDayOfMonth; + while (currentDay <= lastDayOfMonth) { + const weekNum = currentDay.week(); + const isoWeekYear = getYearOfWeek(currentDay); + + // If the month is January and the week year is the previous year, skip it + if (monthIndex === 0 && isoWeekYear < year) { + currentDay = currentDay.add(1, 'days'); + continue; + } + + // If it's the last week of the month and it's also in the next month, skip it. + if (currentDay.isAfter(moment(new Date(year, monthIndex, 24))) && knownNextMonthWeeks?.has(weekNum)) { + currentDay = currentDay.add(1, 'days'); + continue; + } + + weeks.add(weekNum); + currentDay = currentDay.add(1, 'days'); + } + return Array.from(weeks).sort((a, b) => a - b); +} + + + const WeeklyView: React.FC = ({ demandId }) => { const { updateDemand } = useContext(DemandContext)!; const { demandcategories } = useContext(DemandCategoryContext) ?? {}; + const currentYear = new Date().getFullYear(); const [editMode, setEditMode] = useState(false); const [isLoading, setIsLoading] = useState(true); const { user } = useUser(); @@ -70,40 +111,50 @@ const WeeklyView: React.FC = ({ demandId }) => { } }, [demandId, getDemandbyId, setDemandData, navigate]); + useEffect(() => { + fetchDemandData(); + }, [fetchDemandData]); - const currentDate = startOfDay(new Date()); - const defaultStartDateString = formatISO(subWeeks(currentDate, 8), { representation: 'date' }); - const defaultEndDateString = formatISO(addWeeks(currentDate, 53), { representation: 'date' }); - const [startDate, setStartDate] = useState(new Date(defaultStartDateString)); - const [endDate, setEndDate] = useState(new Date(defaultEndDateString)); - const [weeksForDateRange, setWeeksForDateRange] = useState< - { name: string; year: number; weeks: number[]; monthIndex: number }[] - >([]); + const monthsPreviousYear = Array.from({ length: 1 }, (_, monthIndex) => { + const monthStart = new Date(currentYear - 1, monthIndex + 11, 1); + const monthName = format(monthStart, 'MMM'); // <-- This line + let weeks = getWeeksInMonth(currentYear - 1, monthIndex + 11); + return { + name: monthName, + year: currentYear - 1, + weeks: weeks, + monthIndex: monthIndex + 11, + }; + }); - const handleStartDateChange = (date: Date | null) => { - if (date) { - const adjustedEndDate = endDate && date.getTime() > endDate.getTime() ? date : endDate; - setStartDate(date); - setEndDate(adjustedEndDate); - setWeeksForDateRange(generateWeeksForDateRange(date, adjustedEndDate)); - } - }; + const monthsCurrentYear = Array.from({ length: 12 }, (_, monthIndex) => { + const monthStart = new Date(currentYear, monthIndex, 1); + const monthName = format(monthStart, 'MMM'); + let weeks = getWeeksInMonth(currentYear, monthIndex); + return { + name: monthName, + year: currentYear, + weeks: weeks, + monthIndex: monthIndex, + }; + }); - const handleEndDateChange = (date: Date | null) => { - if (date) { - const adjustedStartDate = startDate && date.getTime() < startDate.getTime() ? date : startDate; - setStartDate(adjustedStartDate); - setEndDate(date); - setWeeksForDateRange(generateWeeksForDateRange(adjustedStartDate, date)); - } - }; + const monthsNextYear = Array.from({ length: 1 }, (_, monthIndex) => { + const monthStart = new Date(currentYear + 1, monthIndex, 1); + const monthName = format(monthStart, 'MMM'); + const weeks = getWeeksInMonth(currentYear + 1, monthIndex); + return { + name: monthName, + year: currentYear + 1, + weeks: weeks, + monthIndex: monthIndex, + }; + }); - - useEffect(() => { - fetchDemandData(); - setWeeksForDateRange(generateWeeksForDateRange(startDate, endDate)); - }, [fetchDemandData, startDate, endDate]); + const totalWeeksPreviousYear = monthsPreviousYear.reduce((total, month) => total + month.weeks.length, 0); + const totalWeeksCurrentYear = monthsCurrentYear.reduce((total, month) => total + month.weeks.length, 0); + const totalWeeksNextYear = monthsNextYear.reduce((total, month) => total + month.weeks.length, 0); // Object to store the demand values based on year, month, and week type DemandValuesMap = Record>>; @@ -130,6 +181,9 @@ const WeeklyView: React.FC = ({ demandId }) => { }; }; + + + useEffect(() => { const newDemandValuesMap: DemandValuesMap = {}; @@ -138,7 +192,7 @@ const WeeklyView: React.FC = ({ demandId }) => { series.demandSeriesValues.forEach((value) => { const date = moment(value.calendarWeek); - const year = date.year(); + const year = moment().year(); const week = date.week(); if (!newDemandValuesMap[categoryId]) { @@ -154,10 +208,41 @@ const WeeklyView: React.FC = ({ demandId }) => { setDemandValuesMap(newDemandValuesMap); }, [demandData]); - /*useEffect(() => { - console.log(demandValuesMap) - console.log(weeksForDateRange) - }, [demandValuesMap]);*/ + + const tableRef = useRef(null); + const [shouldScroll, setShouldScroll] = useState(false); + + useEffect(() => { + if (shouldScroll && tableRef.current && Object.keys(demandValuesMap).length > 0) { + for (const categoryId in demandValuesMap) { + const categoryData: Record> = demandValuesMap[categoryId]; + const years = Object.keys(categoryData); + for (const year of years) { + const weeksWithData = Object.keys(categoryData[year]); + if (weeksWithData.length > 0) { + const firstWeekWithData = parseInt(weeksWithData[0], 10); + const weekHeaderCell = tableRef.current!.querySelector(`#week-${firstWeekWithData}`); + if (weekHeaderCell) { + weekHeaderCell.scrollIntoView({ + behavior: 'smooth', + block: 'center', + inline: 'center', + }); + } + } + } + } + // Reset the shouldScroll state to prevent continuous scrolling + setShouldScroll(false); + } + }, [demandValuesMap, shouldScroll]); + + // Use another useEffect to listen for changes in the tableRef + useEffect(() => { + if (tableRef.current) { + setShouldScroll(true); + } + }, [demandValuesMap, tableRef]); const handleSave = async () => { @@ -172,13 +257,19 @@ const WeeklyView: React.FC = ({ demandId }) => { // Check if there is data for this category in demandValuesMap if (demandValuesMap[categoryId]) { - Object.entries(demandValuesMap[categoryId]).forEach(([year, yearData]) => { - Object.entries(yearData).forEach(([week, demand]) => { - const isoWeekMonday = getISOWeekMonday(parseInt(year), parseInt(week)); - demandSeriesValues.push({ - calendarWeek: isoWeekMonday.format('YYYY-MM-DD'), - demand: demand, - }); + // Loop through months and weeks to populate demandSeriesValues + monthsCurrentYear.forEach((month) => { + month.weeks.forEach((week) => { + const isoWeekMonday = getISOWeekMonday(month.year, week); + isoWeekMonday.format('YYYY-MM-dd') + // Get the Monday of the ISO week + const demand = demandValuesMap[categoryId]?.[month.year]?.[week]; + if (demand !== undefined) { + demandSeriesValues.push({ + calendarWeek: isoWeekMonday.format('YYYY-MM-DD'), + demand: demand, + }); + } }); }); @@ -212,7 +303,6 @@ const WeeklyView: React.FC = ({ demandId }) => { unitMeasureId: demandData.unitMeasureId.id, }; - console.log(updatedDemand) // Perform save operation with updatedDemandData if (filteredUpdatedDemandSeries.length > 0) { try { @@ -290,101 +380,54 @@ const WeeklyView: React.FC = ({ demandId }) => { )} -
-
-
Data Range
-
- handleStartDateChange(date)} - selectsStart - startDate={startDate} - endDate={endDate} - placeholderText="Select a Start Date" - showYearDropdown - showMonthDropdown - showWeekNumbers - /> - - - handleEndDateChange(date)} - selectsEnd - startDate={startDate} - endDate={endDate} - minDate={startDate} - placeholderText="Select a End Date" - showMonthDropdown - showYearDropdown - showWeekNumbers - /> -
-
-
- +
-
handleSort('customerBPNL')}> - Customer BPNL - {sortColumn === 'customerBPNL' && sortOrder === 'asc' && } - {sortColumn === 'customerBPNL' && sortOrder === 'desc' && } - handleSort('customerName')}> - Customer Name - {sortColumn === 'customerName' && sortOrder === 'asc' && } - {sortColumn === 'customerName' && sortOrder === 'desc' && } - handleSort('supplierBNPL')}> - Supplier BPNL - {sortColumn === 'supplierBNPL' && sortOrder === 'asc' && } - {sortColumn === 'supplierBNPL' && sortOrder === 'desc' && } - handleSort('customerBPNL')}> + Customber BPNL + {sortColumn === 'customerBPNL' && sortOrder === 'asc' && } + {sortColumn === 'customerBPNL' && sortOrder === 'desc' && } + handleSort('customerName')}> + Customer Name + {sortColumn === 'customerName' && sortOrder === 'asc' && } + {sortColumn === 'customerName' && sortOrder === 'desc' && } + handleSort('supplierBNPL')}> + Supplier BPNL + {sortColumn === 'supplierBNPL' && sortOrder === 'asc' && } + {sortColumn === 'supplierBNPL' && sortOrder === 'desc' && } + handleSort('numberOfMaterials')}> # of Materials {sortColumn === 'numberOfMaterials' && sortOrder === 'asc' && } {sortColumn === 'numberOfMaterials' && sortOrder === 'desc' && } handleSort('favoritedBy')}> + Favorited by + {sortColumn === 'favoritedBy' && sortOrder === 'asc' && } + {sortColumn === 'favoritedBy' && sortOrder === 'desc' && } + handleSort('status')}> Status {sortColumn === 'status' && sortOrder === 'asc' && } diff --git a/demand-capacity-mgmt-frontend/src/components/common/CompanyOptions.tsx b/demand-capacity-mgmt-frontend/src/components/common/CompanyOptions.tsx index f0a8a651..e313ec36 100644 --- a/demand-capacity-mgmt-frontend/src/components/common/CompanyOptions.tsx +++ b/demand-capacity-mgmt-frontend/src/components/common/CompanyOptions.tsx @@ -20,7 +20,7 @@ * SPDX-License-Identifier: Apache-2.0 * ******************************************************************************** */ -import React, { useCallback, useContext, useEffect, useRef, useState } from 'react'; +import React, { useCallback, useContext, useEffect, useState } from 'react'; import Select, { ActionMeta, OptionTypeBase } from 'react-select'; import { CompanyContext } from '../../contexts/CompanyContextProvider'; import { FavoritesContext } from '../../contexts/FavoritesContextProvider'; @@ -42,11 +42,8 @@ const CompanyOptions: React.FC = ({ selectedCompanyName, on const [companyOptions, setCompanyOptions] = useState<{ value: string; label: string; isFavorite: boolean }[]>([]); const [loading, setLoading] = useState(true); - const fetchFavoritesByTypeRef = useRef(fetchFavoritesByType); - useEffect(() => { const fetchData = async () => { - const fetchFavoritesByType = fetchFavoritesByTypeRef.current; try { setLoading(true); const response = await fetchFavoritesByType(FavoriteType.COMPANY_BASE_DATA); @@ -80,7 +77,7 @@ const CompanyOptions: React.FC = ({ selectedCompanyName, on }; fetchData(); - }, [companies, topCompanies, fetchFavoritesByTypeRef]); + }, [companies]); const selectedOption = companyOptions.find((option) => option.value === selectedCompanyName) || null; diff --git a/demand-capacity-mgmt-frontend/src/components/common/Pagination.tsx b/demand-capacity-mgmt-frontend/src/components/common/Pagination.tsx index 47b97daa..aae8f62a 100644 --- a/demand-capacity-mgmt-frontend/src/components/common/Pagination.tsx +++ b/demand-capacity-mgmt-frontend/src/components/common/Pagination.tsx @@ -27,7 +27,6 @@ interface PaginationProps { setCurrentPage: React.Dispatch>; currentItems: any[]; // Update with the correct type for currentItems items: any[]; // Update with the correct type for items - initialPage?: number; // New prop for initial page } const CustomPagination: React.FC = ({ @@ -35,7 +34,6 @@ const CustomPagination: React.FC = ({ setCurrentPage, currentItems, items, - initialPage = 1, // Default initialPage to 1 if not provided }) => { const numOfPages: number[] = []; @@ -43,7 +41,7 @@ const CustomPagination: React.FC = ({ numOfPages.push(i); } - const [currentButton, setCurrentButton] = useState(initialPage); // Set initialButton state + const [currentButton, setCurrentButton] = useState(1); useEffect(() => { setCurrentPage(currentButton); diff --git a/demand-capacity-mgmt-frontend/src/components/common/TopMenu.tsx b/demand-capacity-mgmt-frontend/src/components/common/TopMenu.tsx index c0b93776..144f1974 100644 --- a/demand-capacity-mgmt-frontend/src/components/common/TopMenu.tsx +++ b/demand-capacity-mgmt-frontend/src/components/common/TopMenu.tsx @@ -33,7 +33,6 @@ import DemandCategoryContextProvider from '../../contexts/DemandCategoryProvider import EventsContextProvider from '../../contexts/EventsContextProvider'; import { InfoMenuProvider } from '../../contexts/InfoMenuContextProvider'; import { useUser } from "../../contexts/UserContext"; -import { getUserName } from '../../interfaces/user_interface'; import { logout } from "../../util/Auth"; import InfoMenu from "../menu/InfoMenu"; @@ -101,7 +100,7 @@ function TopMenuLinks() { - Signed in as: {getUserName(user)} + Signed in as: {user?.username}
Role: {user?.role.toLowerCase()}
diff --git a/demand-capacity-mgmt-frontend/src/components/dcm/AppComponent.tsx b/demand-capacity-mgmt-frontend/src/components/dcm/AppComponent.tsx index 5bd863f8..d18ccf56 100644 --- a/demand-capacity-mgmt-frontend/src/components/dcm/AppComponent.tsx +++ b/demand-capacity-mgmt-frontend/src/components/dcm/AppComponent.tsx @@ -23,7 +23,6 @@ import React from 'react'; import { Route, Routes } from "react-router-dom"; import CapacityGroupsProvider from '../../contexts/CapacityGroupsContextProvider'; -import CompanyContextProvider from '../../contexts/CompanyContextProvider'; import DemandContextProvider from '../../contexts/DemandContextProvider'; import EventsContextProvider from '../../contexts/EventsContextProvider'; import FavoritesContextProvider from "../../contexts/FavoritesContextProvider"; @@ -54,13 +53,10 @@ const AppComponent: React.FC = () => { - - - - - - - + + + + diff --git a/demand-capacity-mgmt-frontend/src/components/demands/DemandAddForm.tsx b/demand-capacity-mgmt-frontend/src/components/demands/DemandAddForm.tsx index 34fa37f0..58de6a9a 100644 --- a/demand-capacity-mgmt-frontend/src/components/demands/DemandAddForm.tsx +++ b/demand-capacity-mgmt-frontend/src/components/demands/DemandAddForm.tsx @@ -26,7 +26,6 @@ import CompanyContextProvider from '../../contexts/CompanyContextProvider'; import DemandCategoryContextProvider from '../../contexts/DemandCategoryProvider'; import { DemandContext } from '../../contexts/DemandContextProvider'; import UnitsofMeasureContextContextProvider from '../../contexts/UnitsOfMeasureContextProvider'; -import { useUser } from '../../contexts/UserContext'; import { Demand } from '../../interfaces/demand_interfaces'; import CompanyOptions from '../common/CompanyOptions'; import UnitsOfMeasureOptions from '../common/UnitsofMeasureOptions'; @@ -114,18 +113,17 @@ const useHandleSubmit = (initialFormState: Demand) => { }; const AddForm: React.FC = () => { - const { user } = useUser(); const initialFormState: Demand = { id: '', materialDescriptionCustomer: '', materialNumberCustomer: '', materialNumberSupplier: '', - customerId: user?.companyID || '', //This will be the ID of the company associated with the logged user + customerId: 'e1abe001-4e24-471f-9b66-a4b3408e3bf6', //This will be the ID of the company associated with the logged user supplierId: '', unitMeasureId: '', materialDemandSeries: [ { - customerLocationId: user?.companyID || '', //This will be the ID of the company associated with the logged user + customerLocationId: 'e1abe001-4e24-471f-9b66-a4b3408e3bf6', //This will be the ID of the company associated with the logged user expectedSupplierLocationId: [], demandCategoryId: '', demandSeriesValues: [], diff --git a/demand-capacity-mgmt-frontend/src/components/demands/DemandList.tsx b/demand-capacity-mgmt-frontend/src/components/demands/DemandList.tsx index 8d5ea6ae..9a434395 100644 --- a/demand-capacity-mgmt-frontend/src/components/demands/DemandList.tsx +++ b/demand-capacity-mgmt-frontend/src/components/demands/DemandList.tsx @@ -78,17 +78,35 @@ const DemandList: React.FC<{ const [demandsPerPage, setDemandsPerPage] = useState(6); //Only show 5 items by default - //const [listedDemands, setListedDemands] = useState([]); - - + const [filteredDemands, setFilteredDemands] = useState([]); + const fetchFavorites = async () => { + try { + const favorites = await fetchFavoritesByType(FavoriteType.MATERIAL_DEMAND); + if (favorites && favorites.materialDemands) { + setFavoriteDemands(favorites.materialDemands.map((fav: MaterialDemandFavoriteResponse) => fav.id)); + } + } catch (error) { + console.error('Error fetching favorites by type in DemandList:', error); + } + }; useEffect(() => { setShowWizardModal(showWizard || false); fetchDemandProps(); fetchFavorites(); - setCurrentPage(1); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [showWizard, searchQuery]); + }, [showWizard]); + + + const filteredDemandsByEventTypes = useMemo(() => { + if (eventTypes.length > 0) { + // If eventTypes array is provided, filter demands based on the specified event types + return filteredDemands.filter((demand) => eventTypes.includes(demand.linkStatus)); + } else { + // If no eventTypes are provided, return all filteredDemands + return filteredDemands; + } + }, [filteredDemands, eventTypes]); + const handleSort = (column: string | null) => { if (sortColumn === column) { @@ -152,27 +170,12 @@ const DemandList: React.FC<{ const handleCloseDetails = () => setShowDetailsModal(false); - const isDemandFavorited = useMemo(() => { - const isFavorited = (demandId: string) => favoriteDemands.includes(demandId); - return isFavorited; - }, [favoriteDemands]); - - const fetchFavorites = useCallback(async () => { - try { - const favorites = await fetchFavoritesByType(FavoriteType.MATERIAL_DEMAND); - if (favorites && favorites.materialDemands) { - setFavoriteDemands(favorites.materialDemands.map((fav: MaterialDemandFavoriteResponse) => fav.id)); - } - } catch (error) { - console.error('Error fetching favorites by type in DemandList:', error); - } - }, [fetchFavoritesByType, setFavoriteDemands]); + const isDemandFavorited = (demandId: string) => favoriteDemands.includes(demandId); - const filteredDemands = useMemo(() => { + useMemo(() => { let filteredDemands = [...demandprops]; if (searchQuery !== '') { - setCurrentPage(1); filteredDemands = filteredDemands.filter((demand) => demand.materialDescriptionCustomer.toLowerCase().includes(searchQuery.toLowerCase()) || demand.id.toString().includes(searchQuery.toLowerCase()) || @@ -182,11 +185,6 @@ const DemandList: React.FC<{ ); } - // Filter by eventTypes if provided - if (eventTypes.length > 0) { - filteredDemands = filteredDemands.filter((demand) => eventTypes.includes(demand.linkStatus)); - } - // Separate favorited and unfavorited demands const favoritedDemands = filteredDemands.filter((demand) => isDemandFavorited(demand.id)); const unfavoritedDemands = filteredDemands.filter((demand) => !isDemandFavorited(demand.id)); @@ -198,7 +196,7 @@ const DemandList: React.FC<{ unfavoritedDemands.sort((a, b) => new Date(b.changedAt).getTime() - new Date(a.changedAt).getTime()); // Concatenate favorited and unfavorited demands - let sortedDemands = [...favoritedDemands, ...unfavoritedDemands]; + const sortedDemands = [...favoritedDemands, ...unfavoritedDemands]; if (sortColumn) { // Sort the concatenated array by the specified column @@ -217,6 +215,7 @@ const DemandList: React.FC<{ // If the types are not string or number, return 0 (no sorting) return 0; + }); if (sortOrder === 'desc') { @@ -224,17 +223,21 @@ const DemandList: React.FC<{ sortedDemands.reverse(); } } - // Return the sortedDemands instead of filteredDemands - return sortedDemands; - }, [demandprops, searchQuery, isDemandFavorited, sortColumn, sortOrder, eventTypes]); + + setFilteredDemands(sortedDemands); + }, [demandprops, searchQuery, sortColumn, sortOrder]); const slicedDemands = useMemo(() => { + // Use filteredDemandsByEventTypes instead of filteredDemands for slicing and rendering const indexOfLastDemand = currentPage * demandsPerPage; const indexOfFirstDemand = indexOfLastDemand - demandsPerPage; - return filteredDemands.slice(indexOfFirstDemand, indexOfLastDemand); - }, [currentPage, demandsPerPage, filteredDemands]); + return filteredDemandsByEventTypes.slice(indexOfFirstDemand, indexOfLastDemand); + }, [filteredDemandsByEventTypes, currentPage, demandsPerPage]); - const totalPagesNum = Math.ceil(filteredDemands.length / demandsPerPage); + const totalPagesNum = useMemo(() => Math.ceil(filteredDemands.length / demandsPerPage), [ + filteredDemands, + demandsPerPage, + ]); const handleCheckboxChange = useCallback( (event: React.ChangeEvent, demandId: string) => { @@ -254,17 +257,17 @@ const DemandList: React.FC<{ [filteredDemands] ); - const toggleFavorite = useCallback(async (demandId: string) => { + const toggleFavorite = async (demandId: string) => { if (favoriteDemands.includes(demandId)) { - await deleteFavorite(demandId); + await deleteFavorite(demandId) setFavoriteDemands(prev => prev.filter(id => id !== demandId)); } else { - await addFavorite(demandId, FavoriteType.MATERIAL_DEMAND); + await addFavorite(demandId, FavoriteType.MATERIAL_DEMAND) setFavoriteDemands(prev => [...prev, demandId]); } fetchFavorites(); fetchDemandProps(); - }, [favoriteDemands, deleteFavorite, addFavorite, fetchFavorites, fetchDemandProps]); + }; const demandItems = useMemo( @@ -371,7 +374,7 @@ const DemandList: React.FC<{
+
- - {weeksForDateRange.reduce((acc: { year: number; weeks: number }[], monthData) => { - const existingYearIndex = acc.findIndex((data) => data.year === monthData.year); - if (existingYearIndex === -1) { - acc.push({ year: monthData.year as number, weeks: monthData.weeks.length as number }); - } else { - acc[existingYearIndex].weeks += monthData.weeks.length; - } - return acc; - }, []).map((yearData, index) => ( - - ))} + + + - {/* Render headers based on data */} - {weeksForDateRange.map((monthData) => ( - + ))} + {monthsCurrentYear.map((month) => ( + + ))} + {monthsNextYear.map((month) => ( + ))} - - - {weeksForDateRange.reduce((acc, curr) => acc.concat(curr.weeks), []).map((week) => { - // Find the relevant monthData for the current week - const monthData = weeksForDateRange.find((month) => month.weeks.includes(week)); - - if (!monthData) { - // Handle the case where monthData is not found - return null; - } - - return ( - - - ); - })} + )) + )} - {demandcategories?.sort((a, b) => a.id.localeCompare(b.id)).map((category: DemandCategory) => ( - - - {weeksForDateRange.map((month) => ( - month.weeks.map((week: number, index: number) => ( - + + {monthsPreviousYear.concat(monthsCurrentYear, monthsNextYear).map((month) => ( + + {month.weeks.map((week: number) => ( + - )) - ))} - - ))} - + onChange={(event) => { + const inputValue = event.target.value; + const numericValue = inputValue.replace(/\D/g, ''); // Remove non-numeric characters + + setDemandValuesMap((prevDemandValuesMap) => { + const categoryMap = { + ...(prevDemandValuesMap[category.id] || {}), + [month.year]: { + ...(prevDemandValuesMap[category.id]?.[month.year] || {}), + }, + }; + + if (inputValue === '' || numericValue === '0') { + delete categoryMap[month.year]?.[week]; + + if (Object.keys(categoryMap[month.year]).length === 0) { + delete categoryMap[month.year]; + } + } else if (/^[0-9]\d*$/.test(numericValue)) { + categoryMap[month.year][week] = parseInt(numericValue, 10); + } + + return { + ...prevDemandValuesMap, + [category.id]: categoryMap, + }; + }); + }} + /> + ) : ( + + {demandValuesMap[category.id]?.[month.year]?.[week] !== undefined + ? demandValuesMap[category.id]?.[month.year]?.[week] === 0 + ? '0' + : demandValuesMap[category.id]?.[month.year]?.[week] + : ''} + + )} + + ))} + + ))} + + ))}
- {yearData.year} - + {currentYear - 1} + + {currentYear} + + {currentYear + 1} +
- {monthData.name} + {monthsPreviousYear.map((month) => ( + + {month.name} + + {month.name} + + {month.name}
+ {[monthsPreviousYear, monthsCurrentYear, monthsNextYear].reduce((acc, curr) => acc.concat(curr), []).map((month) => + month.weeks.map((week) => ( + - {`Week ${week} - ${getWeekDates(monthData.year, monthData.name, week).startDate} to ${getWeekDates( - monthData.year, - monthData.name, + + {`Week ${week} - ${getWeekDates(month.year, month.name, week).startDate} to ${getWeekDates( + month.year, + month.name, week ).endDate}`} @@ -393,71 +436,72 @@ const WeeklyView: React.FC = ({ demandId }) => { {week}
-
{category.demandCategoryName}
-
- {editMode ? ( - { - const inputValue = event.target.value; - const numericValue = inputValue.replace(/\D/g, ''); // Remove non-numeric characters - - setDemandValuesMap((prevDemandValuesMap) => { - const categoryMap = { - ...(prevDemandValuesMap[category.id] || {}), - [month.year]: { - ...(prevDemandValuesMap[category.id]?.[month.year] || {}), - }, - }; - - if (inputValue === '' || numericValue === '0') { - delete categoryMap[month.year]?.[week]; - - if (Object.keys(categoryMap[month.year]).length === 0) { - delete categoryMap[month.year]; - } - } else if (/^[0-9]\d*$/.test(numericValue)) { - categoryMap[month.year][week] = parseInt(numericValue, 10); + {demandcategories?.sort((a, b) => a.id.localeCompare(b.id)) + .map((category: DemandCategory) => ( +
+
{category.demandCategoryName}
+
+ {editMode ? ( + - ) : ( - - {demandValuesMap[category.id]?.[month.year]?.[week] !== undefined - ? demandValuesMap[category.id]?.[month.year]?.[week] === 0 - ? '0' - : demandValuesMap[category.id]?.[month.year]?.[week] - : ''} - - )} -
diff --git a/demand-capacity-mgmt-frontend/src/components/events/EventsTable.tsx b/demand-capacity-mgmt-frontend/src/components/events/EventsTable.tsx index 9ae408a2..12552502 100644 --- a/demand-capacity-mgmt-frontend/src/components/events/EventsTable.tsx +++ b/demand-capacity-mgmt-frontend/src/components/events/EventsTable.tsx @@ -94,7 +94,6 @@ const EventsTable: React.FC = ({ events, isArchive }) => { useEffect(() => { fetchFavorites(); - // eslint-disable-next-line react-hooks/exhaustive-deps }, [events]); const sortedData = useMemo(() => { diff --git a/demand-capacity-mgmt-frontend/src/components/favorites/FavoritesTableAddressBook.tsx b/demand-capacity-mgmt-frontend/src/components/favorites/FavoritesTableAddressBook.tsx index c5947e80..b8af0551 100644 --- a/demand-capacity-mgmt-frontend/src/components/favorites/FavoritesTableAddressBook.tsx +++ b/demand-capacity-mgmt-frontend/src/components/favorites/FavoritesTableAddressBook.tsx @@ -27,21 +27,25 @@ import { } from 'react-icons/fa'; import { LuStarOff } from "react-icons/lu"; import { FavoritesContext } from "../../contexts/FavoritesContextProvider"; -import { AddressBookFavoriteResponse } from '../../interfaces/favorite_interfaces'; +import {AddressBookFavoriteResponse, CompanyDtoFavoriteResponse} from '../../interfaces/favorite_interfaces'; import Pagination from '../common/Pagination'; - interface FavoriteTableCompaniesProps { favaddressbook: AddressBookFavoriteResponse[]; } const FavoriteTableCompanies: React.FC = ({ favaddressbook }) => { - const [sortField] = useState('changedAt'); - const [sortOrder] = useState<'asc' | 'desc'>('asc'); + const [sortField, setSortField] = useState('changedAt'); + const [sortOrder, setSortOrder] = useState<'asc' | 'desc'>('asc'); const [currentPage, setCurrentPage] = useState(1); const [eventsPerPage, setEventsPerPage] = useState(5); const { deleteFavorite, fetchFavorites } = useContext(FavoritesContext)!; + const handleSort = useCallback((field: string) => { + setSortField(field); + setSortOrder(prevOrder => (prevOrder === 'asc' ? 'desc' : 'asc') as 'asc' | 'desc'); + }, []); + const sortedData = useMemo(() => { const sortedArray = [...favaddressbook].sort((a, b) => { @@ -75,7 +79,7 @@ const FavoriteTableCompanies: React.FC = ({ favaddr console.error('Error Unfavoriting:', error); } }, - [deleteFavorite, fetchFavorites] + [favaddressbook] ); return ( @@ -83,19 +87,19 @@ const FavoriteTableCompanies: React.FC = ({ favaddr
- - - - - - - - + + + + + + + + - {favaddressbook.map((addressBook, index) => ( - - + - - - - - - - ))} + + + + + + + + ))}
Address Book Name Address Book Contact Address Book Email Address Book function
Address Book Name Address Book Contact Address Book Email Address Book function
+ {favaddressbook.map((addressBook, index) => ( +
= ({ favaddr /> - - {addressBook.companyId}}> - - {addressBook.name}{addressBook.contact}{addressBook.email}{addressBook.function}
+ {addressBook.companyId}}> + + {addressBook.name}{addressBook.contact}{addressBook.email}{addressBook.function}
diff --git a/demand-capacity-mgmt-frontend/src/components/favorites/FavoritesTableCapacityGroup.tsx b/demand-capacity-mgmt-frontend/src/components/favorites/FavoritesTableCapacityGroup.tsx index 191a0914..cc1bb564 100644 --- a/demand-capacity-mgmt-frontend/src/components/favorites/FavoritesTableCapacityGroup.tsx +++ b/demand-capacity-mgmt-frontend/src/components/favorites/FavoritesTableCapacityGroup.tsx @@ -37,14 +37,23 @@ interface FavoriteTableMaterialDemandsProps { } const FavoritesTableCapacityGroup: React.FC = ({ favcapacitygroups }) => { - const [sortField] = useState('changedAt'); - const [sortOrder] = useState<'asc' | 'desc'>('asc'); - // eslint-disable-next-line @typescript-eslint/no-unused-vars + const [sortField, setSortField] = useState('changedAt'); + const [sortOrder, setSortOrder] = useState<'asc' | 'desc'>('asc'); const [currentPage, setCurrentPage] = useState(1); const [eventsPerPage, setEventsPerPage] = useState(5); const { deleteFavorite, fetchFavorites } = useContext(FavoritesContext)!; + const handleSort = (field: string) => { + if (sortField === field) { + setSortOrder(prevOrder => (prevOrder === 'asc' ? 'desc' : 'asc') as 'asc' | 'desc'); + } else { + setSortField(field); + setSortOrder('desc'); + } + }; + + const sortedData = useMemo(() => { const sortedArray = [...favcapacitygroups].sort((a, b) => { let comparison = 0; @@ -63,6 +72,9 @@ const FavoritesTableCapacityGroup: React.FC = return sortedArray; }, [favcapacitygroups, sortField, sortOrder]); + const indexOfLastEvent = currentPage * eventsPerPage; + const indexOfFirstEvent = indexOfLastEvent - eventsPerPage; + const currentEvents = sortedData.slice(indexOfFirstEvent, indexOfLastEvent); const totalPagesNum = Math.ceil(sortedData.length / eventsPerPage); const handleUnfavorite = useCallback( @@ -74,7 +86,7 @@ const FavoritesTableCapacityGroup: React.FC = console.error('Error Unfavoriting:', error); } }, - [deleteFavorite, fetchFavorites] + [favcapacitygroups] ); return ( diff --git a/demand-capacity-mgmt-frontend/src/components/favorites/FavoritesTableCompanies.tsx b/demand-capacity-mgmt-frontend/src/components/favorites/FavoritesTableCompanies.tsx index 3847d9a7..9e159f7b 100644 --- a/demand-capacity-mgmt-frontend/src/components/favorites/FavoritesTableCompanies.tsx +++ b/demand-capacity-mgmt-frontend/src/components/favorites/FavoritesTableCompanies.tsx @@ -34,13 +34,18 @@ interface FavoriteTableCompaniesProps { } const FavoriteTableCompanies: React.FC = ({ favcompanies }) => { - const [sortField] = useState('changedAt'); - const [sortOrder] = useState<'asc' | 'desc'>('asc'); + const [sortField, setSortField] = useState('changedAt'); + const [sortOrder, setSortOrder] = useState<'asc' | 'desc'>('asc'); const [currentPage, setCurrentPage] = useState(1); const [eventsPerPage, setEventsPerPage] = useState(5); const { deleteFavorite, fetchFavorites } = useContext(FavoritesContext)!; + const handleSort = useCallback((field: string) => { + setSortField(field); + setSortOrder(prevOrder => (prevOrder === 'asc' ? 'desc' : 'asc') as 'asc' | 'desc'); + }, []); + const sortedData = useMemo(() => { const sortedArray = [...favcompanies].sort((a, b) => { @@ -74,7 +79,7 @@ const FavoriteTableCompanies: React.FC = ({ favcomp console.error('Error Unfavoriting:', error); } }, - [deleteFavorite, fetchFavorites] + [favcompanies] ); return ( diff --git a/demand-capacity-mgmt-frontend/src/components/favorites/FavoritesTableEvents.tsx b/demand-capacity-mgmt-frontend/src/components/favorites/FavoritesTableEvents.tsx index 85bc12ad..291ec14f 100644 --- a/demand-capacity-mgmt-frontend/src/components/favorites/FavoritesTableEvents.tsx +++ b/demand-capacity-mgmt-frontend/src/components/favorites/FavoritesTableEvents.tsx @@ -39,7 +39,6 @@ interface FavoriteTableEventsProps { const FavoritesTableEvents: React.FC = ({ events }) => { const [sortField, setSortField] = useState('changedAt'); const [sortOrder, setSortOrder] = useState<'asc' | 'desc'>('asc'); - // eslint-disable-next-line @typescript-eslint/no-unused-vars const [currentPage, setCurrentPage] = useState(1); const [eventsPerPage, setEventsPerPage] = useState(5); @@ -72,6 +71,9 @@ const FavoritesTableEvents: React.FC = ({ events }) => return sortedArray; }, [events, sortField, sortOrder]); + const indexOfLastEvent = currentPage * eventsPerPage; + const indexOfFirstEvent = indexOfLastEvent - eventsPerPage; + const currentEvents = sortedData.slice(indexOfFirstEvent, indexOfLastEvent); const totalPagesNum = Math.ceil(sortedData.length / eventsPerPage); const handleUnfavorite = useCallback( @@ -83,7 +85,7 @@ const FavoritesTableEvents: React.FC = ({ events }) => console.error('Error Unfavoriting:', error); } }, - [deleteFavorite, fetchFavorites] + [events] ); const generateOverlay = (event: EventFavoriteResponse): React.ReactElement => { diff --git a/demand-capacity-mgmt-frontend/src/components/favorites/FavoritesTableMaterialDemands.tsx b/demand-capacity-mgmt-frontend/src/components/favorites/FavoritesTableMaterialDemands.tsx index 6bb6412f..6d269499 100644 --- a/demand-capacity-mgmt-frontend/src/components/favorites/FavoritesTableMaterialDemands.tsx +++ b/demand-capacity-mgmt-frontend/src/components/favorites/FavoritesTableMaterialDemands.tsx @@ -35,13 +35,19 @@ interface FavoriteTableMaterialDemandsProps { } const FavoriteTableMaterialDemands: React.FC = ({ materialdemands }) => { - const [sortField] = useState('changedAt'); - const [sortOrder] = useState<'asc' | 'desc'>('asc'); + const [sortField, setSortField] = useState('changedAt'); + const [sortOrder, setSortOrder] = useState<'asc' | 'desc'>('asc'); const [currentPage, setCurrentPage] = useState(1); const [eventsPerPage, setEventsPerPage] = useState(5); const { deleteFavorite, fetchFavorites } = useContext(FavoritesContext)!; + const handleSort = useCallback((field: string) => { + setSortField(field); + setSortOrder(prevOrder => (prevOrder === 'asc' ? 'desc' : 'asc') as 'asc' | 'desc'); + }, []); + + const sortedData = useMemo(() => { const sortedArray = [...materialdemands].sort((a, b) => { let comparison = 0; @@ -74,7 +80,7 @@ const FavoriteTableMaterialDemands: React.FC console.error('Error Unfavoriting:', error); } }, - [deleteFavorite, fetchFavorites] + [materialdemands] ); return ( diff --git a/demand-capacity-mgmt-frontend/src/components/pages/AdminPage.tsx b/demand-capacity-mgmt-frontend/src/components/pages/AdminPage.tsx index fab37d53..6dcedbe4 100644 --- a/demand-capacity-mgmt-frontend/src/components/pages/AdminPage.tsx +++ b/demand-capacity-mgmt-frontend/src/components/pages/AdminPage.tsx @@ -24,7 +24,7 @@ import { useEffect, useState } from 'react'; import { Button, Col, Modal, Nav, Row, Tab, TabContent } from 'react-bootstrap'; -import { FaBell, FaClock, FaCogs, FaFingerprint, FaHeartbeat, FaKey, FaQuestion, FaUsers } from 'react-icons/fa'; +import { FaBell, FaClock, FaCogs, FaFingerprint, FaHeartbeat, FaKey, FaQuestion } from 'react-icons/fa'; import { FcEngineering, FcQuestions } from 'react-icons/fc'; import { useNavigate } from 'react-router-dom'; import { useUser } from '../../contexts/UserContext'; @@ -32,7 +32,7 @@ import { LoadingMessage } from '../common/LoadingMessages'; const AdminPage = () => { const { user } = useUser(); - const [loading] = useState(false); + const [loading, setLoading] = useState(false); const [activeTab, setActiveTab] = useState('general'); const [showHelpModal, setShowHelpModal] = useState(false); @@ -42,7 +42,7 @@ const AdminPage = () => { if (user?.role !== 'ADMIN') { navigate('/error'); } - }, [navigate, user]); + }, [user]); if (loading) { return ; // Show loading spinner when data is loading @@ -78,7 +78,7 @@ const AdminPage = () => { setActiveTab('tab2')}> - Users + Tab @@ -119,7 +119,7 @@ const AdminPage = () => {

General Settings

-

User Management

+

Tab 2 Content

Alerts Content

@@ -129,6 +129,7 @@ const AdminPage = () => {

Api Content

+

Scheduled Actions Content

diff --git a/demand-capacity-mgmt-frontend/src/components/pages/CapacityGroupDetailsPage.tsx b/demand-capacity-mgmt-frontend/src/components/pages/CapacityGroupDetailsPage.tsx index 36f88efa..20916867 100644 --- a/demand-capacity-mgmt-frontend/src/components/pages/CapacityGroupDetailsPage.tsx +++ b/demand-capacity-mgmt-frontend/src/components/pages/CapacityGroupDetailsPage.tsx @@ -51,11 +51,6 @@ function CapacityGroupDetailsPage() { const [capacityGroupEvents, setcapacityGroupEvents] = useState([]); const navigate = useNavigate() - - const [startDate, setStartDate] = useState(new Date()); - const [endDate, setEndDate] = useState(new Date()); - - useEffect(() => { if (id) { (async () => { @@ -95,10 +90,7 @@ function CapacityGroupDetailsPage() { } }, [id, getCapacityGroupById, fetchFilteredEvents, navigate, getDemandbyId]); - function updateParentDateRange(start: Date, end: Date) { - setStartDate(start); - setEndDate(end); - } + const memoizedComponent = useMemo(() => { if (!capacityGroup) { @@ -129,18 +121,8 @@ function CapacityGroupDetailsPage() { }} > - -
- -
+ +
@@ -155,7 +137,7 @@ function CapacityGroupDetailsPage() {
); - }, [capacityGroup, capacityGroupEvents, materialDemands, activeTab, startDate, endDate]); + }, [capacityGroup, capacityGroupEvents, materialDemands, activeTab]); return memoizedComponent; } diff --git a/demand-capacity-mgmt-frontend/src/components/pages/CapacityGroupPage.tsx b/demand-capacity-mgmt-frontend/src/components/pages/CapacityGroupPage.tsx index e64b106e..b0e19b2e 100644 --- a/demand-capacity-mgmt-frontend/src/components/pages/CapacityGroupPage.tsx +++ b/demand-capacity-mgmt-frontend/src/components/pages/CapacityGroupPage.tsx @@ -28,16 +28,16 @@ function CapacityGroupPage() { return ( <> -
-
-
-
- - - -
+
+
+
+
+ + +
+
); diff --git a/demand-capacity-mgmt-frontend/src/components/pages/EventsPage.tsx b/demand-capacity-mgmt-frontend/src/components/pages/EventsPage.tsx index bbc00e28..47fdc5dc 100644 --- a/demand-capacity-mgmt-frontend/src/components/pages/EventsPage.tsx +++ b/demand-capacity-mgmt-frontend/src/components/pages/EventsPage.tsx @@ -19,7 +19,7 @@ * SPDX-License-Identifier: Apache-2.0 * ******************************************************************************** */ -import { useContext, useEffect, useRef, useState } from "react"; +import { useContext, useEffect, useState } from "react"; import { Button, Tab, Tabs } from "react-bootstrap"; import { FaFilter, FaRedo } from "react-icons/fa"; import { FcTimeline } from "react-icons/fc"; @@ -93,24 +93,16 @@ function EventsPage() { }; - const fetchFavoritesByTypeRef = useRef(fetchFavoritesByType); - const userInputRef = useRef(userInput); - - useEffect(() => { - userInputRef.current = userInput; - }, [userInput]); - useEffect(() => { const fetchData = async () => { - const fetchFavoritesByType = fetchFavoritesByTypeRef.current; try { setLoading(true); let filteredEvents: EventProp[] = []; - if (userInputRef.current !== '') { + if (userInput !== '') { filteredEvents = await fetchFilteredEvents({ - material_demand_id: userInputRef.current, - capacity_group_id: userInputRef.current, - event: userInputRef.current, + material_demand_id: userInput, + capacity_group_id: userInput, + event: userInput, }); } else { filteredEvents = events; // Show all events if userInput is empty @@ -160,7 +152,7 @@ function EventsPage() { }; fetchData(); - }, [events, fetchFilteredEvents, fetchFavoritesByTypeRef, userInputRef]); + }, [fetchFilteredEvents]); @@ -207,10 +199,8 @@ function EventsPage() {
- {user?.role === 'ADMIN' && (
- {user?.role === 'SUPPLIER' && ( <> diff --git a/demand-capacity-mgmt-frontend/src/contexts/CompanyContextProvider.tsx b/demand-capacity-mgmt-frontend/src/contexts/CompanyContextProvider.tsx index 08cc2883..136ef58f 100644 --- a/demand-capacity-mgmt-frontend/src/contexts/CompanyContextProvider.tsx +++ b/demand-capacity-mgmt-frontend/src/contexts/CompanyContextProvider.tsx @@ -39,7 +39,6 @@ export interface Company { interface CompanyContextData { companies: Company[]; topCompanies: Company[]; - findCompanyByCompanyID: (companyID: string) => Company | undefined; } export const CompanyContext = createContext(undefined); @@ -75,18 +74,12 @@ const CompanyContextProvider: React.FC> = (props) => fetchCompanies(); fetchTopCompanies(); - }, - // eslint-disable-next-line react-hooks/exhaustive-deps - [access_token]); + }, [access_token]); - const findCompanyByCompanyID = (companyID: string | undefined): Company | undefined => { - return companies.find(company => company.id === companyID); - }; - return ( - + {props.children} ); diff --git a/demand-capacity-mgmt-frontend/src/contexts/FavoritesContextProvider.tsx b/demand-capacity-mgmt-frontend/src/contexts/FavoritesContextProvider.tsx index b9d7b7e9..bb16a38d 100644 --- a/demand-capacity-mgmt-frontend/src/contexts/FavoritesContextProvider.tsx +++ b/demand-capacity-mgmt-frontend/src/contexts/FavoritesContextProvider.tsx @@ -85,12 +85,9 @@ const FavoritesContextProvider: React.FC> = (props) } } - useEffect(() => { fetchFavorites(); - }, - // eslint-disable-next-line react-hooks/exhaustive-deps - []); // Note the empty array, this ensures it runs only once. + }, []); // Note the empty array, this ensures it runs only once. const refresh = () => { fetchFavorites(); diff --git a/demand-capacity-mgmt-frontend/src/custom-bootstrap.scss b/demand-capacity-mgmt-frontend/src/custom-bootstrap.scss index e0375cae..1aa7a26c 100644 --- a/demand-capacity-mgmt-frontend/src/custom-bootstrap.scss +++ b/demand-capacity-mgmt-frontend/src/custom-bootstrap.scss @@ -26,14 +26,6 @@ $theme-colors: ( info: $theme1-info, ); -$container-max-widths: ( - sm: 540px, - md: 720px, - lg: 960px, - xl: 1200px, - xxl: 1650px -); - @import '~bootstrap/scss/functions'; @import '~bootstrap/scss/mixins'; @import '~bootstrap/scss/root'; @@ -42,9 +34,6 @@ $container-max-widths: ( @import '~bootstrap/scss/buttons'; @import '~bootstrap/scss/dropdown'; @import '~bootstrap/scss/badge'; -@import '~bootstrap/scss/bootstrap'; - - // Override button text color .btn { diff --git a/demand-capacity-mgmt-frontend/src/index.css b/demand-capacity-mgmt-frontend/src/index.css index 47d22220..78e2b64b 100644 --- a/demand-capacity-mgmt-frontend/src/index.css +++ b/demand-capacity-mgmt-frontend/src/index.css @@ -130,24 +130,6 @@ code { font-size: small; } -/*Data Range Selectors*/ - -.data-range-container { - display: flex; - /* Adjust this height as needed */ -} - -.pop-out-section { - padding: 10px; -} - -.text-muted { - color: #6c757d; - /* Adjust text color */ - font-size: 14px; -} - - /*Sum View Tables*/ .table-container { overflow-x: auto; @@ -200,6 +182,7 @@ code { position: sticky; padding: 0; left: 0; + z-index: 1; } .sticky-header-content { @@ -335,9 +318,6 @@ code { } -.spin-on-hover:hover .button-content { - animation: spin 0.7s ease-in-out infinite; -} @keyframes spin { 0% { @@ -349,17 +329,15 @@ code { } } -.button-content { - display: inline-block; +.spin-on-hover { + animation: spin 1s ease-in-out; transform-origin: center; - /* Ensure the span takes the size of its content */ } -.icon { - /* Any specific styling for your icon */ +.spin-on-hover:hover { + animation: spin 1s ease-in-out infinite; } - /* Admin Panel */ .tabs-column { background-color: #f0f0f0; diff --git a/demand-capacity-mgmt-frontend/src/interfaces/user_interface.tsx b/demand-capacity-mgmt-frontend/src/interfaces/user_interface.tsx index 91d6c158..29f78c11 100644 --- a/demand-capacity-mgmt-frontend/src/interfaces/user_interface.tsx +++ b/demand-capacity-mgmt-frontend/src/interfaces/user_interface.tsx @@ -26,7 +26,6 @@ export interface User { lastName: string; email: string; username: string; - companyID: string; role: string; access_token: string; refresh_token: string; @@ -38,34 +37,14 @@ export function getUserGreeting(user: User | null): string { const hours = currentTime.getHours(); if (user) { if (hours < 12) { - return `Good morning, ${getUserName(user)}`; + return `Good morning, ${user.username}`; } else if (hours < 18) { - return `Good afternoon, ${getUserName(user)}`; + return `Good afternoon, ${user.username}`; } else { - return `Good evening, ${getUserName(user)}`; + return `Good evening, ${user.username}`; } } else { // Handle the case when user is null return 'Welcome!'; } } - -export function getUserName(user: User | null): string { - if (user?.name && user.lastName) { - if (user.lastName.length <= 6) { - return `${user.name.charAt(0).toUpperCase()}${user.name.slice(1)} ${user.lastName.charAt(0).toUpperCase()}${user.lastName.slice(1)}`; - } else { - return `${user.name.charAt(0).toUpperCase()}${user.name.slice(1)}.${user.lastName.charAt(0).toUpperCase()}`; - } - } else if (user?.name) { - return `${user.name.charAt(0).toUpperCase()}${user.name.slice(1)}`; - } else if (user?.username) { - return user.username.replace(/(?:^\w|[A-Z]|\b\w)/g, (letter, index) => index === 0 ? letter.toUpperCase() : letter.toLowerCase()); - } - return ''; -} - - - - - diff --git a/demand-capacity-mgmt-frontend/src/util/WeeksUtils.tsx b/demand-capacity-mgmt-frontend/src/util/WeeksUtils.tsx deleted file mode 100644 index 461cde61..00000000 --- a/demand-capacity-mgmt-frontend/src/util/WeeksUtils.tsx +++ /dev/null @@ -1,114 +0,0 @@ -/* - * ******************************************************************************* - * Copyright (c) 2023 BMW AG - * Copyright (c) 2023 Contributors to the Eclipse Foundation - * - * See the NOTICE file(s) distributed with this work for additional - * information regarding copyright ownership. - * - * This program and the accompanying materials are made available under the - * terms of the Apache License, Version 2.0 which is available at - * https://www.apache.org/licenses/LICENSE-2.0. - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * ******************************************************************************** - */ - -import moment from "moment"; - -export function getISOWeekMonday(year: number, isoWeek: number): moment.Moment { - return moment().year(year).isoWeek(isoWeek).startOf('isoWeek'); -} - -export function getYearOfWeek(date: moment.Moment): number { - return date.add(3, 'days').year(); -} - -export const getWeekNumber = (date: Date) => { - const momentDate = moment(date); - return momentDate.isoWeek(); -}; - -export function getWeeksInMonth(year: number, monthIndex: number, knownNextMonthWeeks?: Set): number[] { - const weeks: Set = new Set(); - - const firstDayOfMonth = moment().year(year).month(monthIndex).startOf('month'); - const lastDayOfMonth = moment().year(year).month(monthIndex).endOf('month'); - // Fetch weeks of the next month if not provided. - if (!knownNextMonthWeeks && monthIndex < 11) { - knownNextMonthWeeks = new Set(getWeeksInMonth(year, monthIndex + 1)); - } - - let currentDay = firstDayOfMonth; - while (currentDay <= lastDayOfMonth) { - const weekNum = currentDay.week(); - const isoWeekYear = getYearOfWeek(currentDay); - - // If the month is January and the week year is the previous year, skip it - if (monthIndex === 0 && isoWeekYear < year) { - currentDay = currentDay.add(1, 'days'); - continue; - } - - // If it's the last week of the month and it's also in the next month, skip it. - if (currentDay.isAfter(moment(new Date(year, monthIndex, 24))) && knownNextMonthWeeks?.has(weekNum)) { - currentDay = currentDay.add(1, 'days'); - continue; - } - - weeks.add(weekNum); - currentDay = currentDay.add(1, 'days'); - } - return Array.from(weeks).sort((a, b) => a - b); -} - - -export const generateWeeksForDateRange = (start: Date, end: Date) => { - const weeks: { name: string; year: number; weeks: number[]; monthIndex: number }[] = []; - let currentDate = moment(start).startOf('isoWeek'); - - while (currentDate.isSameOrBefore(moment(end), 'day')) { - const year = currentDate.year(); - const monthName = currentDate.format('MMMM'); - const weeksInMonth = getWeeksInMonth(year, currentDate.month()); - - const monthIndex = currentDate.month(); - - const existingMonthIndex = weeks.findIndex((monthData) => monthData.year === year && monthData.monthIndex === monthIndex); - - if (existingMonthIndex === -1) { - weeks.push({ - name: monthName, - year, - weeks: weeksInMonth, - monthIndex, - }); - } else { - weeks[existingMonthIndex].weeks.push(...weeksInMonth); - } - - currentDate.add(1, 'month'); - } - - return weeks; -}; - - -// Function to get the beginning and end dates of the week -export const getWeekDates = (year: number, month: string, week: number) => { - const startDate = getISOWeekMonday(year, week); - - const endDate = new Date(startDate.toDate()); - endDate.setDate(endDate.getDate() + 6); // Assuming weeks end on Saturdays - - return { - startDate: startDate.toString(), - endDate: endDate.toDateString(), - }; -}; diff --git a/demand-capacity-mgmt-frontend/yarn.lock b/demand-capacity-mgmt-frontend/yarn.lock index 4e67277b..8e30021c 100644 --- a/demand-capacity-mgmt-frontend/yarn.lock +++ b/demand-capacity-mgmt-frontend/yarn.lock @@ -4535,7 +4535,7 @@ class-utils@^0.3.5: isobject "^3.0.0" static-extend "^0.1.1" -classnames@^2.2.5, classnames@^2.2.6, classnames@^2.3.2: +classnames@^2.2.5, classnames@^2.3.2: version "2.3.2" resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.3.2.tgz#351d813bf0137fcc6a76a16b88208d2560a0d924" integrity sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw== @@ -10572,18 +10572,6 @@ react-bootstrap@^2.8.0: uncontrollable "^7.2.1" warning "^4.0.3" -react-datepicker@^4.23.0: - version "4.23.0" - resolved "https://registry.yarnpkg.com/react-datepicker/-/react-datepicker-4.23.0.tgz#0da50b3815b3350b7df6cf0dbc63e37c6c3079b4" - integrity sha512-w+msqlOZ14v6H1UknTKtZw/dw9naFMgAOspf59eY130gWpvy5dvKj/bgsFICDdvxB7PtKWxDcbGlAqCloY1d2A== - dependencies: - "@popperjs/core" "^2.11.8" - classnames "^2.2.6" - date-fns "^2.30.0" - prop-types "^15.7.2" - react-onclickoutside "^6.13.0" - react-popper "^2.3.0" - react-dev-utils@^12.0.1: version "12.0.1" resolved "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.1.tgz" @@ -10731,12 +10719,7 @@ react-oauth2-auth-code-flow@^1.0.2: react "^16.13.1" react-oauth-flow "^1.2.0" -react-onclickoutside@^6.13.0: - version "6.13.0" - resolved "https://registry.yarnpkg.com/react-onclickoutside/-/react-onclickoutside-6.13.0.tgz#e165ea4e5157f3da94f4376a3ab3e22a565f4ffc" - integrity sha512-ty8So6tcUpIb+ZE+1HAhbLROvAIJYyJe/1vRrrcmW+jLsaM+/powDRqxzo6hSh9CuRZGSL1Q8mvcF5WRD93a0A== - -react-popper@^2.2.5, react-popper@^2.3.0: +react-popper@^2.2.5: version "2.3.0" resolved "https://registry.npmjs.org/react-popper/-/react-popper-2.3.0.tgz" integrity sha512-e1hj8lL3uM+sgSR4Lxzn5h1GxBlpa4CQz0XLF8kx4MDrDRWY0Ena4c97PUeSX9i5W3UAfDP0z0FXCTQkoXUl3Q== diff --git a/demand-capacity-mgmt-specification/src/main/resources/openapi.yml b/demand-capacity-mgmt-specification/src/main/resources/openapi.yml index 8a4f5bcc..01009da4 100644 --- a/demand-capacity-mgmt-specification/src/main/resources/openapi.yml +++ b/demand-capacity-mgmt-specification/src/main/resources/openapi.yml @@ -427,77 +427,6 @@ paths: $ref: '#/components/schemas/LoggingHistoryResponse' 404: description: loggingHistory not found - - /alerts: - post: - tags: - - alerts - summary: configureAlert - operationId: configureAlert - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/AlertRequest' - responses: - 200: - description: General greeting - content: - application/json: - schema: - $ref: '#/components/schemas/AlertResponse' - - get: - tags: - - alerts - summary: get alerts - operationId: getAlerts - responses: - 200: - description: General greeting - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/AlertResponse' - - /triggeredAlerts: - post: - tags: - - alerts - summary: configureTriggeredAlert - operationId: configureTriggeredAlert - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/TriggeredAlertRequest' - responses: - 200: - description: General greeting - content: - application/json: - schema: - $ref: '#/components/schemas/TriggeredAlertResponse' - - get: - tags: - - alerts - summary: get triggered alerts - operationId: getTriggeredAlerts - responses: - 200: - description: General greeting - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/TriggeredAlertResponse' - /statuses: post: tags: @@ -1164,117 +1093,6 @@ components: statusDegradation: type: integer - AlertRequest: - type: object - properties: - alertId: - type: string - alertName: - type: string - monitoredObjects: - type: string - created: - type: string - type: - type: string - threshold: - type: number - description: - type: string - user: - type: string - dedicatedAlerts: - type: array - items: - $ref: '#/components/schemas/DedicatedAlert' - - - TriggeredAlertRequest: - type: object - properties: - alertId: - type: string - alertName: - type: string - monitoredObjects: - type: string - created: - type: string - triggerTimes: - type: number - triggerTimesInThreeMonths: - type: number - type: - type: string - threshold: - type: number - description: - type: string - user: - type: string - - - AlertResponse: - type: object - properties: - alertId: - type: string - alertName: - type: string - monitoredObjects: - type: string - created: - type: string - type: - type: string - threshold: - type: string - description: - type: string - user: - type: string - dedicatedAlerts: - type: array - items: - $ref: '#/components/schemas/DedicatedAlert' - - DedicatedAlert: - type: object - properties: - id: - type: string - objectId: - type: string - type: - type: string - - - - TriggeredAlertResponse: - type: object - properties: - alertId: - type: string - alertName: - type: string - monitoredObjects: - type: string - created: - type: string - triggerTimes: - type: integer - triggerTimesInThreeMonths: - type: integer - type: - type: string - threshold: - type: string - description: - type: string - user: - type: string - - DemandRequestDto: type: object properties: