Skip to content
This repository has been archived by the owner on May 16, 2023. It is now read-only.

Handling failed post delete service calls #79

Open
wants to merge 67 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
461fa0e
1. introducing error handling in post/delete calls related to Assignm…
Oct 8, 2020
c9e11b1
learncontent- error handling for post and delete calls
maleekha Oct 9, 2020
54a8c0e
using the promise object properly now
maleekha Oct 9, 2020
b00be7a
Error handling for publishStatusChange call
maleekha Oct 9, 2020
969ddd9
error handling for AssignmentLinks - fixes
Oct 9, 2020
4661667
improved publish button action
Oct 9, 2020
dbe145a
removed console.log statement, extra spaces
Oct 9, 2020
5574421
Changing serviceCallInProgress from boolean to number
maleekha Oct 11, 2020
f5ece3b
1. error handling for Assignment APIs
Oct 12, 2020
2f8f3ce
Error handling for get and post calls; added appropraiate error messa…
maleekha Oct 12, 2020
cd55741
Assignment store synced state on publish; warning text
maleekha Oct 12, 2020
e2930dd
Error message for publish status change when the user is unauthorized
maleekha Oct 12, 2020
b9e974c
Updating warning text styles; making assignment link store on-publish…
maleekha Oct 12, 2020
e95f637
Merge branch 'main' into handling-failed-POST-DELETE-service-calls
maleekha Oct 12, 2020
c7dfca9
Updating LearnStore from main
maleekha Oct 12, 2020
f2f3be8
Updating MicrosoftLearnStore -- fixing diff from main to show properl…
maleekha Oct 13, 2020
b730715
Assignment updating spinner; renamed failure message bar; code refact…
maleekha Oct 13, 2020
65cbe8a
error handling for GET call in Links and Learn Content stores
Oct 13, 2020
f70068d
Refactoring learn store
maleekha Oct 13, 2020
ef66b22
Revert "Refactoring learn store"
maleekha Oct 13, 2020
56d1ffe
Modifying student-view to show synced assignment content; updating er…
maleekha Oct 13, 2020
d0b1ca6
Updating student view description and deadline
maleekha Oct 13, 2020
26adb49
removing error handling for getCatalog -- TODO: To be done on server …
maleekha Oct 13, 2020
b2f8f10
Updating Learnstore error handling- including waiting mechanism based…
maleekha Oct 14, 2020
dd73a01
build fix
maleekha Oct 14, 2020
3145cd8
Updating Microsoft Learn Content-item toggle logic to use observables
maleekha Oct 15, 2020
776ad42
Code-refactoring; added call-status
maleekha Oct 15, 2020
9b61ddc
Updated LearnStore to handle error case of clear all call
maleekha Oct 15, 2020
993e0c2
Refactoring LearnStore; removing removeItem-action, as it can be done…
maleekha Oct 16, 2020
65c7dd5
LearnStore code refactoring
maleekha Oct 16, 2020
8b104c5
Disable link action area while an add/update call is in progress for …
maleekha Oct 16, 2020
20bd6ce
Updating AssignmentLinkstore to reflect changes on publish properly; …
maleekha Oct 16, 2020
bc2676a
removing unnecessary comments
maleekha Oct 16, 2020
77365e9
Code refactoring; assignment store updates
maleekha Oct 16, 2020
577c352
removing unused imports
maleekha Oct 16, 2020
408bde7
Removing "isSynced" observables as they are not needed.
maleekha Oct 16, 2020
12efe24
Adding license header to new files
maleekha Oct 16, 2020
5e470a7
Updated assignment store update from synced state on publish; publish…
maleekha Oct 19, 2020
1112f0b
Update AssignmentLinks.store.ts
Oct 19, 2020
8251fdf
Fix for unnecessary links, learn-content, me calls on assignment update
maleekha Oct 19, 2020
3f2808e
Merge branch 'handling-failed-POST-DELETE-service-calls' of https://g…
maleekha Oct 19, 2020
3606311
minor syntax uodates
Oct 19, 2020
478d79e
Soft fade-in fade-out for assignmentUpdateFailureMessageBar
maleekha Oct 20, 2020
fc1f826
Updating links and learn-store to have computed variables storing the…
maleekha Oct 20, 2020
9ff5066
Update AssignmentUpdateFailureMessageBar.tsx
Oct 20, 2020
76c3b08
Update MainLayout.tsx
Oct 20, 2020
fbf4c52
Update AssignmentUpdateFailureMessageBar.tsx
Oct 20, 2020
6e464fb
updating AssignmentFailMessageBar to display store-specific messages.
maleekha Oct 20, 2020
97ddea1
minor updates to make code look cleaner
Oct 20, 2020
5d64de4
Update AssignmentUpdateFailureMessageBar.tsx
Oct 20, 2020
71790b3
Merge branch 'main' into handling-failed-POST-DELETE-service-calls
nehalilani Oct 20, 2020
4931a47
Updated store-specific message in the assignmentUpdateFailureMessageBar
maleekha Oct 20, 2020
53617d5
Fixing issues in Assignment and Links store
maleekha Oct 21, 2020
6c8e6ed
Update AssignmentLinks.store.ts
maleekha Oct 21, 2020
6207f21
LinksStore update
Oct 21, 2020
9d47ea2
Fixing learn store clear-all issue
maleekha Oct 21, 2020
2f6b74f
Removing unnecessary comments
maleekha Oct 21, 2020
abba9d8
Update Assignment.store.ts
Oct 21, 2020
643b26c
Update Assignment.store.ts
Oct 21, 2020
e7ede1a
Update Assignment.store.ts
Oct 21, 2020
cad7743
Update Assignment.store.ts
Oct 21, 2020
f3ce995
Update Assignment.store.ts
Oct 22, 2020
b16c568
updated error messages
Oct 22, 2020
17cbbfc
Update Assignment.store.ts
Oct 22, 2020
736dc4a
Update Assignment.store.ts
maleekha Oct 22, 2020
e1a119f
Temporarily hardcoding the linkid and contentuid in service calls. Wi…
maleekha Oct 22, 2020
601fc77
Fixed issues in learn-store; modified the disable condition for clear…
maleekha Oct 27, 2020
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
92 changes: 92 additions & 0 deletions client/src/Core/Components/AssignmentUpdateFailureMessageBar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*--------------------------------------------------------------------------------------------*/

