Skip to content

Commit

Permalink
fix(cards): Show forecast preview in Sales pipeline (#4683)
Browse files Browse the repository at this point in the history
  • Loading branch information
ariunzayarin committed Oct 17, 2023
1 parent 2f99d1a commit ad3c058
Show file tree
Hide file tree
Showing 8 changed files with 213 additions and 212 deletions.
129 changes: 32 additions & 97 deletions packages/plugin-cards-ui/src/deals/components/CalendarColumn.tsx
Expand Up @@ -13,7 +13,7 @@ import styled from 'styled-components';
import options from '@erxes/ui-cards/src/deals/options';
import { IDeal, IDealTotalAmount } from '@erxes/ui-cards/src/deals/types';
import Deal from '@erxes/ui-cards/src/deals/components/DealItem';
import styledTS from 'styled-components-ts';
import ItemProductProbabilities from '@erxes/ui-cards/src/deals/components/ItemProductProbabilities';

type Props = {
deals: IDeal[];
Expand All @@ -23,23 +23,12 @@ type Props = {
onLoadMore: (skip: number) => void;
};

const Amount = styledTS<{ showAll: boolean }>(styled.ul)`
const Amount = styled.ul`
list-style: none;
overflow: hidden;
margin: 0 0 5px;
padding: 0 16px;
${props =>
props.showAll === false
? `
height: 20px;
overflow: hidden;
transition: all 300ms ease-out;
`
: `
height: unset;
`}
li {
padding-right: 5px;
font-size: 12px;
Expand Down Expand Up @@ -113,101 +102,47 @@ class DealColumn extends React.Component<Props, {}> {

renderTotalAmount() {
const { dealTotalAmounts, deals } = this.props;
const totalForType = dealTotalAmounts || [];

const forecastArray = [];
const totalAmountArray = [];
const totalForType = dealTotalAmounts || ([] as IDealTotalAmount[]);

dealTotalAmounts.map(total =>
total.currencies.map(currency => totalAmountArray.push(currency))
);

this.props.deals.map(deal => {
const probability =
deal.stage.probability === 'Won'
? '100%'
: deal.stage.probability === 'Lost'
? '0%'
: deal.stage.probability;

Object.keys(deal.amount).map(key =>
forecastArray.push({
name: key,
amount: deal.amount[key] as number,
probability: parseInt(probability, 10)
})
);
});

const detail = () => {
const renderDetail = () => {
if (!deals || deals.length === 0) {
return null;
}

if (
localStorage.getItem('showSalesDetail') === 'false' ||
!localStorage.getItem('showSalesDetail')
) {
return null;
}

return (
<>
<li>
<span>Total ({deals.length}): </span>
{this.renderPercentedAmount(totalAmountArray)}
</li>
<li>
<span>Forecasted: </span>
{this.renderPercentedAmount(forecastArray)}
</li>
<ItemProductProbabilities
dealTotalAmounts={totalForType}
deals={deals}
/>
{totalForType.map(type => {
if (type.name === 'In progress') {
return null;
}

const percent = type.name === 'Won' ? '100%' : '0%';

return (
<li key={type._id}>
<span>
{type.name} ({percent}){' '}
</span>
{this.renderAmount(type.currencies)}
</li>
);
})}
</>
);
};

return (
<Amount
showAll={
localStorage.getItem('showSalesDetail') === 'true' ? true : false
}
>
{detail()}
{totalForType.map(type => {
if (type.name === 'In progress') {
return null;
}

const percent = type.name === 'Won' ? '100%' : '0%';

return (
<li key={type._id}>
<span>
{type.name} ({percent}):{' '}
</span>
{this.renderAmount(type.currencies)}
</li>
);
})}
</Amount>
);
}

renderPercentedAmount(currencies) {
const sumByName = {};

currencies.forEach(item => {
const { name, amount, probability = 100 } = item;
if (sumByName[name] === undefined) {
sumByName[name] = (amount * probability) / 100;
} else {
sumByName[name] += (amount * probability) / 100;
}
});

return Object.keys(sumByName).map((key, index) => (
<div key={index}>
{sumByName[key].toLocaleString(undefined, {
maximumFractionDigits: 0
})}{' '}
<span>
{key}
{index < Object.keys(sumByName).length - 1 && ','}&nbsp;
</span>
</div>
));
return <Amount>{renderDetail()}</Amount>;
}

renderFooter() {
Expand Down
20 changes: 12 additions & 8 deletions packages/ui-cards/src/boards/components/MainActionBar.tsx
Expand Up @@ -67,7 +67,10 @@ class MainActionBar extends React.Component<Props, State> {
constructor(props: Props) {
super(props);

this.state = { showDetail: false };
this.state = {
showDetail:
localStorage.getItem('showSalesDetail') === 'true' ? true : false
};
}

renderBoards() {
Expand Down Expand Up @@ -267,12 +270,12 @@ class MainActionBar extends React.Component<Props, State> {
const type = options.type;
localStorage.setItem(`${type}View`, `${viewType}`);

const onFilterClick = (type: string) => {
const onFilterClick = (option: string) => {
if (currentBoard && currentPipeline) {
return `/${options.type}/${type}?id=${currentBoard._id}&pipelineId=${currentPipeline._id}`;
return `/${options.type}/${option}?id=${currentBoard._id}&pipelineId=${currentPipeline._id}`;
}

return `/${options.type}/${type}`;
return `/${options.type}/${option}`;
};

return (
Expand Down Expand Up @@ -382,10 +385,7 @@ class MainActionBar extends React.Component<Props, State> {
};

renderSalesDetail = () => {
if (
window.location.pathname.includes('deal/board') ||
window.location.pathname.includes('deal/calendar')
) {
if (window.location.pathname.includes('deal/calendar')) {
return (
<Button
btnStyle="link"
Expand Down Expand Up @@ -415,6 +415,10 @@ class MainActionBar extends React.Component<Props, State> {

const type = options.type;

if (!localStorage.getItem('showSalesDetail')) {
localStorage.setItem('showSalesDetail', `false`);
}

const actionBarLeft = (
<BarItems>
<HeaderLabel>
Expand Down
47 changes: 8 additions & 39 deletions packages/ui-cards/src/boards/components/stage/Stage.tsx
Expand Up @@ -9,13 +9,12 @@ import {
IndicatorItem,
LoadingContent,
StageFooter,
StageInfo,
StageRoot,
StageTitle
} from '../../styles/stage';
import { Dropdown, OverlayTrigger, Popover } from 'react-bootstrap';
import { IItem, IOptions, IStage } from '../../types';
import { renderAmount, renderPercentedAmount } from '../../utils';
import ItemProductProbabilities from '../../../deals/components/ItemProductProbabilities';

import { AddForm } from '../../containers/portable';
import { Draggable } from 'react-beautiful-dnd';
Expand Down Expand Up @@ -351,43 +350,13 @@ export default class Stage extends React.Component<Props, State> {
return <EmptyState icon="columns-1" text="No stage" size="small" />;
}

const probability =
stage.probability === 'Won'
? '100%'
: stage.probability === 'Lost'
? '0%'
: stage.probability;

const detail = () => {
if (
window.location.pathname.includes('deal') &&
Object.keys(stage.amount).length > 0
) {
const forecast = () => {
if (!probability) {
return null;
}

return (
<div>
<span>{__('Forecasted') + `(${probability}):`}</span>
{renderPercentedAmount(stage.amount, parseInt(probability, 10))}
</div>
);
};

const renderDetail = () => {
if (window.location.pathname.includes('deal')) {
return (
<StageInfo
showAll={
localStorage.getItem('showSalesDetail') === 'true' ? true : false
}
>
<div>
<span>{__('Total') + ':'}</span>
{renderAmount(stage.amount)}
</div>
{forecast()}
</StageInfo>
<ItemProductProbabilities
totalAmount={stage.amount}
probability={stage.probability}
/>
);
}

Expand All @@ -407,7 +376,7 @@ export default class Stage extends React.Component<Props, State> {
</div>
{this.renderCtrl()}
</StageTitle>
{detail()}
{renderDetail()}
<Indicator>{this.renderIndicator()}</Indicator>
</Header>
<Body innerRef={this.bodyRef} onScroll={this.onScroll}>
Expand Down
9 changes: 4 additions & 5 deletions packages/ui-cards/src/boards/containers/Stage.tsx
Expand Up @@ -11,7 +11,6 @@ import {
IFilterParams,
IItem,
IOptions,
IPipeline,
IStage,
ItemsQueryResponse,
RemoveStageMutation,
Expand Down Expand Up @@ -293,17 +292,17 @@ class WithData extends React.Component<StageProps> {
private withQuery;
private abortController;

componentWillUnmount() {
this.abortController.abort();
}

constructor(props) {
super(props);

this.withQuery = withQuery({ options: props.options });
this.abortController = new AbortController();
}

componentWillUnmount() {
this.abortController.abort();
}

render() {
const Component = this.withQuery;

Expand Down
21 changes: 4 additions & 17 deletions packages/ui-cards/src/boards/styles/stage.ts
Expand Up @@ -196,34 +196,21 @@ export const StageTitle = styled.h4`
}
`;

export const StageInfo = styledTS<{ showAll?: boolean }>(styled.div)`
export const StageInfo = styled.div`
margin-bottom: 10px;
${props =>
props.showAll === false
? `
height: 15px;
overflow: hidden;
transition: all 300ms ease-out;
`
: `
height: unset;
`}
div {
display: flex;
justify-content: space-between;
min-height: unset !important;
align-items: center;
}
> div {
margin-bottom: 5px;
}
span {
font-size: 11px;
font-weight: 600;
}
ul {
margin: 0;
li {
Expand Down

0 comments on commit ad3c058

Please sign in to comment.