mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-19 14:20:31 +00:00
re-structure to monorepo.
This commit is contained in:
@@ -0,0 +1,29 @@
|
||||
// @ts-nocheck
|
||||
import React from 'react';
|
||||
import intl from 'react-intl-universal';
|
||||
|
||||
import '@/style/pages/Preferences/warehousesList.scss';
|
||||
|
||||
import WarehousesGrid from './WarehousesGrid';
|
||||
import withDashboardActions from '@/containers/Dashboard/withDashboardActions';
|
||||
import { compose } from '@/utils';
|
||||
|
||||
/**
|
||||
* Warehouses.
|
||||
* @returns
|
||||
*/
|
||||
function Warehouses({
|
||||
// #withDashboardActions
|
||||
changePreferencesPageTitle,
|
||||
}) {
|
||||
React.useEffect(() => {
|
||||
changePreferencesPageTitle(intl.get('warehouses.label'));
|
||||
}, [changePreferencesPageTitle]);
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<WarehousesGrid />
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
export default compose(withDashboardActions)(Warehouses);
|
||||
@@ -0,0 +1,36 @@
|
||||
// @ts-nocheck
|
||||
import React from 'react';
|
||||
import { Button, Intent } from '@blueprintjs/core';
|
||||
|
||||
import { Features } from '@/constants';
|
||||
import { FeatureCan, FormattedMessage as T, Icon } from '@/components';
|
||||
import withDialogActions from '@/containers/Dialog/withDialogActions';
|
||||
import { compose } from '@/utils';
|
||||
|
||||
/**
|
||||
* Warehouse actions.
|
||||
*/
|
||||
function WarehousesActions({
|
||||
//#ownProps
|
||||
openDialog,
|
||||
}) {
|
||||
const handleClickNewWarehouse = () => {
|
||||
openDialog('warehouse-form');
|
||||
};
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<FeatureCan feature={Features.Warehouses}>
|
||||
<Button
|
||||
icon={<Icon icon="plus" iconSize={12} />}
|
||||
onClick={handleClickNewWarehouse}
|
||||
intent={Intent.PRIMARY}
|
||||
>
|
||||
<T id={'warehouses.label.new_warehouse'} />
|
||||
</Button>
|
||||
</FeatureCan>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
export default compose(withDialogActions)(WarehousesActions);
|
||||
@@ -0,0 +1,11 @@
|
||||
// @ts-nocheck
|
||||
import React from 'react';
|
||||
|
||||
const WarehouseDeleteAlert = React.lazy(
|
||||
() => import('@/containers/Alerts/Warehouses/WarehouseDeleteAlert'),
|
||||
);
|
||||
|
||||
/**
|
||||
* Warehouses alerts.
|
||||
*/
|
||||
export default [{ name: 'warehouse-delete', component: WarehouseDeleteAlert }];
|
||||
@@ -0,0 +1,41 @@
|
||||
// @ts-nocheck
|
||||
import React from 'react';
|
||||
import { Button, Intent } from '@blueprintjs/core';
|
||||
import { FormattedMessage as T, EmptyStatus } from '@/components';
|
||||
import withDialogActions from '@/containers/Dialog/withDialogActions';
|
||||
|
||||
import { compose } from '@/utils';
|
||||
|
||||
function WarehousesEmptyStatus({
|
||||
// #withDialogActions
|
||||
openDialog,
|
||||
}) {
|
||||
// Handle activate action warehouse.
|
||||
const handleActivateWarehouse = () => {
|
||||
openDialog('warehouse-activate', {});
|
||||
};
|
||||
|
||||
return (
|
||||
<EmptyStatus
|
||||
title={<T id={'warehouses.empty_status.title'} />}
|
||||
description={
|
||||
<p>
|
||||
<T id={'warehouses.empty_status.description'} />
|
||||
</p>
|
||||
}
|
||||
action={
|
||||
<React.Fragment>
|
||||
<Button
|
||||
intent={Intent.PRIMARY}
|
||||
large={true}
|
||||
onClick={handleActivateWarehouse}
|
||||
>
|
||||
<T id={'warehouses.activate_button'} />
|
||||
</Button>
|
||||
</React.Fragment>
|
||||
}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export default compose(withDialogActions)(WarehousesEmptyStatus);
|
||||
@@ -0,0 +1,32 @@
|
||||
// @ts-nocheck
|
||||
import React from 'react';
|
||||
import WarehousesEmptyStatus from './WarehousesEmptyStatus';
|
||||
import { useWarehousesContext } from './WarehousesProvider';
|
||||
import { WarehousesList, WarehousesSkeleton } from './components';
|
||||
import WarehousesGridItems from './WarehousesGridItems';
|
||||
|
||||
/**
|
||||
* Warehouses grid.
|
||||
*/
|
||||
export default function WarehousesGrid() {
|
||||
// Retrieve list context.
|
||||
const {
|
||||
warehouses,
|
||||
isWarehouesLoading,
|
||||
isEmptyStatus,
|
||||
} = useWarehousesContext();
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<WarehousesList>
|
||||
{isWarehouesLoading ? (
|
||||
<WarehousesSkeleton />
|
||||
) : isEmptyStatus ? (
|
||||
<WarehousesEmptyStatus />
|
||||
) : (
|
||||
<WarehousesGridItems warehouses={warehouses} />
|
||||
)}
|
||||
</WarehousesList>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
// @ts-nocheck
|
||||
import React from 'react';
|
||||
import intl from 'react-intl-universal';
|
||||
import { Intent } from '@blueprintjs/core';
|
||||
import { ContextMenu2 } from '@blueprintjs/popover2';
|
||||
|
||||
import { AppToaster } from '@/components';
|
||||
import { WarehouseContextMenu, WarehousesGridItemBox } from './components';
|
||||
import { useMarkWarehouseAsPrimary } from '@/hooks/query';
|
||||
|
||||
import withAlertsActions from '@/containers/Alert/withAlertActions';
|
||||
import withDialogActions from '@/containers/Dialog/withDialogActions';
|
||||
import { compose } from '@/utils';
|
||||
|
||||
/**
|
||||
* warehouse grid item.
|
||||
*/
|
||||
function WarehouseGridItem({
|
||||
// #withAlertsActions
|
||||
openAlert,
|
||||
|
||||
// #withDialogActions
|
||||
openDialog,
|
||||
|
||||
warehouse,
|
||||
}) {
|
||||
const { mutateAsync: markWarehouseAsPrimaryMutate } =
|
||||
useMarkWarehouseAsPrimary();
|
||||
|
||||
// Handle edit warehouse.
|
||||
const handleEditWarehouse = () => {
|
||||
openDialog('warehouse-form', { warehouseId: warehouse.id, action: 'edit' });
|
||||
};
|
||||
// Handle delete warehouse.
|
||||
const handleDeleteWarehouse = () => {
|
||||
openAlert('warehouse-delete', { warehouseId: warehouse.id });
|
||||
};
|
||||
// Handle mark primary warehouse.
|
||||
const handleMarkWarehouseAsPrimary = () => {
|
||||
markWarehouseAsPrimaryMutate(warehouse.id).then(() => {
|
||||
AppToaster.show({
|
||||
message: intl.get('warehouse.alert.mark_primary_message'),
|
||||
intent: Intent.SUCCESS,
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<ContextMenu2
|
||||
content={
|
||||
<WarehouseContextMenu
|
||||
warehouse={warehouse}
|
||||
onEditClick={handleEditWarehouse}
|
||||
onDeleteClick={handleDeleteWarehouse}
|
||||
onMarkPrimary={handleMarkWarehouseAsPrimary}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<WarehousesGridItemBox
|
||||
title={warehouse.name}
|
||||
code={warehouse.code}
|
||||
city={warehouse.city}
|
||||
country={warehouse.country}
|
||||
email={warehouse.email}
|
||||
phoneNumber={warehouse.phone_number}
|
||||
primary={warehouse.primary}
|
||||
/>
|
||||
</ContextMenu2>
|
||||
);
|
||||
}
|
||||
|
||||
const WarehousesGridItem = compose(
|
||||
withAlertsActions,
|
||||
withDialogActions,
|
||||
)(WarehouseGridItem);
|
||||
|
||||
/**
|
||||
* warehouses grid items,
|
||||
*/
|
||||
export default function WarehousesGridItems({ warehouses }) {
|
||||
return warehouses.map((warehouse) => (
|
||||
<WarehousesGridItem warehouse={warehouse} />
|
||||
));
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
// @ts-nocheck
|
||||
import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
import classNames from 'classnames';
|
||||
import { CLASSES } from '@/constants/classes';
|
||||
import { useWarehouses } from '@/hooks/query';
|
||||
import { isEmpty } from 'lodash';
|
||||
|
||||
import { Features } from '@/constants';
|
||||
import { useFeatureCan } from '@/hooks/state';
|
||||
|
||||
const WarehousesContext = React.createContext();
|
||||
|
||||
/**
|
||||
* Warehouses data provider.
|
||||
*/
|
||||
function WarehousesProvider({ query, ...props }) {
|
||||
// Features guard.
|
||||
const { featureCan } = useFeatureCan();
|
||||
const isWarehouseFeatureCan = featureCan(Features.Warehouses);
|
||||
|
||||
// Fetch warehouses list.
|
||||
const { data: warehouses, isLoading: isWarehouesLoading } = useWarehouses(
|
||||
query,
|
||||
{ enabled: isWarehouseFeatureCan },
|
||||
);
|
||||
|
||||
// Detarmines the datatable empty status.
|
||||
const isEmptyStatus = isEmpty(warehouses) || !isWarehouseFeatureCan;
|
||||
|
||||
// Provider state.
|
||||
const provider = {
|
||||
warehouses,
|
||||
isWarehouesLoading,
|
||||
isEmptyStatus,
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classNames(
|
||||
CLASSES.PREFERENCES_PAGE_INSIDE_CONTENT,
|
||||
CLASSES.PREFERENCES_PAGE_INSIDE_CONTENT_WAREHOUSES,
|
||||
)}
|
||||
>
|
||||
<React.Fragment>
|
||||
<WarehousesContext.Provider value={provider} {...props} />
|
||||
</React.Fragment>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const useWarehousesContext = () => React.useContext(WarehousesContext);
|
||||
|
||||
export { WarehousesProvider, useWarehousesContext };
|
||||
|
||||
const WarehousePreference = styled.div``;
|
||||
@@ -0,0 +1,189 @@
|
||||
// @ts-nocheck
|
||||
import React from 'react';
|
||||
import intl from 'react-intl-universal';
|
||||
import styled from 'styled-components';
|
||||
import {
|
||||
Menu,
|
||||
MenuItem,
|
||||
MenuDivider,
|
||||
Intent,
|
||||
Classes,
|
||||
} from '@blueprintjs/core';
|
||||
|
||||
import { Icon, If } from '@/components';
|
||||
import { safeCallback } from '@/utils';
|
||||
|
||||
const WAREHOUSES_SKELETON_N = 4;
|
||||
|
||||
/**
|
||||
* Warehouse grid item box context menu.
|
||||
* @returns {JSX.Element}
|
||||
*/
|
||||
export function WarehouseContextMenu({
|
||||
onEditClick,
|
||||
onDeleteClick,
|
||||
onMarkPrimary,
|
||||
warehouse,
|
||||
}) {
|
||||
return (
|
||||
<Menu>
|
||||
<MenuItem
|
||||
icon={<Icon icon="pen-18" />}
|
||||
text={intl.get('warehouses.action.edit_warehouse')}
|
||||
onClick={safeCallback(onEditClick)}
|
||||
/>
|
||||
<If condition={!warehouse.primary}>
|
||||
<MenuItem
|
||||
icon={<Icon icon={'check'} iconSize={18} />}
|
||||
text={intl.get('warehouses.action.make_as_parimary')}
|
||||
onClick={safeCallback(onMarkPrimary)}
|
||||
/>
|
||||
</If>
|
||||
<MenuDivider />
|
||||
<MenuItem
|
||||
text={intl.get('warehouses.action.delete_warehouse')}
|
||||
icon={<Icon icon="trash-16" iconSize={16} />}
|
||||
intent={Intent.DANGER}
|
||||
onClick={safeCallback(onDeleteClick)}
|
||||
/>
|
||||
</Menu>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Warehouse grid item box skeleton.
|
||||
* @returns {JSX.Element}
|
||||
*/
|
||||
function WarehouseGridItemSkeletonBox() {
|
||||
return (
|
||||
<WarehouseBoxRoot>
|
||||
<WarehouseHeader>
|
||||
<WarehouseTitle className={Classes.SKELETON}>X</WarehouseTitle>
|
||||
<WarehouseCode className={Classes.SKELETON}>X</WarehouseCode>
|
||||
</WarehouseHeader>
|
||||
|
||||
<WarehouseContent>
|
||||
<WarehouseItem className={Classes.SKELETON}>X</WarehouseItem>
|
||||
<WarehouseItem className={Classes.SKELETON}>X</WarehouseItem>
|
||||
</WarehouseContent>
|
||||
</WarehouseBoxRoot>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Warehouse grid item box.
|
||||
* @returns {JSX.Element}
|
||||
*/
|
||||
export function WarehousesGridItemBox({
|
||||
title,
|
||||
code,
|
||||
city,
|
||||
country,
|
||||
email,
|
||||
phoneNumber,
|
||||
primary,
|
||||
}) {
|
||||
return (
|
||||
<WarehouseBoxRoot>
|
||||
<WarehouseHeader>
|
||||
<WarehouseTitle>
|
||||
{title} {primary && <Icon icon={'star-18dp'} iconSize={16} />}
|
||||
</WarehouseTitle>
|
||||
<WarehouseCode>{code}</WarehouseCode>
|
||||
<WarehouseIcon>
|
||||
<Icon icon="warehouse-16" iconSize={20} />
|
||||
</WarehouseIcon>
|
||||
</WarehouseHeader>
|
||||
<WarehouseContent>
|
||||
{city && <WarehouseItem>{city}</WarehouseItem>}
|
||||
{country && <WarehouseItem>{country}</WarehouseItem>}
|
||||
{email && <WarehouseItem>{email}</WarehouseItem>}
|
||||
{phoneNumber && <WarehouseItem>{phoneNumber}</WarehouseItem>}
|
||||
</WarehouseContent>
|
||||
</WarehouseBoxRoot>
|
||||
);
|
||||
}
|
||||
|
||||
export function WarehousesSkeleton() {
|
||||
return [...Array(WAREHOUSES_SKELETON_N)].map((key, value) => (
|
||||
<WarehouseGridItemSkeletonBox />
|
||||
));
|
||||
}
|
||||
|
||||
export const WarehousesList = styled.div`
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin: 15px;
|
||||
height: 100%;
|
||||
`;
|
||||
|
||||
export const WarehouseBoxRoot = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-shrink: 0;
|
||||
border-radius: 5px;
|
||||
border: 1px solid #c8cad0;
|
||||
background: #fff;
|
||||
margin: 5px 5px 8px;
|
||||
width: 200px;
|
||||
height: 160px;
|
||||
transition: all 0.1s ease-in-out;
|
||||
padding: 12px;
|
||||
position: relative;
|
||||
|
||||
&:hover {
|
||||
border-color: #0153cc;
|
||||
}
|
||||
`;
|
||||
|
||||
export const WarehouseHeader = styled.div`
|
||||
position: relative;
|
||||
padding-right: 24px;
|
||||
padding-top: 2px;
|
||||
`;
|
||||
|
||||
export const WarehouseTitle = styled.div`
|
||||
font-size: 14px;
|
||||
font-style: inherit;
|
||||
color: #000;
|
||||
white-space: nowrap;
|
||||
font-weight: 500;
|
||||
line-height: 1;
|
||||
|
||||
.bp3-icon {
|
||||
margin: 0;
|
||||
margin-left: 2px;
|
||||
vertical-align: top;
|
||||
color: #e1b31d;
|
||||
}
|
||||
`;
|
||||
|
||||
const WarehouseCode = styled.div`
|
||||
display: block;
|
||||
font-size: 11px;
|
||||
color: #6b7176;
|
||||
margin-top: 4px;
|
||||
`;
|
||||
|
||||
const WarehouseIcon = styled.div`
|
||||
position: absolute;
|
||||
top: 0;
|
||||
color: #abb3bb;
|
||||
right: 0;
|
||||
`;
|
||||
|
||||
const WarehouseContent = styled.div`
|
||||
width: 100%;
|
||||
margin-top: auto;
|
||||
`;
|
||||
|
||||
const WarehouseItem = styled.div`
|
||||
font-size: 11px;
|
||||
color: #000;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
|
||||
&:not(:last-of-type) {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
`;
|
||||
@@ -0,0 +1,16 @@
|
||||
// @ts-nocheck
|
||||
import React from 'react';
|
||||
import { WarehousesProvider } from './WarehousesProvider';
|
||||
import Warehouses from './Warehouses';
|
||||
|
||||
/**
|
||||
* Warehouses Preferences.
|
||||
* @returns
|
||||
*/
|
||||
export default function WarehousesPerences() {
|
||||
return (
|
||||
<WarehousesProvider>
|
||||
<Warehouses />
|
||||
</WarehousesProvider>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
// @ts-nocheck
|
||||
import intl from 'react-intl-universal';
|
||||
import { Intent } from '@blueprintjs/core';
|
||||
import { AppToaster } from '@/components';
|
||||
|
||||
/**
|
||||
* Handle delete errors.
|
||||
*/
|
||||
export const handleDeleteErrors = (errors) => {
|
||||
if (
|
||||
errors.find((error) => error.type === 'COULD_NOT_DELETE_ONLY_WAERHOUSE')
|
||||
) {
|
||||
AppToaster.show({
|
||||
message: intl.get('warehouse.error.could_not_delete_only_waerhouse'),
|
||||
intent: Intent.DANGER,
|
||||
});
|
||||
}
|
||||
if (errors.some((e) => e.type === 'WAREHOUSE_HAS_ASSOCIATED_TRANSACTIONS')) {
|
||||
AppToaster.show({
|
||||
message: intl.get(
|
||||
'warehouse.error.warehouse_has_associated_transactions',
|
||||
),
|
||||
intent: Intent.DANGER,
|
||||
});
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user