import { AnimationClassNames, IMessageBarStyles, MessageBar, MessageBarType, styled } from '@fluentui/react';
import { useObserver } from 'mobx-react-lite';
import React from 'react';
import { useStore } from '../../Stores/Core';
import { ServiceError } from '../Utils/Axios/ServiceError';
import { themedClassNames } from '../Utils/FluentUI';
import { IStylesOnly, IThemeOnlyProps } from '../Utils/FluentUI/typings.fluent-ui';

type Store = 'assignment' | 'links' | 'learn-content';

const getErrorMessage = (stores: Store[], error: ServiceError | null) => {
if (error === null) {
return undefined;
}

const getStoreSpecificMessage = (store: Store) => {
switch (store) {
case 'links': return 'links';
case 'learn-content': return 'Microsoft Learn content';
case 'assignment': return 'description and deadline';
}
};

let storesWithError = stores.map(store => getStoreSpecificMessage(store)).join(', ');
let message = `Sorry! An error was encountered, and we could not sync the assignment's ${storesWithError} properly. Head to the Preview page to see the saved state of the assignment. `;

switch (error) {
case 'unauthorized':
return message + 'It seems like you do not have sufficient permissions to perform this action.';
case 'not found':
return message + 'We could not find what you were looking for. Please contact the server administrator or a teacher.'
case 'bad request':
return message + 'The server could not process your request.';
case 'internal error':
case 'other':
return message + 'The server encountered an internal error and was unable to complete your request. Please contact the server administrator.'
}
};

