commit changes on Slales Order

This commit is contained in:
João Mendes 2023-11-06 10:39:10 +00:00
parent 1789b83c2d
commit 3c3f9ac6e8
9 changed files with 316 additions and 137 deletions

View File

@ -14,10 +14,12 @@ import { SearchBox } from '@fluentui/react-search-preview';
import { Icon } from '@iconify/react'; import { Icon } from '@iconify/react';
import { appGlobalStateAtom } from '../atoms/appGlobalStateAtom'; import { appGlobalStateAtom } from '../atoms/appGlobalStateAtom';
import { EMessageType } from '../constants/EMessageTypes';
import { useGraphAPI } from '../hooks/useGraphAPI'; import { useGraphAPI } from '../hooks/useGraphAPI';
import { ICustomer } from '../models/ICustomer'; import { ICustomer } from '../models/ICustomer';
import { IMenuItem } from '../models/IMenuItem'; import { IMenuItem } from '../models/IMenuItem';
import { IOrder } from '../models/IOrder'; import { IOrder } from '../models/IOrder';
import { ShowMessage } from '../showMessage/ShowMessage';
import { CompanyInfo } from './companyInfo/CompanyInfo'; import { CompanyInfo } from './companyInfo/CompanyInfo';
import { CustomersGrid } from './customersGrid/CustomersGrid'; import { CustomersGrid } from './customersGrid/CustomersGrid';
import { ISalesordersProps } from './ISalesordersProps'; import { ISalesordersProps } from './ISalesordersProps';
@ -47,6 +49,7 @@ export const SalesordersControl: React.FunctionComponent<ISalesordersProps> = (
const [searchText, setSearchText] = React.useState<string>(""); const [searchText, setSearchText] = React.useState<string>("");
const [isLoading, setIsLoading] = React.useState<boolean>(false); const [isLoading, setIsLoading] = React.useState<boolean>(false);
const [customers, setCustomers] = React.useState<ICustomer[]>([]); const [customers, setCustomers] = React.useState<ICustomer[]>([]);
const [error, setError] = React.useState<Error>((undefined as unknown) as Error);
React.useEffect(() => { React.useEffect(() => {
setAppglobalState({ ...appglobalState, ...props }); setAppglobalState({ ...appglobalState, ...props });
@ -59,13 +62,28 @@ export const SalesordersControl: React.FunctionComponent<ISalesordersProps> = (
React.useEffect(() => { React.useEffect(() => {
(async () => { (async () => {
const orders = await searchOrders(searchText); try {
const customers = await getCustomers(searchText); switch (selectedItem.id) {
setCustomers(customers); case 1:
setOrders(orders ); setOrders(await searchOrders(searchText));
break;
case 2:
setCustomers(await getCustomers(searchText));
break;
default:
break;
}
} catch (error) {
setError(error);
} finally {
setIsLoading(false); setIsLoading(false);
}
/* const customers = await getCustomers(searchText);
setCustomers(customers);
setOrders(orders ); */
/* setIsLoading(false); */
})(); })();
}, [searchText]); }, [searchText, selectedItem]);
const totalOrders = React.useMemo(() => { const totalOrders = React.useMemo(() => {
return orders.length; return orders.length;
@ -109,7 +127,6 @@ export const SalesordersControl: React.FunctionComponent<ISalesordersProps> = (
/> />
<OrdersGrid items={orders} /> <OrdersGrid items={orders} />
</> </>
); );
case 2: case 2:
@ -130,6 +147,24 @@ export const SalesordersControl: React.FunctionComponent<ISalesordersProps> = (
} }
}, [selectedItem]); }, [selectedItem]);
const hasError = React.useMemo(() => {
return !error ? false : true;
}, [error]);
const RenderRightContent = React.useCallback(() => {
if (hasError) {
return <ShowMessage isShow={hasError} messageType={EMessageType.ERROR} message={error.message} />;
}
if (isLoading) {
return (
<div style={{ paddingTop: 60 }}>
<Spinner />
</div>
);
}
return <>{!hasOrders ? <NoOrders /> : renderSelectedContent()}</>;
}, [ hasError, error, isLoading, hasOrders, renderSelectedContent]);
return ( return (
<> <>
<main className={styles.mainContainer}> <main className={styles.mainContainer}>
@ -158,13 +193,14 @@ export const SalesordersControl: React.FunctionComponent<ISalesordersProps> = (
} }
/> />
</div> </div>
{isLoading ? ( <RenderRightContent />
{/* {isLoading ? (
<div style={{ paddingTop: 60 }}> <div style={{ paddingTop: 60 }}>
<Spinner /> <Spinner />
</div> </div>
) : ( ) : (
<>{!hasOrders ? <NoOrders /> : renderSelectedContent()}</> <>{!hasOrders ? <NoOrders /> : renderSelectedContent()}</>
)} )} */}
</Right> </Right>
</div> </div>
</main> </main>

View File

@ -19,6 +19,7 @@ import {
} from '@fluentui/react-components'; } from '@fluentui/react-components';
import { IOrder } from '../../models/IOrder'; import { IOrder } from '../../models/IOrder';
import { useOrdersGridStyles } from './useOrdersGridStyles';
const columns: TableColumnDefinition<IOrder>[] = [ const columns: TableColumnDefinition<IOrder>[] = [
createTableColumn<IOrder>({ createTableColumn<IOrder>({
@ -197,8 +198,10 @@ export const OrdersGrid: React.FunctionComponent<IOrdersGridProps> = (
setSortState(nextSortState); setSortState(nextSortState);
}, []); }, []);
const styles = useOrdersGridStyles();
return ( return (
<div style={{ paddingTop: 30 }}> <div className={styles.gridContainer}>
<DataGrid <DataGrid
items={items} items={items}
columns={columns} columns={columns}

View File

@ -0,0 +1,29 @@
import {
makeStyles,
shorthands,
tokens,
} from '@fluentui/react-components';
export const useOrdersGridStyles = makeStyles({
gridContainer: {
paddingTop: "30px",
width: "100%",
height: 'calc(100vh - 440px)',
backgroundColor: tokens.colorNeutralBackground2,
overflowY: "auto",
overflowX: "hidden",
"scrollbar-color": tokens.colorNeutralBackground1,
"scrollbar-width": "thin",
"::-webkit-scrollbar-thumb": {
backgroundColor: tokens?.colorBrandStroke2,
...shorthands.borderRadius("10px"),
...shorthands.borderWidth("1px"),
},
"::-webkit-scrollbar": {
height: "10px",
width: "7px",
},
},
});

View File

@ -6,30 +6,17 @@ import {
export const useSalesordersStyles = makeStyles({ export const useSalesordersStyles = makeStyles({
mainContainer: { mainContainer: {
width: "100%", width: "100%",
height: "100vh", height: 'calc(100vh - 200px)',
backgroundColor: tokens.colorNeutralBackground2, backgroundColor: tokens.colorNeutralBackground2,
overflowY: "auto",
overflowX: "hidden",
"scrollbar-color": tokens.colorNeutralBackground1,
"scrollbar-width": "thin",
"::-webkit-scrollbar-thumb": {
backgroundColor: tokens?.colorBrandStroke2,
...shorthands.borderRadius("10px"),
...shorthands.borderWidth("1px"),
},
"::-webkit-scrollbar": {
height: "10px",
width: "7px",
},
}, },
contentContainer: { contentContainer: {
display: "grid", display: "grid",
gridTemplateColumns: "min(100%, 300px) 1fr 1fr 1fr", gridTemplateColumns: "min(100%, 300px) 1fr 1fr 1fr",
gridTemplateRows: "1fr", gridTemplateRows: "1fr",
height: "100vh", height: 'calc(100vh - 200px)',
}, },
leftContainer : { leftContainer : {

View File

@ -0,0 +1,5 @@
export enum EMessageType {
INFO = 'info',
ERROR = 'error',
SUCCESS = 'success',
}

View File

@ -23,29 +23,8 @@ export const useGraphAPI = (context: BaseComponentContext): IuseGraphAPI => {
return await context.msGraphClientFactory.getClient("3"); return await context.msGraphClientFactory.getClient("3");
}, [context]); }, [context]);
const searchOrders = React.useCallback(
async (searchText: string): Promise<any> => {
if (!graphClient) return undefined;
const request = { const mappingOrders = React.useCallback((result: SearchHit[]): IOrder[] => {
requests: [
{
entityTypes: ["externalItem"],
contentSources: ["/external/connections/ibmdb2lob"],
query: {
queryString: `${searchText}*`,
},
from: 0,
size: 100,
},
],
};
try {
const response = await (await graphClient)?.api(`search/query`).post(request);
const result: SearchHit[] = response?.value[0]?.hitsContainers[0]?.hits;
if (!result) return [];
const ordersList: IOrder[] = []; const ordersList: IOrder[] = [];
for (const item of result) { for (const item of result) {
const { resource } = item; const { resource } = item;
@ -65,27 +44,17 @@ export const useGraphAPI = (context: BaseComponentContext): IuseGraphAPI => {
orderstatus, orderstatus,
} = properties as any; } = properties as any;
if (!custname || !state || !country || !orders || !orderdates || !ordertotals || !orderstatus) continue;
for (let i = 0; i < orders.length; i++) { for (let i = 0; i < orders.length; i++) {
const order: IOrder = { const order: IOrder = {
customer: custname, customer: custname,
city: `${state} ${country}`, city: `${state} ${country}`,
order: orders[i], order: orders[i],
total: ordertotals[i], total: ordertotals[i],
orderDate: orderdates[i], orderDate: orderdates[i],
status: orderstatus[i], status: orderstatus[i],
customerCode: custcode, customerCode: custcode,
custmoerEmail: email, custmoerEmail: email,
customerState: state, customerState: state,
id: id, id: id,
}; };
ordersList.push(order); ordersList.push(order);
@ -93,39 +62,10 @@ export const useGraphAPI = (context: BaseComponentContext): IuseGraphAPI => {
} }
} }
} }
/* setCacheValue(searchText, ordersList); */
console.log(ordersList);
return ordersList; return ordersList;
} catch (error) { }, [ graphClient]);
console.log("[searchOrders] error:", error);
throw new Error("Something went wrong when search Orders");
}
},
[graphClient]
);
const getCustomers = React.useCallback(async (searchText:string): Promise<ICustomer[] | []> => {
if (!graphClient) return [];
const request = {
requests: [
{
entityTypes: ["externalItem"],
contentSources: ["/external/connections/ibmdb2lob"],
query: {
queryString: `${searchText}*`,
},
from: 0,
size: 100,
},
],
};
try {
const response = await (await graphClient)?.api(`search/query`).post(request);
const result: SearchHit[] = response?.value[0]?.hitsContainers[0]?.hits;
const mappingCustomers = React.useCallback((result: SearchHit[]): ICustomer[] => {
const customersList: ICustomer[] = []; const customersList: ICustomer[] = [];
for (const item of result) { for (const item of result) {
const { resource } = item; const { resource } = item;
@ -160,13 +100,74 @@ export const useGraphAPI = (context: BaseComponentContext): IuseGraphAPI => {
} }
} }
} }
return customersList;
}, [ graphClient]);
const searchOrders = React.useCallback(
async (searchText: string): Promise<any> => {
if (!graphClient) return undefined;
const request = {
requests: [
{
entityTypes: ["externalItem"],
contentSources: ["/external/connections/ibmdb2lob"],
query: {
queryString: `${searchText}*`,
},
from: 0,
size: 100,
},
],
};
try {
const response = await (await graphClient)?.api(`search/query`).post(request);
const result: SearchHit[] = response?.value[0]?.hitsContainers[0]?.hits;
if (!result) return [];
const ordersList = mappingOrders(result);
console.log(ordersList);
return ordersList;
} catch (error) {
console.log("[searchOrders] error:", error);
throw new Error("Something went wrong when search Orders");
}
},
[graphClient]
);
const getCustomers = React.useCallback(
async (searchText: string): Promise<ICustomer[] | []> => {
if (!graphClient) return [];
const request = {
requests: [
{
entityTypes: ["externalItem"],
contentSources: ["/external/connections/ibmdb2lob"],
query: {
queryString: `${searchText}*`,
},
from: 0,
size: 100,
},
],
};
try {
const response = await (await graphClient)?.api(`search/query`).post(request);
const result: SearchHit[] = response?.value[0]?.hitsContainers[0]?.hits;
const customersList = mappingCustomers(result);
const uniqueCustomers = uniqBy(customersList, "customerCode"); const uniqueCustomers = uniqBy(customersList, "customerCode");
return sortBy(uniqueCustomers, "customerName"); return sortBy(uniqueCustomers, "customerName");
} catch (error) { } catch (error) {
console.log("[getCustomers] error:", error); console.log("[getCustomers] error:", error);
throw new Error("Something went wrong when getting customers"); throw new Error("Something went wrong when getting customers");
} }
}, [graphClient]); },
[graphClient]
);
return { return {
searchOrders, searchOrders,

View File

@ -0,0 +1,10 @@
import * as React from 'react';
import { EMessageType } from '../constants/EMessageTypes';
export interface IShowMessageProps {
isShow: boolean;
messageType: EMessageType;
message: string | React.ReactNode;
children?: React.ReactNode;
}

View File

@ -0,0 +1,73 @@
import * as React from 'react';
import {
Body1,
Body1Strong,
tokens,
} from '@fluentui/react-components';
import {
CheckmarkCircle32Regular,
Info32Regular,
} from '@fluentui/react-icons';
import { Icon } from '@iconify/react';
import { EMessageType } from '../constants/EMessageTypes';
import { IShowMessageProps } from './IShowMessageProps';
import { useShowMessageStyles } from './useShowMessageStyles';
export const ShowMessage: React.FunctionComponent<IShowMessageProps> = (
props: React.PropsWithChildren<IShowMessageProps>
) => {
const { messageType, children, message, isShow } = props;
const styles = useShowMessageStyles();
const [renderMessageIcon, setRenderMessageIcon] = React.useState<JSX.Element | null>(null);
const RenderError = React.useCallback(() => {
return (
<>
<div className={styles.errorContainer}>
<div className={styles.errorIcon}>
<Icon
icon="fluent:error-circle-24-regular"
width="32"
height="32"
color={tokens.colorStatusDangerForeground1}
/>
</div>
<Body1 style={{ width: "100%" }}>{message}</Body1>
</div>
</>
);
}, [message]);
React.useEffect(() => {
switch (messageType) {
case EMessageType.SUCCESS:
setRenderMessageIcon(<CheckmarkCircle32Regular primaryFill={tokens.colorStatusSuccessForeground1} />);
break;
case EMessageType.INFO:
setRenderMessageIcon(<Info32Regular primaryFill={tokens.colorStatusWarningForeground1} />);
break;
default:
break;
}
}, [messageType]);
if (!isShow) {
return <></>;
}
if (messageType === EMessageType.ERROR) {
return <RenderError />;
}
return (
<>
<div className={styles.root}>
{renderMessageIcon}
<Body1Strong>{messageType}</Body1Strong>
{children}
</div>
</>
);
};

View File

@ -0,0 +1,35 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import {
makeStyles,
shorthands,
tokens,
} from '@fluentui/react-components';
export const useShowMessageStyles = makeStyles({
root: {
display: "flex",
flexDirection: "row",
justifyContent: "center",
alignItems: "center",
...shorthands.padding("10px"),
...shorthands.gap("10px"),
width: '100%',
} ,
iconClass: {
width: "32px",
height: "32px",
} as any,
errorContainer: {
display: "flex",
flexDirection: "row",
justifyContent: "start",
alignItems: "center",
...shorthands.gap("10px"),
...shorthands.padding("10px"),
backgroundColor: tokens.colorStatusDangerBackground1,
} ,
errorIcon: {
width: "32px",
height: "32px",
} ,
});