Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

update(consume data): Fetching policy information from EDC for offer details overlay #83

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/assets/locales/de/main.json
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,8 @@
"title": "Titel",
"assetId": "Asset ID",
"created": "erstellt am",
"sematicVersion": "Sematic Version",
"publisher": "Publisher",
"description": "Beschreibung"
}
},
Expand Down Expand Up @@ -182,6 +184,7 @@
"value": "Wert",
"titleText": "Titel",
"created": "Erstellt am",
"sematicVersion": "Sematic Version",
"dataFormat": "Datenformat",
"description": "Beschreibung",
"publisher": "Anbieter",
Expand All @@ -194,6 +197,9 @@
"point1": "Sie sind befugt, Ihre Organisation in diesem Fall zu vertreten.",
"point2": "Sie haben die Zugangs- und Nutzungspolicies gelesen und verstanden.",
"point3": "Ihre Organisation ist verpflichtet, die Bedingungen der Zugangs- und Nutzungspolicy einzuhalten."
},
"prompt": {
"confirm": "Bitte bestätigen"
}
},
"button": {
Expand Down
6 changes: 6 additions & 0 deletions src/assets/locales/en/main.json
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,8 @@
"title": "Title",
"assetId": "Asset ID",
"created": "Created On",
"sematicVersion": "Sematic Version",
"publisher": "Publisher",
"description": "Description"
}
},
Expand Down Expand Up @@ -185,6 +187,7 @@
"value": "Value",
"titleText": "Title",
"created": "Created on",
"sematicVersion": "Sematic Version",
"dataFormat": "Data format",
"description": "Description",
"publisher": "Publisher",
Expand All @@ -197,6 +200,9 @@
"point1": "You are entitled to represent your organization.",
"point2": "You have read and understood the access/usage policy.",
"point3": "Your organization will be responsible to adhere by the rules stated in the access/usage policy."
},
"prompt": {
"confirm": "Please Confirm"
}
},
"button": {
Expand Down
75 changes: 33 additions & 42 deletions src/components/dialogs/ConfirmTermsDialog.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/********************************************************************************
* Copyright (c) 2021,2022,2023 T-Systems International GmbH
* Copyright (c) 2022,2023 Contributors to the Eclipse Foundation
* Copyright (c) 2022,2024 T-Systems International GmbH
* Copyright (c) 2022,2024 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
Expand All @@ -23,69 +23,60 @@ import { Button, Dialog, DialogActions, DialogContent, DialogHeader, LoadingButt
import React, { useState } from 'react';
import { Trans, useTranslation } from 'react-i18next';

import { setOpenOfferConfirmDialog } from '../../features/consumer/slice';
import { IConsumerDataOffers } from '../../features/consumer/types';
import { useAppDispatch, useAppSelector } from '../../features/store';
import { splitWithFirstOcc } from '../../utils/utils';

interface IntConfirmOffer {
offers?: IConsumerDataOffers[] | [];
offerCount?: number;
provider: string;
}
interface IntDialogProps {
title?: string;
open: boolean;
handleConfirm?: () => void;
handleClose?: (state: boolean) => void;
isProgress?: boolean;
offerObj?: IntConfirmOffer;
}

const ConfirmTermsDialog: React.FC<IntDialogProps> = ({
title = 'Confirm',
open = false,
handleConfirm,
handleClose,
isProgress = false,
children,
offerObj,
}) => {
const ConfirmTermsDialog: React.FC<IntDialogProps> = ({ handleConfirm, isProgress = false, offerObj }) => {
const { openOfferConfirmDialog } = useAppSelector(state => state.consumerSlice);
const [isAgreed, setIsAgreed] = useState(false);
const { t } = useTranslation();

function splitWithFirstOcc(str: string) {
const regX = /:(.*)/s;
return str.split(regX) ? `${str.split(regX)[0]}.` : '-.';
}
const dispatch = useAppDispatch();

return (
<Dialog open={open}>
<DialogHeader closeWithIcon onCloseWithIcon={() => handleClose(false)} title={title} />
<Dialog open={openOfferConfirmDialog}>
<DialogHeader
closeWithIcon
onCloseWithIcon={() => dispatch(setOpenOfferConfirmDialog(false))}
title={t('dialog.prompt.confirm')}
/>
<DialogContent dividers sx={{ py: 3 }}>
{children || (
<>
<Box sx={{ mb: 1 }}>
{offerObj?.offerCount !== 0 && (
<Box>
<Trans i18nKey={'dialog.offerDetails.confirmTermsTitle'} count={offerObj.offerCount} />
</Box>
)}
<>
<Box sx={{ mb: 1 }}>
{offerObj?.offerCount > 1 && (
<Box>
{t('dialog.offerDetails.cofirmTermsSubtitle')}
{offerObj ? <b style={{ margin: '0 5px' }}>{splitWithFirstOcc(offerObj.provider)}</b> : '-.'}
<Trans i18nKey={'dialog.offerDetails.confirmTermsTitle'} count={offerObj.offerCount} />
</Box>
<Box>{t('dialog.offerDetails.confirmHeading')}</Box>
)}
<Box>
{t('dialog.offerDetails.cofirmTermsSubtitle')}
{offerObj ? <b style={{ margin: '0 5px' }}>{splitWithFirstOcc(offerObj.provider)}</b> : '-.'}
</Box>
<Box>(1) {t('dialog.offerDetails.point1')}</Box>
<Box>(2) {t('dialog.offerDetails.point2')}</Box>
<Box>(3) {t('dialog.offerDetails.point3')}</Box>
<FormControlLabel
control={<Checkbox checked={isAgreed} onChange={() => setIsAgreed(!isAgreed)} name="gilad" />}
label={t('content.common.agree')}
/>
</>
)}
<Box>{t('dialog.offerDetails.confirmHeading')}</Box>
</Box>
<Box>(1) {t('dialog.offerDetails.point1')}</Box>
<Box>(2) {t('dialog.offerDetails.point2')}</Box>
<Box>(3) {t('dialog.offerDetails.point3')}</Box>
<FormControlLabel
control={<Checkbox checked={isAgreed} onChange={() => setIsAgreed(!isAgreed)} name="gilad" />}
label={t('content.common.agree')}
/>
</>
</DialogContent>
<DialogActions>
<Button variant="outlined" disabled={isProgress} onClick={() => handleClose(false)}>
<Button variant="contained" disabled={isProgress} onClick={() => dispatch(setOpenOfferConfirmDialog(false))}>
{t('button.cancel')}
</Button>
<LoadingButton
Expand Down
84 changes: 31 additions & 53 deletions src/components/dialogs/OfferDetailsDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,41 +20,50 @@

import { Divider, Grid } from '@mui/material';
import { Button, Dialog, DialogActions, DialogContent, DialogHeader, Typography } from 'cx-portal-shared-components';
import { useState } from 'react';
import { useTranslation } from 'react-i18next';

import Permissions from '../../components/Permissions';
import { setOpenOfferConfirmDialog, setOpenOfferDetailsDialog } from '../../features/consumer/slice';
import { IConsumerDataOffers } from '../../features/consumer/types';
import { useAppDispatch, useAppSelector } from '../../features/store';
import UsagePolicies from './UsagePolicies';

interface IntDialogProps {
open: boolean;
offerObj?: IConsumerDataOffers;
handleConfirm?: (state: boolean) => void;
handleClose?: (state: boolean) => void;
isMultiple?: boolean;
}

const OfferDetailsDialog = ({ open, offerObj, handleConfirm, handleClose, isMultiple }: IntDialogProps) => {
const [offer] = useState(offerObj);
const OfferDetailsDialog = ({ offerObj, isMultiple }: IntDialogProps) => {
const {
title,
created,
description,
sematicVersion,
publisher,
connectorOfferUrl,
policy: { Usage: usagePolicies },
fileContentType,
} = offer;
} = offerObj ?? ({} as IConsumerDataOffers);

const { t } = useTranslation();
const { openOfferDetailsDialog } = useAppSelector(state => state.consumerSlice);

const dispatch = useAppDispatch();

function splitWithFirstOcc(str: string) {
const regX = /:(.*)/s;
return str.split(regX);
}
const renderDetailItem = (label: string, value: string) => (
<Grid item xs={6} sx={{ mb: 1 }}>
<Typography variant="body2">{label}</Typography>
<Typography variant="body2">
<strong>{value || '-'}</strong>
</Typography>
</Grid>
);

return (
<Dialog open={open}>
<DialogHeader closeWithIcon onCloseWithIcon={() => handleClose(false)} title={t('dialog.offerDetails.title')} />
<Dialog open={openOfferDetailsDialog}>
<DialogHeader
closeWithIcon
onCloseWithIcon={() => dispatch(setOpenOfferDetailsDialog(false))}
title={t('dialog.offerDetails.title')}
/>
{isMultiple ? (
<DialogContent dividers sx={{ pt: 3 }}>
<Grid container>
Expand All @@ -69,42 +78,11 @@ const OfferDetailsDialog = ({ open, offerObj, handleConfirm, handleClose, isMult
) : (
<DialogContent dividers>
<Grid container mt={3}>
<Grid item xs={6} sx={{ mb: 1 }}>
<Typography variant="body2">{t('dialog.offerDetails.titleText')}</Typography>
<Typography variant="body2">
<strong>{title || '-'}</strong>
</Typography>
</Grid>
<Grid item xs={6} sx={{ mb: 1 }}>
<Typography variant="body2">{t('dialog.offerDetails.created')}</Typography>
<Typography variant="body2">
<strong>{created || '-'}</strong>
</Typography>
</Grid>
<Grid item xs={6} sx={{ mb: 1 }}>
<Typography variant="body2">{t('dialog.offerDetails.dataFormat')}</Typography>
<Typography variant="body2">
<strong>{fileContentType || '-'}</strong>
</Typography>
</Grid>
<Grid item xs={6} sx={{ mb: 1 }}>
<Typography variant="body2">{t('dialog.offerDetails.description')}</Typography>
<Typography variant="body2">
<strong>{description || '-'}</strong>
</Typography>
</Grid>
<Grid item xs={6} sx={{ mb: 1 }}>
<Typography variant="body2">{t('dialog.offerDetails.publisher')}</Typography>
<Typography variant="body2">
<strong>{splitWithFirstOcc(publisher)[0] || '-'}</strong>
</Typography>
</Grid>
<Grid item xs={6} sx={{ mb: 1 }}>
<Typography variant="body2">{t('dialog.offerDetails.publisherUrl')}</Typography>
<Typography variant="body2">
<strong>{splitWithFirstOcc(publisher)[1] || '-'}</strong>
</Typography>
</Grid>
{renderDetailItem(t('dialog.offerDetails.titleText'), title)}
{renderDetailItem(t('dialog.offerDetails.sematicVersion'), sematicVersion)}
{renderDetailItem(t('dialog.offerDetails.description'), description)}
{renderDetailItem(t('dialog.offerDetails.publisher'), publisher)}
{renderDetailItem(t('dialog.offerDetails.publisherUrl'), connectorOfferUrl)}
</Grid>
<Divider sx={{ m: 1 }} />
<Grid container>
Expand All @@ -118,11 +96,11 @@ const OfferDetailsDialog = ({ open, offerObj, handleConfirm, handleClose, isMult
</DialogContent>
)}
<DialogActions>
<Button variant="outlined" onClick={() => handleClose(false)}>
<Button variant="outlined" onClick={() => dispatch(setOpenOfferDetailsDialog(false))}>
{t('button.close')}
</Button>
<Permissions values={['consumer_establish_contract_agreement']}>
<Button variant="contained" onClick={() => handleConfirm(true)}>
<Button variant="contained" onClick={() => dispatch(setOpenOfferConfirmDialog(true))}>
{t('button.subscribe')}
</Button>
</Permissions>
Expand Down
39 changes: 39 additions & 0 deletions src/features/consumer/apiSlice.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/********************************************************************************
* Copyright (c) 2024 T-Systems International GmbH
* Copyright (c) 2024 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 { setLoadingHandler } from '../../helpers/ApiHelper';
import { apiSlice } from '../app/apiSlice';

export const consumerApiSlice = apiSlice.injectEndpoints({
endpoints: builder => ({
getOfferPolicyDetails: builder.mutation({
query: body => {
return {
url: '/offer-policy-details',
method: 'POST',
body,
};
},
onQueryStarted: setLoadingHandler,
}),
}),
});

export const { useGetOfferPolicyDetailsMutation } = consumerApiSlice;
14 changes: 12 additions & 2 deletions src/features/consumer/slice.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/********************************************************************************
* Copyright (c) 2021,2022,2023 T-Systems International GmbH
* Copyright (c) 2022,2023 Contributors to the Eclipse Foundation
* Copyright (c) 2022,2024 T-Systems International GmbH
* Copyright (c) 2022,2024 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
Expand Down Expand Up @@ -41,6 +41,8 @@ const initialState: IConsumerSlice = {
filterSelectedConnector: {},
contractAgreements: [],
isContractAgreementsLoading: false,
openOfferDetailsDialog: false,
openOfferConfirmDialog: false,
};

export const consumerSlice = createSlice({
Expand Down Expand Up @@ -109,6 +111,12 @@ export const consumerSlice = createSlice({
setIsContractAgreementsLoading: (state, action: PayloadAction<boolean>) => {
state.isContractAgreementsLoading = action.payload;
},
setOpenOfferDetailsDialog: (state, action: PayloadAction<boolean>) => {
state.openOfferDetailsDialog = action.payload;
},
setOpenOfferConfirmDialog: (state, action: PayloadAction<boolean>) => {
state.openOfferConfirmDialog = action.payload;
},
},
});

Expand All @@ -128,5 +136,7 @@ export const {
setFilterSelectedBPN,
setContractAgreements,
setIsContractAgreementsLoading,
setOpenOfferDetailsDialog,
setOpenOfferConfirmDialog,
} = consumerSlice.actions;
export default consumerSlice.reducer;
4 changes: 3 additions & 1 deletion src/features/consumer/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
********************************************************************************/

export interface IUsageControl {
type: string;
typeOfAccess: string;
value?: string;
durationUnit?: string | Record<string, never>;
Expand Down Expand Up @@ -51,6 +50,7 @@ export interface IConsumerDataOffers {
usagePolicies: IUsageControl[];
fileName?: string;
fileContentType?: string;
sematicVersion: string;
}
export interface ILegalEntityName {
value?: string;
Expand Down Expand Up @@ -128,4 +128,6 @@ export interface IConsumerSlice {
filterSelectedConnector: Partial<IntConnectorItem>;
contractAgreements: IContractAgreements[];
isContractAgreementsLoading: boolean;
openOfferDetailsDialog: boolean;
openOfferConfirmDialog: boolean;
}
Loading
Loading