const AssignmentUpdateFailureMessageBarInner = ({ styles }: IStylesOnly<IMessageBarStyles>): JSX.Element | null => {
const assignmentStore = useStore('assignmentStore');
const assignmentLinksStore = useStore('assignmentLinksStore');
const learnStore = useStore('microsoftLearnStore');
const classes = themedClassNames(styles);

return useObserver(() => {
const learnStoreError = learnStore.itemsInErrorState.length !== 0 && !learnStore.serviceCallsInProgress && learnStore.hasServiceError ? learnStore.hasServiceError : null;
const linkStoreError = !assignmentLinksStore.isSynced && assignmentLinksStore.serviceCallInProgress === 0 && assignmentLinksStore.hasServiceError ? assignmentLinksStore.hasServiceError : null;
const assignmentError = !assignmentStore.isSynced && assignmentStore.serviceCallInProgress === 0 && assignmentStore.hasServiceError ? assignmentStore.hasServiceError : null;

let errorMessageMap: Map<ServiceError, Store[]> = new Map<ServiceError, Store[]>();

const getExistingStoresErrorMap = (err: ServiceError): Store[] => errorMessageMap.get(err) || [];

if (linkStoreError) {
errorMessageMap.set(linkStoreError, [...getExistingStoresErrorMap(linkStoreError), 'links']);
}
if (learnStoreError) {
errorMessageMap.set(learnStoreError, [...getExistingStoresErrorMap(learnStoreError), 'learn-content']);
}
if (assignmentError) {
errorMessageMap.set(assignmentError, [...getExistingStoresErrorMap(assignmentError), 'assignment']);
}

if (learnStoreError || linkStoreError || assignmentError) {
return (
<>
{[...errorMessageMap].map(([serviceError, stores]) => {
return (
<MessageBar messageBarType={MessageBarType.warning} isMultiline={true} className={classes.root}>
{getErrorMessage(stores, serviceError)}
</MessageBar>
);
})}
</>
);
} else {
return null;
}
});
};

const assignmentUpdateFailureMessageBarStyles = ({ theme }: IThemeOnlyProps): Partial<IMessageBarStyles> => ({
root: [AnimationClassNames.fadeIn500]
});

export const AssignmentUpdateFailureMessageBar = styled(AssignmentUpdateFailureMessageBarInner, assignmentUpdateFailureMessageBarStyles);
7 changes: 6 additions & 1 deletion client/src/Core/Components/MainLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import learnLogo from '../../Assets/icon_learn_062020.png';
import { useQueryValue } from '../Hooks';
import { ErrorPage } from './ErrorsPage';
import { NavigationControlHeader } from './NavigationControlHeader';
import { AssignmentUpdateFailureMessageBar } from './AssignmentUpdateFailureMessageBar';

type MainLayoutStyles = SimpleComponentStyles<'root' | 'spinner' | 'content'>;

Expand Down Expand Up @@ -52,11 +53,15 @@ const MainLayoutInner = ({ styles }: IStylesOnly<MainLayoutStyles>): JSX.Element
<div className={classes.content}>
{usersStore.userDetails.role === 'teacher' && !asStudent ? (
<>
<AssignmentUpdateFailureMessageBar/>
<NavigationControlHeader/>
<PagesRouter />
</>
) : (
<StudentPage />
<>
<AssignmentUpdateFailureMessageBar/>
<StudentPage />
</>
)}
</div>
)}
Expand Down
87 changes: 67 additions & 20 deletions client/src/Core/Components/NavigationControlHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,50 +3,97 @@
* Licensed under the MIT License.
*--------------------------------------------------------------------------------------------*/

import { FontSizes, FontWeights, mergeStyles, styled } from '@fluentui/react';
import { SpinnerSize } from '@fluentui/react';
import { Spinner } from '@fluentui/react';
import { FontSizes, FontWeights, mergeStyles, MessageBarType, styled } from '@fluentui/react';
import { useObserver } from 'mobx-react-lite';
import React from 'react';
import { PublishControlArea } from '../../Features/PublishAssignment/PublishControlArea';
import { PublishSuccessMessageBar } from '../../Features/PublishAssignment/PublishSuccessMessageBar';
import {
PublishSuccessMessageBar,
PublishSuccessMessageBarProps
} from '../../Features/PublishAssignment/PublishSuccessMessageBar';
import { useStore } from '../../Stores/Core';
import { themedClassNames } from '../Utils/FluentUI';
import { IStylesOnly, IThemeOnlyProps, SimpleComponentStyles } from '../Utils/FluentUI/typings.fluent-ui';
import { stickyHeaderStyle } from './Common/StickyHeaderStyle';
import * as NavBarBase from './Navbar';

