diff --git a/CHANGELOG.md b/CHANGELOG.md index 1ad4a681c..ed1ef2366 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ - Enable credential reset - Serview Overview - Added Sub menu for active services in service overview + - Added Deactivate functionality - Added image to service overview cards - Data Space - Last section background color issue diff --git a/package.json b/package.json index dfaaac7c3..279c5e334 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,7 @@ ] }, "dependencies": { - "@catena-x/portal-shared-components": "^2.0.27", + "@catena-x/portal-shared-components": "^2.0.29", "@emotion/react": "^11.11.1", "@emotion/styled": "^11.11.0", "@hookform/error-message": "^2.0.1", diff --git a/src/assets/locales/de/servicerelease.json b/src/assets/locales/de/servicerelease.json index 5b217db87..0fef0045c 100644 --- a/src/assets/locales/de/servicerelease.json +++ b/src/assets/locales/de/servicerelease.json @@ -16,6 +16,13 @@ "loadmore": "Mehr laden", "documentDeleteSuccess": "Document deleted successfully", "documentDeleteError": "Something went wrong.", + "global": { + "actions": { + "confirm": "Bestätigen", + "cancel": "Stornieren", + "save": "Speichern" + } + }, "stepper": { "marketCard": "Offer Card", "servicePage": "Offer Page Details", @@ -120,6 +127,14 @@ "submenuNotAvailable": "Sub-Menu is not available for not active apps.", "sortOptions": { "deactivate": "Deactivate" + }, + "serviceDeactivate": { + "headerTitle": "Dienst deaktivieren", + "description": "Durch die Deaktivierung des Dienstes wird das Serviceangebot auf dem Catena-X-Marktplatz deaktiviert. Alle derzeit aktiven Abonnements bleiben aktiv und die Kunden sind von der Deaktivierung nicht betroffen. Neue Abonnements sind nicht möglich.", + "checkboxLabel": "Hiermit bestätige ich, dass ich die Geschäftsbedingungen für Business-Services gelesen habe und dass ich die Business-Services meines Unternehmens mit sofortiger Wirkung vom Marktplatz deaktiviere. Ich verstehe, dass es nicht möglich ist, die Deaktivierung selbst rückgängig zu machen.", + "checkboxErrorMsg": "Bitte bestätigen Sie, dass Sie die oben genannten Auswirkungen der Deaktivierung gelesen haben, bevor Sie fortfahren", + "successMsg": "Deaktivierung erfolgreich abgeschlossen", + "errorMsg": "Fehler! Etwas ist schief gelaufen" } }, "servicedetails": { diff --git a/src/assets/locales/en/servicerelease.json b/src/assets/locales/en/servicerelease.json index 901035dda..537528662 100644 --- a/src/assets/locales/en/servicerelease.json +++ b/src/assets/locales/en/servicerelease.json @@ -16,6 +16,13 @@ "loadmore": "Load More", "documentDeleteSuccess": "Document deleted successfully", "documentDeleteError": "Something went wrong.", + "global": { + "actions": { + "confirm": "Confirm", + "cancel": "Cancel", + "save": "Save" + } + }, "stepper": { "marketCard": "Offer Card", "servicePage": "Offer Page Details", @@ -120,6 +127,14 @@ "submenuNotAvailable": "Sub-Menu is not available for not active apps.", "sortOptions": { "deactivate": "Deactivate" + }, + "serviceDeactivate": { + "headerTitle": "Deactivate Service", + "description": "Deactivation of service will deactivate the service offer inside the Catena-X marketplace. Any current active subscription will stay active and customers wont be effected by the deactivation. New subscriptions are not possible.", + "checkboxLabel": "Hereby I confirm that I have read the business service terms and conditions and that I am deactivating my company business services from the marketplace with immediate effect. I understand that it is not possible to self-reverse the deactivation.", + "checkboxErrorMsg": "Please confirm that you have read the deactivation impact above before proceeding", + "successMsg": "Deactivation successfully completed", + "errorMsg": "Error! Something went wrong" } }, "servicedetails": { diff --git a/src/components/pages/AppOverview/AddRolesOverlay.tsx b/src/components/pages/AppOverview/AddRolesOverlay.tsx index d38cbba21..74e268f59 100644 --- a/src/components/pages/AppOverview/AddRolesOverlay.tsx +++ b/src/components/pages/AppOverview/AddRolesOverlay.tsx @@ -157,6 +157,13 @@ const AddRolesOverlay = ({ }) } + const handleClose = () => { + handleOverlayClose() + setRolesPreviews([]) + setRolesDescription([]) + setUploadCSVError(false) + } + return (
{ - handleOverlayClose() - }} + onCloseWithIcon={() => handleClose()} /> - diff --git a/src/components/pages/AppOverview/Deactivate.tsx b/src/components/pages/AppOverview/Deactivate.tsx index 3013a6c1e..d5f8366ac 100644 --- a/src/components/pages/AppOverview/Deactivate.tsx +++ b/src/components/pages/AppOverview/Deactivate.tsx @@ -31,10 +31,10 @@ import { import { useTranslation } from 'react-i18next' import { useLocation, useNavigate, useParams } from 'react-router-dom' import { Box } from '@mui/material' -import { useCallback, useEffect, useState } from 'react' +import { useState } from 'react' import { useDeactivateAppMutation } from 'features/apps/apiSlice' -import { useFetchDocumentByIdMutation } from 'features/appManagement/apiSlice' -import { error } from 'services/NotifyService' +import { getApiBase } from 'services/EnvironmentService' +import { fetchImageWithToken } from 'services/ImageService' export default function Deactivate() { const { t } = useTranslation() @@ -46,36 +46,8 @@ export default function Deactivate() { const items: any = state const app = items?.filter((item: any) => item.id === appId) const [deactivateApp] = useDeactivateAppMutation() - const [deactivateCardImage, setDeactivateCardImage] = useState('') - const [fetchDocumentById] = useFetchDocumentByIdMutation() const leadImageId = app?.[0]?.leadPictureId - const fetchImage = useCallback( - async (documentId: string, docType: string) => { - try { - const response = await fetchDocumentById({ - appId: appId ?? '', - documentId, - }) - if (response && 'data' in response) { - const file = response?.data?.data - if (docType === 'APP_LEADIMAGE') { - return setDeactivateCardImage(URL.createObjectURL(file)) - } - } - } catch (err) { - error('ERROR WHILE FETCHING IMAGE', '', err as object) - } - }, - [fetchDocumentById, appId] - ) - - useEffect(() => { - if (leadImageId) { - fetchImage(leadImageId, 'APP_LEADIMAGE') - } - }, [fetchImage, leadImageId]) - const handleSaveClick = async () => { setIsLoading(true) await deactivateApp(app[0].id) @@ -115,16 +87,19 @@ export default function Deactivate() { diff --git a/src/components/pages/ServiceReleaseProcess/components/ServiceDeactivate.tsx b/src/components/pages/ServiceReleaseProcess/components/ServiceDeactivate.tsx new file mode 100644 index 000000000..d5312eb38 --- /dev/null +++ b/src/components/pages/ServiceReleaseProcess/components/ServiceDeactivate.tsx @@ -0,0 +1,167 @@ +/******************************************************************************** + * Copyright (c) 2021, 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 { PageBreadcrumb } from 'components/shared/frame/PageBreadcrumb/PageBreadcrumb' +import { + Typography, + PageHeader, + Card, + Checkbox, + Button, + Tooltips, + LoadingButton, +} from '@catena-x/portal-shared-components' +import { useTranslation } from 'react-i18next' +import { useLocation, useNavigate, useParams } from 'react-router-dom' +import { Box } from '@mui/material' +import { useState } from 'react' +import { + ServiceDeactivateEnum, + useDeactivateServiceMutation, +} from 'features/serviceManagement/apiSlice' +import { PAGES } from 'types/Constants' +import { getApiBase } from 'services/EnvironmentService' +import { fetchImageWithToken } from 'services/ImageService' + +export default function ServiceDeactivate() { + const { t } = useTranslation('servicerelease') + const navigate = useNavigate() + const serviceId = useParams().serviceId + const [checked, setChecked] = useState(false) + const { state } = useLocation() + const [isLoading, setIsLoading] = useState(false) + const items: any = state + const service = items?.filter((item: any) => item.id === serviceId) + const [deactivateService] = useDeactivateServiceMutation() + const leadImageId = service?.[0]?.leadPictureId + + const handleSaveClick = async () => { + setIsLoading(true) + await deactivateService(service[0].id) + .unwrap() + .then(() => + navigate(`/${PAGES.SERVICEOVERVIEW}`, { + state: ServiceDeactivateEnum.SERVICE_DEACTIVATE_SUCCESS, + }) + ) + .catch((error) => + navigate(`/${PAGES.SERVICEOVERVIEW}`, { + state: ServiceDeactivateEnum.SERVICE_DEACTIVATE_ERROR, + }) + ) + } + + return ( +
+ + + +
+ + {service?.[0]?.title} + + + {t('serviceoverview.serviceDeactivate.headerTitle')} + + + {t('serviceoverview.serviceDeactivate.description')} + +
+
+
+ {service && ( + + + + + + + e.target.checked ? setChecked(true) : setChecked(false) + } + key={service[0].id} + className="checkbox-input" + /> + + + )} +
+
+
+
+ + + + {isLoading ? ( + {}} + label={`${t('global.actions.confirm')}`} + /> + ) : ( + + )} + + } + /> + +
+
+ ) +} diff --git a/src/components/pages/ServiceReleaseProcess/components/ServiceListOverview.tsx b/src/components/pages/ServiceReleaseProcess/components/ServiceListOverview.tsx index 206bbe1cf..cf29e689a 100644 --- a/src/components/pages/ServiceReleaseProcess/components/ServiceListOverview.tsx +++ b/src/components/pages/ServiceReleaseProcess/components/ServiceListOverview.tsx @@ -28,6 +28,7 @@ import { Cards, LoadMoreButton, CardItems, + PageSnackbar, ErrorBar, } from '@catena-x/portal-shared-components' import { serviceToCard } from 'features/apps/mapper' @@ -36,16 +37,18 @@ import { ProvidedServices, ProvidedServiceStatusEnum, ProvidedServiceType, + ServiceDeactivateEnum, StatusIdEnum, useFetchProvidedServicesQuery, } from 'features/serviceManagement/apiSlice' import NoItems from 'components/pages/NoItems' -import { useNavigate } from 'react-router-dom' +import { useLocation, useNavigate } from 'react-router-dom' import { PAGES } from 'types/Constants' import debounce from 'lodash.debounce' import { setServiceId } from 'features/serviceManagement/actions' import { useDispatch } from 'react-redux' import { setServiceReleaseActiveStep } from 'features/serviceManagement/slice' +import { SuccessErrorType } from 'features/admin/appuserApiSlice' import { Box, useTheme, CircularProgress } from '@mui/material' enum ServiceSubMenuItems { @@ -66,6 +69,7 @@ export default function ServiceListOverview() { statusFilter: '', }, }) + const { state } = useLocation() const { data, isFetching, isSuccess, refetch } = useFetchProvidedServicesQuery(argsData) const dispatch = useDispatch() @@ -79,6 +83,10 @@ export default function ServiceListOverview() { }, ] + useEffect(() => { + state === ServiceDeactivateEnum.SERVICE_DEACTIVATE_SUCCESS && refetch() + }, [state, refetch]) + useEffect(() => { dispatch(setServiceReleaseActiveStep()) if (data && data.content) @@ -248,7 +256,7 @@ export default function ServiceListOverview() { submenuOptions={submenuOptions} submenuClick={(sortMenu: string, id: string | undefined) => { sortMenu === ServiceSubMenuItems.DEACTIVATE && - navigate(`/${PAGES.DEACTIVATE}/${id}`, { + navigate(`/${PAGES.SERVICEDEACTIVATE}/${id}`, { state: items, }) return undefined @@ -271,6 +279,25 @@ export default function ServiceListOverview() { )}
+ + {state && ( + {}} + severity={ + state === ServiceDeactivateEnum.SERVICE_DEACTIVATE_SUCCESS + ? SuccessErrorType.SUCCESS + : SuccessErrorType.ERROR + } + description={ + state === ServiceDeactivateEnum.SERVICE_DEACTIVATE_SUCCESS + ? t('serviceoverview.serviceDeactivate.successMsg') + : t('serviceoverview.serviceDeactivate.errorMsg') + } + showIcon={true} + autoClose={true} + /> + )} ) } diff --git a/src/components/pages/Test/index.image.tsx b/src/components/pages/Test/index.image.tsx index ea712bb92..34db77615 100644 --- a/src/components/pages/Test/index.image.tsx +++ b/src/components/pages/Test/index.image.tsx @@ -44,8 +44,6 @@ export default function ImageTest() { }) }, []) - console.log(data) - return ( <>
diff --git a/src/features/serviceManagement/apiSlice.ts b/src/features/serviceManagement/apiSlice.ts index 3db30ed72..bd8cc5a60 100644 --- a/src/features/serviceManagement/apiSlice.ts +++ b/src/features/serviceManagement/apiSlice.ts @@ -34,6 +34,11 @@ export enum ServiceTypeIdsEnum { DATASPACE_SERVICE = 'DATASPACE_SERVICE', } +export enum ServiceDeactivateEnum { + SERVICE_DEACTIVATE_SUCCESS = 'service-deactivate-success', + SERVICE_DEACTIVATE_ERROR = 'service-deactivate-error', +} + export type CreateServiceStep1Item = { title?: string price?: string | null @@ -323,6 +328,12 @@ export const apiSlice = createApi({ body: data, }), }), + deactivateService: builder.mutation({ + query: (serviceId) => ({ + url: `/api/service/ServiceChange/${serviceId}/deactivateService`, + method: 'PUT', + }), + }), }), }) @@ -345,4 +356,5 @@ export const { useFetchServiceTechnicalUserProfilesQuery, useSaveServiceTechnicalUserProfilesMutation, useActivateSubscriptionMutation, + useDeactivateServiceMutation, } = apiSlice diff --git a/src/types/Config.tsx b/src/types/Config.tsx index 8c8f8d1a1..6571924e9 100644 --- a/src/types/Config.tsx +++ b/src/types/Config.tsx @@ -80,6 +80,7 @@ import ChangeDescription from 'components/pages/AppOverview/ChangeDescription' import DataSpace from 'components/pages/DataSpace' import AdminCredential from 'components/pages/AdminCredential' import AddRoles from 'components/pages/AppOverview/AddRoles' +import ServiceDeactivate from 'components/pages/ServiceReleaseProcess/components/ServiceDeactivate' import ChangeDocuments from 'components/pages/AppOverview/ChangeDocuments' /** @@ -426,6 +427,19 @@ export const ALL_PAGES: IPage[] = [ ), }, + { + name: PAGES.SERVICEDEACTIVATE, + isRoute: true, + element: ( + } + > + } /> + + ), + }, { name: PAGES.CHANGE_IMAGE, isRoute: true, diff --git a/src/types/Constants.ts b/src/types/Constants.ts index 8d705186e..d443df1cc 100644 --- a/src/types/Constants.ts +++ b/src/types/Constants.ts @@ -86,6 +86,7 @@ export enum PAGES { USE_CASE_TRACABILITY = 'usecasetraceablity', SERVICE_MANAGEMENT = 'servicemanagement', SERVICEOVERVIEW = 'serviceoverview', + SERVICEDEACTIVATE = 'servicedeactivate', SERVICERELEASEPROCESS = 'servicereleaseprocess', SERVICEADMINBOARD = 'serviceadminboard', SERVICEADMINBOARD_DETAIL = 'serviceadminboarddetail',