Skip to content

Commit 4c9abd2

Browse files
authored
Merge pull request #3005 from irontec/PROVIDER-2323-fix-pricing-simulator-multiple-plans-graceful-errors
[PROVIDER-2323] Fix pricing simulator to show partial results with multiple plans
2 parents b3c8bdf + 2127462 commit 4c9abd2

File tree

6 files changed

+240
-182
lines changed

6 files changed

+240
-182
lines changed

web/portal/brand/src/entities/RatingPlanGroup/Action/SimulateCall.tsx

Lines changed: 118 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@ import {
1010
} from '@irontec/ivoz-ui/components/shared/Button/Button.styles';
1111
import {
1212
ActionFunctionComponent,
13-
GlobalActionItemProps,
13+
ActionItemProps,
1414
isSingleRowAction,
15+
MultiSelectActionItemProps,
1516
} from '@irontec/ivoz-ui/router/routeMapParser';
1617
import { StyledTextField } from '@irontec/ivoz-ui/services/form/Field/TextField/TextField.styles';
1718
import _ from '@irontec/ivoz-ui/services/translations/translate';
@@ -47,14 +48,25 @@ type SimulateCallResponseType = {
4748
};
4849

4950
const SimulateCall: ActionFunctionComponent = (
50-
props: GlobalActionItemProps
51+
props: MultiSelectActionItemProps | ActionItemProps
5152
) => {
53+
const {
54+
selectedValues = [],
55+
rows = [],
56+
variant = 'icon',
57+
} = props as MultiSelectActionItemProps;
58+
const { row } = props as ActionItemProps;
59+
const isSingleRow = isSingleRowAction(props);
60+
5261
/* eslint-disable react-hooks/rules-of-hooks */
53-
if (isSingleRowAction(props)) {
62+
if (isSingleRow) {
5463
return <span className='display-none'></span>;
5564
}
5665

57-
const { rows, variant = 'icon' } = props;
66+
const selectedIds =
67+
selectedValues.length > 0
68+
? selectedValues
69+
: rows.map((row) => row.id.toString());
5870

5971
const [open, setOpen] = useState(false);
6072
const [error, setError] = useState(false);
@@ -86,11 +98,12 @@ const SimulateCall: ActionFunctionComponent = (
8698
};
8799

88100
const handleUpdate = () => {
101+
setCost(undefined);
89102
const promises = [];
90-
for (const row of rows) {
103+
for (const id of selectedIds) {
91104
promises.push(
92105
apiPost({
93-
path: `${RatingPlanGroup.path}/${row.id}/simulate_call`,
106+
path: `${RatingPlanGroup.path}/${id}/simulate_call`,
94107
values: {
95108
number: phoneNumber,
96109
duration,
@@ -101,15 +114,33 @@ const SimulateCall: ActionFunctionComponent = (
101114
);
102115
}
103116

104-
Promise.all(promises)
105-
.then((values) => {
106-
setCost(values.map((row) => row.data as SimulateCallResponseType));
107-
})
108-
.catch((error) => {
109-
console.error('error', error);
110-
setError(true);
111-
setErrorMsg(error.data.detail || error.data.title);
117+
Promise.allSettled(promises).then((results) => {
118+
const successfulResults: SimulateCallResponseType[] = [];
119+
const errorMessages: string[] = [];
120+
121+
results.forEach((result, index) => {
122+
if (result.status === 'fulfilled') {
123+
successfulResults.push(result.value.data);
124+
} else {
125+
const errorDetail = result.reason?.data?.detail;
126+
if (errorDetail) {
127+
errorMessages.push(`Plan ID ${selectedIds[index]}: ${errorDetail}`);
128+
}
129+
}
112130
});
131+
132+
if (successfulResults.length > 0) {
133+
setCost(successfulResults);
134+
setError(false);
135+
setErrorMsg('');
136+
} else if (errorMessages.length > 0) {
137+
setError(true);
138+
setErrorMsg(
139+
_('No rating plan group can rate a call to introduced destination')
140+
);
141+
setCost(undefined);
142+
}
143+
});
113144
};
114145

115146
const boxStyles = {
@@ -146,84 +177,80 @@ const SimulateCall: ActionFunctionComponent = (
146177
{_('Simulate call')} {cost ? `(${phoneNumber})` : ''}
147178
</DialogTitle>
148179
<DialogContent sx={{ textAlign: 'left!important' }}>
149-
{!error && (
150-
<>
151-
{!cost && (
152-
<Box>
153-
<Box sx={boxStyles}>
154-
<StyledTextField
155-
type='text'
156-
required={true}
157-
label={_('Phone number')}
158-
placeholder='+34987654321'
159-
value={phoneNumber}
160-
onChange={(event) => {
161-
const { value } = event.target;
162-
setPhoneNumber(value);
163-
}}
164-
hasChanged={false}
165-
/>
166-
</Box>
167-
<Box sx={boxStyles}>
168-
<StyledTextField
169-
type='number'
170-
required={true}
171-
label={_('Duration (seconds)')}
172-
value={duration}
173-
onChange={(event) => {
174-
const { value } = event.target;
175-
setDuration(parseInt(value, 10));
176-
}}
177-
hasChanged={false}
178-
/>
179-
</Box>
180-
</Box>
181-
)}
182-
{cost && (
183-
<Box>
184-
<StyledTable size='small'>
185-
<TableHead>
186-
<TableRow>
187-
<TableCell>{_('Plan')}</TableCell>
188-
<TableCell>{_('Start time')}</TableCell>
189-
<TableCell>{_('Duration')}</TableCell>
190-
<TableCell>{_('Destination')}</TableCell>
191-
<TableCell>{_('Connection fee')}</TableCell>
192-
<TableCell>{_('Interval start')}</TableCell>
193-
<TableCell>{_('Price')}</TableCell>
194-
<TableCell>{_('Total')}</TableCell>
180+
{!error && !cost && (
181+
<Box>
182+
<Box sx={boxStyles}>
183+
<StyledTextField
184+
type='text'
185+
required={true}
186+
label={_('Phone number')}
187+
placeholder='+34987654321'
188+
value={phoneNumber}
189+
onChange={(event) => {
190+
const { value } = event.target;
191+
setPhoneNumber(value);
192+
}}
193+
hasChanged={false}
194+
/>
195+
</Box>
196+
<Box sx={boxStyles}>
197+
<StyledTextField
198+
type='number'
199+
required={true}
200+
label={_('Duration (seconds)')}
201+
value={duration}
202+
onChange={(event) => {
203+
const { value } = event.target;
204+
setDuration(parseInt(value, 10));
205+
}}
206+
hasChanged={false}
207+
/>
208+
</Box>
209+
</Box>
210+
)}
211+
{cost && cost.length > 0 && (
212+
<Box>
213+
<StyledTable size='small'>
214+
<TableHead>
215+
<TableRow>
216+
<TableCell>{_('Plan')}</TableCell>
217+
<TableCell>{_('Start time')}</TableCell>
218+
<TableCell>{_('Duration')}</TableCell>
219+
<TableCell>{_('Destination')}</TableCell>
220+
<TableCell>{_('Connection fee')}</TableCell>
221+
<TableCell>{_('Interval start')}</TableCell>
222+
<TableCell>{_('Price')}</TableCell>
223+
<TableCell>{_('Total')}</TableCell>
224+
</TableRow>
225+
</TableHead>
226+
<TableBody>
227+
{cost.map((row, idx) => {
228+
const rate = row.rate
229+
? `${row.rate} ${row.currencySymbol} / ${row.ratePeriod}`
230+
: '';
231+
232+
return (
233+
<TableRow key={idx}>
234+
<TableCell>{row.plan}</TableCell>
235+
<TableCell>{row.callDate}</TableCell>
236+
<TableCell>{row.duration}</TableCell>
237+
<TableCell>{row.patternName}</TableCell>
238+
<TableCell>
239+
{row.connectionCharge} {row.currencySymbol}
240+
</TableCell>
241+
<TableCell>{row.intervalStart}</TableCell>
242+
<TableCell>
243+
{rate} {rate ? _('Seconds') : ''}
244+
</TableCell>
245+
<TableCell>
246+
{row.totalCost} {row.currencySymbol}
247+
</TableCell>
195248
</TableRow>
196-
</TableHead>
197-
<TableBody>
198-
{cost.map((row, idx) => {
199-
const rate = row.rate
200-
? `${row.rate} ${row.currencySymbol} / ${row.ratePeriod}`
201-
: '';
202-
203-
return (
204-
<TableRow key={idx}>
205-
<TableCell>{row.plan}</TableCell>
206-
<TableCell>{row.callDate}</TableCell>
207-
<TableCell>{row.duration}</TableCell>
208-
<TableCell>{row.patternName}</TableCell>
209-
<TableCell>
210-
{row.connectionCharge} {row.currencySymbol}
211-
</TableCell>
212-
<TableCell>{row.intervalStart}</TableCell>
213-
<TableCell>
214-
{rate} {rate ? _('Seconds') : ''}
215-
</TableCell>
216-
<TableCell>
217-
{row.totalCost} {row.currencySymbol}
218-
</TableCell>
219-
</TableRow>
220-
);
221-
})}
222-
</TableBody>
223-
</StyledTable>
224-
</Box>
225-
)}
226-
</>
249+
);
250+
})}
251+
</TableBody>
252+
</StyledTable>
253+
</Box>
227254
)}
228255
{error && <ErrorMessageComponent message={errorMsg} />}
229256
</DialogContent>

0 commit comments

Comments
 (0)