type NavigationControlHeaderStyles = SimpleComponentStyles<'assignmentTitle' | 'navAndControlArea'>;
type NavigationControlHeaderStyles = SimpleComponentStyles<'assignmentTitle' | 'navAndControlArea' | 'header'>;

function NavigationControlHeaderInner({ styles }: IStylesOnly<NavigationControlHeaderStyles>): JSX.Element {
const assignmentStore = useStore('assignmentStore');
const assignmentLinksStore = useStore('assignmentLinksStore');
const learnStore = useStore('microsoftLearnStore');
const classes = themedClassNames(styles);
return useObserver(() => (
<>
<span className={classes.assignmentTitle}>{assignmentStore.assignment?.name}</span>
<div className={classes.navAndControlArea}>
<NavBarBase.NavbarTop />
<PublishControlArea />
</div>
<PublishSuccessMessageBar
isPublished={
assignmentStore.assignment?.publishStatus === 'Published' && assignmentStore.isChangingPublishState === false
}
/>
</>
));

return useObserver(() => {
const learnStoreCallsInProgress =
!learnStore.isLoadingCatalog &&
(learnStore.serviceCallsInProgress || learnStore.clearCallInProgress || learnStore.clearCallsToMake)
? 1
: 0;
const isCallInProgress =
learnStoreCallsInProgress + assignmentLinksStore.serviceCallInProgress + assignmentStore.serviceCallInProgress > 0;
const publishStatusMessageBarProps: PublishSuccessMessageBarProps =
assignmentStore.pushlishStatusChangeError === 'unauthorized'
? {
messageBarType: MessageBarType.error,
message: 'Sorry, but it seems like you do not have sufficient permissions to perform this action.',
showMessage: assignmentStore.pushlishStatusChangeError === 'unauthorized'
}
: assignmentStore.pushlishStatusChangeError !== null
? {
messageBarType: MessageBarType.error,
message:
assignmentStore.assignment?.publishStatus !== 'Published'
? 'Something went wrong! Could not publish the assignment'
: 'Something went wrong! Could not switch to edit mode',
showMessage: assignmentStore.pushlishStatusChangeError !== null
}
: {
messageBarType: MessageBarType.success,
message: 'Your assignment was published successfully',
showMessage:
assignmentStore.assignment?.publishStatus === 'Published' &&
assignmentStore.isChangingPublishState === false
};

return (
<>
<div className={classes.header}>
<span className={classes.assignmentTitle}>{assignmentStore.assignment?.name}</span>
{isCallInProgress && <Spinner label="Updating..." labelPosition="left" size={SpinnerSize.small}/>}
</div>
<div className={classes.navAndControlArea}>
<NavBarBase.NavbarTop />
<PublishControlArea />
</div>
<PublishSuccessMessageBar {...publishStatusMessageBarProps} />
</>
);
});
}

