Skip to content

Commit

Permalink
Merge pull request #67 from catenax-ng/update/usecase_selection
Browse files Browse the repository at this point in the history
[feat|sde-frontend-update]: Use case selection improved
  • Loading branch information
almadigabor authored Feb 16, 2024
2 parents 26e02a9 + ce9125d commit 7614771
Show file tree
Hide file tree
Showing 7 changed files with 112 additions and 139 deletions.
16 changes: 7 additions & 9 deletions src/components/layouts/AppLayout.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) 2021,2022 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 @@ -18,22 +18,20 @@
* SPDX-License-Identifier: Apache-2.0
********************************************************************************/
import { Box } from '@mui/material';
import { useEffect } from 'react';

import { fetchUserPermissions } from '../../features/app/actions';
import { useGetPermissionsQuery, useGetUseCasesQuery } from '../../features/app/apiSlice';
import { setLoggedInUser } from '../../features/app/slice';
import { useAppDispatch } from '../../features/store';
import Nav from '../Nav';
import Sidebar from '../sidebar';

// eslint-disable-next-line @typescript-eslint/no-explicit-any
export default function AppLayout(props: any) {
useGetUseCasesQuery({});
useGetPermissionsQuery({});

const dispatch = useAppDispatch();
useEffect(() => {
dispatch(fetchUserPermissions());
dispatch(setLoggedInUser(props.loggedUser));
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
dispatch(setLoggedInUser(props.loggedUser));

return (
<Box sx={{ my: 0, mx: 'auto', overflowY: 'auto', overflowX: 'hidden', height: '100vh' }}>
Expand Down
42 changes: 0 additions & 42 deletions src/features/app/actions.ts

This file was deleted.

44 changes: 40 additions & 4 deletions src/features/app/apiSlice.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
/********************************************************************************
* 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 @@ -21,7 +21,8 @@ import { BaseQueryFn, createApi, FetchArgs, fetchBaseQuery, FetchBaseQueryError

import { apiBaseQuery } from '../../services/RequestService';
import { setSnackbarMessage } from '../notifiication/slice';
import { IExtraOptions } from './types';
import { setPageLoading, setPermissions, setUseCases } from './slice';
import { IExtraOptions, UseCaseSelectionModel } from './types';

const baseQuery = fetchBaseQuery(apiBaseQuery());
const baseQueryInterceptor: BaseQueryFn<string | FetchArgs, unknown, FetchBaseQueryError, IExtraOptions> = async (
Expand Down Expand Up @@ -54,6 +55,41 @@ const baseQueryInterceptor: BaseQueryFn<string | FetchArgs, unknown, FetchBaseQu
export const apiSlice = createApi({
reducerPath: 'api',
baseQuery: baseQueryInterceptor,
endpoints: () => ({}),
endpoints: builder => ({
getUseCases: builder.query({
query: () => {
return {
url: '/usecases',
};
},
async onQueryStarted(_, { dispatch, queryFulfilled }) {
try {
dispatch(setPageLoading(true));
const data = UseCaseSelectionModel.create((await queryFulfilled).data);
dispatch(setUseCases(data));
} finally {
dispatch(setPageLoading(false));
}
},
}),
getPermissions: builder.query({
query: () => {
return {
url: '/user/role/permissions',
};
},
async onQueryStarted(_, { dispatch, queryFulfilled }) {
try {
dispatch(setPageLoading(true));
const data = (await queryFulfilled).data;
dispatch(setPermissions(data));
} finally {
dispatch(setPageLoading(false));
}
},
}),
}),
tagTypes: ['UploadHistory', 'DeleteContract'],
});

export const { useGetUseCasesQuery, useGetPermissionsQuery } = apiSlice;
32 changes: 10 additions & 22 deletions src/features/app/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 All @@ -19,8 +19,8 @@
********************************************************************************/

import { createSlice, PayloadAction } from '@reduxjs/toolkit';
import { filter } from 'lodash';

import { fetchUseCases, fetchUserPermissions } from './actions';
import { IAppSlice, IUser } from './types';

const initialState: IAppSlice = {
Expand Down Expand Up @@ -53,27 +53,15 @@ export const appSlice = createSlice({
setSidebarExpanded: state => {
state.sidebarExpanded = !state.sidebarExpanded;
},
setSelectedUseCases: (state, action: PayloadAction<string[]>) => {
state.selectedUseCases = action.payload;
setUseCases: (state, { payload }) => {
state.useCases = payload;
state.selectedUseCases = filter(payload, 'checked').map(e => e.id);
},
setPermissions: (state, { payload }) => {
state.permissions = payload;
},
},
extraReducers: builder => {
builder.addCase(fetchUserPermissions.pending, state => {
state.pageLoading = true;
});
builder.addCase(fetchUserPermissions.fulfilled, (state, action) => {
state.permissions = action.payload;
state.pageLoading = false;
});
builder.addCase(fetchUseCases.pending, state => {
state.pageLoading = true;
});
builder.addCase(fetchUseCases.fulfilled, (state, action) => {
state.useCases = action.payload;
state.pageLoading = false;
});
},
});

export const { setPageLoading, setLoggedInUser, setSelectedUseCases, setSidebarExpanded } = appSlice.actions;
export const { setPageLoading, setLoggedInUser, setUseCases, setPermissions, setSidebarExpanded } = appSlice.actions;
export default appSlice.reducer;
13 changes: 11 additions & 2 deletions src/features/app/types.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,9 +41,18 @@ export interface IAppSlice {
export interface IUseCase {
id: string;
title: string;
checked?: boolean;
}
export interface IExtraOptions {
showNotification?: boolean;
message?: string;
type?: IAlertColors;
}

export class UseCaseSelectionModel {
static create(useCase: IUseCase[]) {
return useCase.map(item => {
return { id: item.id, title: item.title, checked: false };
});
}
}
80 changes: 38 additions & 42 deletions src/pages/Home.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 @@ -21,49 +21,41 @@
import '../styles/home.scss';

import ArrowForwardIcon from '@mui/icons-material/ArrowForward';
import { Avatar, Box, FormControl, Grid, Stack } from '@mui/material';
import { Button, Tab, TabPanel, Tabs, Typography } from 'cx-portal-shared-components';
import { SyntheticEvent, useCallback, useEffect, useState } from 'react';
import CheckCircleIcon from '@mui/icons-material/CheckCircle';
import { Avatar, Box, FormControlLabel, Grid } from '@mui/material';
import { Button, Checkbox, Tab, TabPanel, Tabs, Typography } from 'cx-portal-shared-components';
import { SyntheticEvent, useCallback, useState } from 'react';
import { useTranslation } from 'react-i18next';

import legalNoticeContent from '../assets/about/legal-notice.json';
import { DataExchangeStepper } from '../components/DataExchangeStepper';
import { fetchUseCases } from '../features/app/actions';
import { setSelectedUseCases } from '../features/app/slice';
import { setUseCases } from '../features/app/slice';
import { IUseCase } from '../features/app/types';
import { clearRows, setSelectedSubmodel } from '../features/provider/submodels/slice';
import { ISubmodelList } from '../features/provider/submodels/types';
import { removeSelectedFiles, setUploadStatus } from '../features/provider/upload/slice';
import { useAppDispatch, useAppSelector } from '../features/store';
import { consumeDataSteps, provideDataSteps } from '../models/Home';
import { USER_GUIDE_URL } from '../utils/constants';
import { openInNewTab } from '../utils/utils';

export default function Home() {
const [activeTab, setActiveTab] = useState(0);
const { loggedInUser, useCases, selectedUseCases } = useAppSelector(state => state.appSlice);
const { loggedInUser, useCases } = useAppSelector(state => state.appSlice);
const dispatch = useAppDispatch();
const { t } = useTranslation();

useEffect(() => {
dispatch(fetchUseCases());
}, [dispatch]);

const handleUseCaseChange = useCallback(
(event: React.ChangeEvent<HTMLInputElement>) => {
(usecase: IUseCase) => {
// Clearing all the ongoing uploads
dispatch(setSelectedSubmodel({} as ISubmodelList));
dispatch(setUploadStatus(true));
dispatch(clearRows());
dispatch(removeSelectedFiles());

const { value, checked } = event.target;
if (checked) {
dispatch(setSelectedUseCases([...selectedUseCases, value]));
} else {
dispatch(setSelectedUseCases(selectedUseCases.filter((e: string) => e !== value)));
}
const res = useCases.map(item => (item.id === usecase.id ? { ...item, checked: !item.checked } : item));
dispatch(setUseCases(res));
},
[dispatch, selectedUseCases],
[dispatch, useCases],
);

const handleTabChange = (_event: SyntheticEvent, newValue: number) => {
Expand All @@ -85,7 +77,7 @@ export default function Home() {
<Button
variant="text"
size="medium"
onClick={() => openInNewTab(legalNoticeContent.readmePath)}
onClick={() => openInNewTab(USER_GUIDE_URL)}
endIcon={<ArrowForwardIcon />}
sx={{
p: 0,
Expand All @@ -102,7 +94,7 @@ export default function Home() {
</Grid>
<Grid item xs={6}>
<Box>
<img src="images/sde.png" width={'100%'} />
<img src="images/sde.png" width={'100%'} alt="sde" />
</Box>
</Grid>
<Grid item xs={12}>
Expand All @@ -112,28 +104,32 @@ export default function Home() {
<Typography variant="body1" maxWidth={1000}>
{t('content.home.selectUsecasesSubheader')}
</Typography>
<FormControl component="fieldset" variant="standard">
<Stack direction="row" spacing={1} mt={3} sx={{ flexWrap: 'wrap', gap: 1 }}>
{useCases && (
<Grid container spacing={3} mt={0}>
{useCases.map((item: IUseCase) => (
<Box className="usecase-tile" key={item.id}>
<input
type="checkbox"
name={item.title}
value={item.id}
id={item.id}
onChange={handleUseCaseChange}
checked={selectedUseCases.includes(item.id)}
<Grid item key={item.id}>
<FormControlLabel
control={
<Checkbox
checked={item.checked}
onChange={() => handleUseCaseChange(item)}
sx={{ '&.MuiCheckbox-root': { display: 'none' } }}
/>
}
label={
<Box className="usecase-tile-content">
{item.checked && (
<CheckCircleIcon color="primary" sx={{ position: 'absolute', top: 15, right: 15 }} />
)}
<Avatar src={`images/${item.id}.png`} sx={{ width: 60, height: 60 }} />
<Typography variant="subtitle1">{item.title}</Typography>
</Box>
}
/>
<label className="usecase-tile-content" htmlFor={item.id}>
<Stack className="usecase-tile-content-wrapper" spacing={2}>
<Avatar src={`images/${item.id}.png`} sx={{ width: 60, height: 60 }} />
<Typography variant="subtitle1">{item.title}</Typography>
</Stack>
</label>
</Box>
</Grid>
))}
</Stack>
</FormControl>
</Grid>
)}
</Grid>
<Grid item xs={12} my={5}>
<Typography variant="h4" mb={1}>
Expand Down
Loading

0 comments on commit 7614771

Please sign in to comment.