const navigationControlHeaderStyle = ({ theme }: IThemeOnlyProps): NavigationControlHeaderStyles => {
return {
header: [
{
display: 'flex',
justifyContent: 'space-between',
paddingRight: `calc(${theme.spacing.l1} * 1.6)`,
paddingLeft: `calc(${theme.spacing.l1} * 1.6)`,
paddingBottom: `calc(${theme.spacing.l1} * 0.5)`,
paddingTop: `calc(${theme.spacing.l1} * 1.5)`
}
],
assignmentTitle: [
{
fontSize: FontSizes.xLargePlus,
fontWeight: FontWeights.semibold,
color: theme.palette.neutralPrimary,
backgroundColor: theme.palette.neutralLighterAlt,
lineHeight: FontSizes.xxLarge,
paddingLeft: `calc(${theme.spacing.l1} * 1.6)`,
paddingBottom: `calc(${theme.spacing.l1} * 0.5)`,
paddingTop: `calc(${theme.spacing.l1} * 1.5)`
}
],

Expand Down
2 changes: 1 addition & 1 deletion client/src/Core/Utils/Axios/ServiceError.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
* Licensed under the MIT License.
*--------------------------------------------------------------------------------------------*/

export type ServiceError = 'unauthorized' | 'internal error' | 'other' | 'not found';
export type ServiceError = 'unauthorized' | 'internal error' | 'other' | 'not found' | 'bad request';
3 changes: 2 additions & 1 deletion client/src/Core/Utils/Axios/safeData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ import { ServiceError } from './ServiceError';
const errorNumberToEnumMap: Map<number, ServiceError> = new Map<number, ServiceError>([
[500, 'internal error'],
[401, 'unauthorized'],
[404, 'not found']
[404, 'not found'],
[400, 'bad request']
]);

export type WithError<T> = T & { error?: ServiceError };
Expand Down
2 changes: 1 addition & 1 deletion client/src/Dtos/Assignment.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { PlatformPersonalizationDto } from './PlatformPersonalization.dto';

export interface AssignmentDto {
id: string;
deadline: Date;
deadline: Date | null;
courseName: string;
name: string;
description: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { themedClassNames } from '../../Core/Utils/FluentUI';
import { useStore } from '../../Stores/Core';
import { AssignmentLink } from '../../Models/AssignmentLink.model';
import { commonDialogContentProps, DIALOG_MIN_WIDTH } from '../../Core/Components/Common/Dialog/EdnaDialogStyles';
import { useObserver } from 'mobx-react-lite';

interface AssignmentLinkDisplayItemActionAreaProps {
toggleEditMode: () => void;
Expand All @@ -42,10 +43,18 @@ const AssignmentLinkDisplayItemActionAreaInner = ({
title: 'Delete Link'
};

return (
return useObserver(() => (
<div className={classes.root}>
<IconButton iconProps={{ iconName: 'Edit' }} onClick={toggleEditMode} />
<IconButton iconProps={{ iconName: 'Delete' }} onClick={() => setIsDialogOpen(true)}>
<IconButton
iconProps={{ iconName: 'Edit' }}
onClick={toggleEditMode}
disabled={assignmentLinksStore.addOrUpdateCallInProgress.includes(link.id)}
/>
<IconButton
iconProps={{ iconName: 'Delete' }}
onClick={() => setIsDialogOpen(true)}
disabled={assignmentLinksStore.addOrUpdateCallInProgress.includes(link.id)}
>
<Dialog
hidden={!isDialogOpen}
onDismiss={() => setIsDialogOpen(false)}
Expand All @@ -64,7 +73,7 @@ const AssignmentLinkDisplayItemActionAreaInner = ({
</Dialog>
</IconButton>
</div>
);
))
};

const assignmentLinkDisplayItemActionAreaStyles = ({
Expand Down
8 changes: 6 additions & 2 deletions client/src/Features/AssignmentLinks/AssignmentLinksList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { AssignmentLinkItemShimmer } from './AssignmentLinkItemShimmer';

interface AssignmentLinksListProps {
disableEdit?: boolean;
showSynced?: boolean;
}
export type AssignmentLinksListStyles = SimpleComponentStyles<'root' | 'itemsDividerSeparator'>;
type AssignmentLinksListStylesProps = {
Expand All @@ -22,10 +23,13 @@ type AssignmentLinksListStylesProps = {

const AssignmentLinksListInner = ({
styles,
disableEdit
disableEdit,
showSynced
}: AssignmentLinksListProps & IStylesOnly<AssignmentLinksListStyles>): JSX.Element => {
const assignmentLinksStore = useStore('assignmentLinksStore');

const assignmentLinksToDisplay = showSynced? assignmentLinksStore.syncedAssignmentLinks : assignmentLinksStore.assignmentLinks;

const classes = themedClassNames(styles);

return useObserver(() => {
Expand All @@ -35,7 +39,7 @@ const AssignmentLinksListInner = ({
<AssignmentLinkItemShimmer />
) : (
<>
{assignmentLinksStore.assignmentLinks.map((link, index) => (
{ assignmentLinksToDisplay.map((link, index) => (
<React.Fragment key={link.id}>
{index !== 0 && <Separator className={classes.itemsDividerSeparator} />}
<AssignmentLinkItem link={link} disableEdit={disableEdit} />
Expand Down
5 changes: 3 additions & 2 deletions client/src/Features/GeneralPage/DeadlineInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { InputGroupWrapper } from '../../Core/Components/Common/InputGroupWrappe
import { generalPageInputGroupChildrenStyleProps } from './GeneralPageStyles';
import { datePickerBaseStyle } from '../../Core/Components/Common/Inputs/EdnaInputStyles';
import { useStore } from '../../Stores/Core';
import { useObserver } from 'mobx-react-lite';

type DeadlineInputStyles = Partial<IDatePickerStyles>;

Expand All @@ -31,7 +32,7 @@ const DeadlineInputInner = ({ styles }: IStylesOnly<DeadlineInputStyles>): JSX.E
const formatDate = (chosenDate?: Date): string => {
return chosenDate ? moment(chosenDate).format('MMM DD YYYY') : '';
};
return (
return useObserver(() => (
<InputGroupWrapper styles={generalPageInputGroupChildrenStyleProps} label="Deadline">
<DatePicker
styles={combinedStyles}
Expand All @@ -43,7 +44,7 @@ const DeadlineInputInner = ({ styles }: IStylesOnly<DeadlineInputStyles>): JSX.E
value={deadline || undefined}
/>
</InputGroupWrapper>
);
));
};

const deadlineInputStyles = ({ theme }: IThemeOnlyProps): DeadlineInputStyles => ({
Expand Down
5 changes: 3 additions & 2 deletions client/src/Features/GeneralPage/DescriptionInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { generalPageInputGroupChildrenStyleProps } from './GeneralPageStyles';
import { themedClassNames } from '../../Core/Utils/FluentUI';
import { textFieldBaseStyle } from '../../Core/Components/Common/Inputs/EdnaInputStyles';
import { useStore } from '../../Stores/Core';
import { useObserver } from 'mobx-react-lite';

type DescriptionInputStyles = Partial<ITextFieldStyles>;
const DescriptionInputInner = ({ styles }: IStylesOnly<DescriptionInputStyles>): JSX.Element => {
Expand All @@ -21,7 +22,7 @@ const DescriptionInputInner = ({ styles }: IStylesOnly<DescriptionInputStyles>):

const combinedStyles = mergeStyleSets(themedClassNames(textFieldBaseStyle), themedClassNames(styles));

return (
return useObserver(() => (
<InputGroupWrapper
label="Description"
labelElementId={descriptionFieldId}
Expand All @@ -38,7 +39,7 @@ const DescriptionInputInner = ({ styles }: IStylesOnly<DescriptionInputStyles>):
onChange={(_e, newValue) => setDescription(newValue || '')}
/>
</InputGroupWrapper>
);
));
};

const descriptionInputStyles = ({ theme }: IThemeOnlyProps): DescriptionInputStyles => ({
Expand Down
3 changes: 2 additions & 1 deletion client/src/Features/MicrosoftLearn/MicrosoftLearnItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,8 @@ const MicrosoftLearnItemInner = ({
);

return useObserver(() => {
const isSelected = !!learnStore.selectedItems?.find(selectedItem => selectedItem.contentUid === item.uid);
const selectedItems = [...learnStore.contentSelectionMap].filter(item => item[1].userState==='selected');
const isSelected = !!selectedItems?.find(selectedItem => selectedItem[0] === item.uid);
const classNames = classNamesFunction<MicrosoftLearnItemStylesProps, MicrosoftLearnItemStyles>()(styles, {
theme: getTheme(),
productDetails: productCatalogDetails,
Expand Down
Loading