Skip to content

Commit b4c2212

Browse files
authored
Minor cleanup + refactoring + some frontend tests (#513)
* Minor cleanup, address lint warning, add utils.test.ts for frontend utils * More cleanup * Clean up handle_post_creation_conversation_updates
1 parent 397eaf4 commit b4c2212

File tree

13 files changed

+218
-66
lines changed

13 files changed

+218
-66
lines changed

assets/src/api.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,7 @@ export const deleteCompany = async (id: string, token = getAccessToken()) => {
260260

261261
export const createNewConversation = async (
262262
customerId: string,
263-
params?: object,
263+
params?: Record<any, any>,
264264
token = getAccessToken()
265265
) => {
266266
if (!token) {

assets/src/components/account/support.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -672,11 +672,7 @@ export const timezones: Array<Timezone> = [
672672
},
673673
];
674674

675-
/**
676-
*
677-
* @type {Array.<{ offset: string, label: string, tzCode: string }>}
678-
*/
679-
export var minimalTimezoneSet = [
675+
export const minimalTimezoneSet: Array<Timezone> = [
680676
{
681677
offset: '-11:00',
682678
label: '(GMT-11:00) Pago Pago',

assets/src/components/common.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import Radio from 'antd/lib/radio';
1616
import Result from 'antd/lib/result';
1717
import Select from 'antd/lib/select';
1818
import Spin from 'antd/lib/spin';
19+
import Statistic from 'antd/lib/statistic';
1920
import Table from 'antd/lib/table';
2021
import Tag from 'antd/lib/tag';
2122
import Tooltip from 'antd/lib/tooltip';
@@ -120,6 +121,7 @@ export {
120121
Result,
121122
Select,
122123
Spin,
124+
Statistic,
123125
Table,
124126
Tag,
125127
Tooltip,

assets/src/components/conversations/ChatMessageBox.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ const renderers = {
1414
type ChatMessageBoxProps = {
1515
className?: string;
1616
content: string;
17-
sx?: object;
17+
sx?: Record<any, any>;
1818
};
1919

2020
const ChatMessageBox = ({className, content, sx}: ChatMessageBoxProps) => {

assets/src/components/reporting/ReportingDashboard.tsx

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ import MessagesSentVsReceivedChart from './MessagesSentVsReceivedChart';
99
import MessagesByDayOfWeekChart from './MessagesByDayOfWeekChart';
1010
import FirstResponseTimeByWeekChart from './FirstResponseTimeByWeekChart';
1111
import CustomerBreakdownChart from './CustomerBreakdownChart';
12-
import {ReportingDatum, secondsToHoursAndMinutes} from './support';
12+
import {ReportingDatum} from './support';
13+
import {formatSecondsToHoursAndMinutes} from '../../utils';
1314
import logger from '../../logger';
1415

1516
type DateCount = {
@@ -114,19 +115,20 @@ class ReportingDashboard extends React.Component<Props, State> {
114115
};
115116

116117
formatCustomerBreakdownStats = (stats: Array<any>, field: string) => {
118+
const MAX_NUM_SHOWN = 10;
117119
const formatted = stats
118120
.map((data) => ({
119121
name: data[field] || 'Unknown',
120122
value: data.count || 0,
121123
}))
122124
.sort((a, b) => b.value - a.value);
123125

124-
if (formatted.length <= 10) {
126+
if (formatted.length <= MAX_NUM_SHOWN) {
125127
return formatted;
126128
}
127129

128-
const top = formatted.slice(0, 9);
129-
const other = formatted.slice(9).reduce(
130+
const top = formatted.slice(0, MAX_NUM_SHOWN - 1);
131+
const other = formatted.slice(MAX_NUM_SHOWN - 1).reduce(
130132
(acc, data) => {
131133
return {...acc, value: acc.value + (data.value || 0)};
132134
},
@@ -206,9 +208,11 @@ class ReportingDashboard extends React.Component<Props, State> {
206208
};
207209

208210
formatResponseTimeStats = (responseTime: number) => {
209-
const time = secondsToHoursAndMinutes(responseTime);
210-
const [hour, minute, second] = time.split(':');
211-
return `${hour} h ${minute} m ${second} s`;
211+
const {hours, minutes, seconds} = formatSecondsToHoursAndMinutes(
212+
responseTime
213+
);
214+
215+
return `${hours} h ${minutes} m ${seconds} s`;
212216
};
213217

214218
render() {
@@ -273,10 +277,11 @@ class ReportingDashboard extends React.Component<Props, State> {
273277
<Box mb={2}>
274278
<Text strong>Response Metrics</Text>
275279
</Box>
280+
{/* TODO: use antd <Statistic> instead? */}
276281
<Box>
277282
<Box mb={2}>
278-
<Text>average first response time: </Text>
279-
<Text style={{fontWeight: 'bold'}}>{responseTimeStats}</Text>
283+
<Text>Average first response time: </Text>
284+
<Text strong>{responseTimeStats}</Text>
280285
</Box>
281286
</Box>
282287
<FirstResponseTimeByWeekChart data={responseTimeByWeekDay} />

assets/src/components/reporting/support.ts

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,3 @@ export const FAKE_DATA: Array<ReportingDatum> = [
8181
conversations: 12,
8282
},
8383
];
84-
85-
export const secondsToHoursAndMinutes = (seconds: number) => {
86-
//time would look like 00:01:20 if on average it takes 80.3 seconds to respond
87-
return new Date(Math.round(seconds) * 1000).toISOString().substring(11, 19);
88-
};

assets/src/components/sessions/SessionsOverview.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ class SessionsOverview extends React.Component<Props, State> {
121121
}
122122
};
123123

124-
getSessionActiveMetadata = (sessionId: string): object => {
124+
getSessionActiveMetadata = (sessionId: string): Record<string, any> => {
125125
const {sessionStatusMetadataById = {}} = this.state;
126126

127127
return sessionStatusMetadataById[sessionId] || {};

assets/src/utils.test.ts

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
import dayjs from 'dayjs';
2+
import {
3+
formatRelativeTime,
4+
formatDiffDuration,
5+
formatSecondsToHoursAndMinutes,
6+
formatSecondsToHoursAndMinutesV2,
7+
} from './utils';
8+
9+
describe('formatRelativeTime', () => {
10+
test('handles seconds correctly', () => {
11+
const day = dayjs().subtract(10, 'second');
12+
13+
expect(formatRelativeTime(day)).toEqual('10 seconds ago');
14+
});
15+
16+
test('handles minutes correctly', () => {
17+
const day = dayjs().subtract(150, 'second');
18+
19+
expect(formatRelativeTime(day)).toEqual('2 minutes ago');
20+
});
21+
22+
test('handles hours correctly', () => {
23+
const day = dayjs().subtract(90, 'minute');
24+
25+
expect(formatRelativeTime(day)).toEqual('1 hour ago');
26+
});
27+
28+
test('handles hours correctly', () => {
29+
const day = dayjs().subtract(100, 'hour');
30+
31+
expect(formatRelativeTime(day)).toEqual('4 days ago');
32+
});
33+
});
34+
35+
describe('formatDiffDuration', () => {
36+
test('handles seconds correctly', () => {
37+
const start = dayjs();
38+
const finish = dayjs().add(10, 'second');
39+
40+
expect(formatDiffDuration(start, finish)).toEqual('00:00:10');
41+
});
42+
43+
test('handles minutes correctly', () => {
44+
const start = dayjs();
45+
const finish = dayjs().add(205, 'second');
46+
47+
expect(formatDiffDuration(start, finish)).toEqual('00:03:25');
48+
});
49+
50+
test('handles hours correctly', () => {
51+
const start = dayjs();
52+
const finish = dayjs().add(400, 'minute');
53+
54+
expect(formatDiffDuration(start, finish)).toEqual('06:40:00');
55+
});
56+
});
57+
58+
describe('formatSecondsToHoursAndMinutes', () => {
59+
test('handles seconds correctly', () => {
60+
expect(formatSecondsToHoursAndMinutes(0)).toEqual({
61+
hours: '00',
62+
minutes: '00',
63+
seconds: '00',
64+
});
65+
66+
expect(formatSecondsToHoursAndMinutes(50)).toEqual({
67+
hours: '00',
68+
minutes: '00',
69+
seconds: '50',
70+
});
71+
});
72+
73+
test('handles minutes correctly', () => {
74+
expect(formatSecondsToHoursAndMinutes(60)).toEqual({
75+
hours: '00',
76+
minutes: '01',
77+
seconds: '00',
78+
});
79+
80+
expect(formatSecondsToHoursAndMinutes(80)).toEqual({
81+
hours: '00',
82+
minutes: '01',
83+
seconds: '20',
84+
});
85+
});
86+
87+
test('handles hours correctly', () => {
88+
expect(formatSecondsToHoursAndMinutes(3600)).toEqual({
89+
hours: '01',
90+
minutes: '00',
91+
seconds: '00',
92+
});
93+
94+
expect(formatSecondsToHoursAndMinutes(4000)).toEqual({
95+
hours: '01',
96+
minutes: '06',
97+
seconds: '40',
98+
});
99+
});
100+
});
101+
102+
describe('formatSecondsToHoursAndMinutesV2', () => {
103+
test('handles seconds correctly', () => {
104+
expect(formatSecondsToHoursAndMinutesV2(0)).toEqual({
105+
hours: '00',
106+
minutes: '00',
107+
seconds: '00',
108+
});
109+
110+
expect(formatSecondsToHoursAndMinutesV2(50)).toEqual({
111+
hours: '00',
112+
minutes: '00',
113+
seconds: '50',
114+
});
115+
});
116+
117+
test('handles minutes correctly', () => {
118+
expect(formatSecondsToHoursAndMinutesV2(60)).toEqual({
119+
hours: '00',
120+
minutes: '01',
121+
seconds: '00',
122+
});
123+
124+
expect(formatSecondsToHoursAndMinutesV2(80)).toEqual({
125+
hours: '00',
126+
minutes: '01',
127+
seconds: '20',
128+
});
129+
});
130+
131+
test('handles hours correctly', () => {
132+
expect(formatSecondsToHoursAndMinutesV2(3600)).toEqual({
133+
hours: '01',
134+
minutes: '00',
135+
seconds: '00',
136+
});
137+
138+
expect(formatSecondsToHoursAndMinutesV2(4000)).toEqual({
139+
hours: '01',
140+
minutes: '06',
141+
seconds: '40',
142+
});
143+
});
144+
});

assets/src/utils.ts

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,39 @@ export const formatDiffDuration = (start: dayjs.Dayjs, finish: dayjs.Dayjs) => {
3434
const diff = finish.diff(start, 's');
3535
const seconds = diff % 60;
3636
const mins = Math.floor(diff / 60) % 60;
37-
const hrs = Math.floor(mins / 60);
37+
const hrs = Math.floor(diff / 60 / 60);
3838
const format = (n: number) => String(n).padStart(2, '0');
3939

4040
return `${format(hrs)}:${format(mins)}:${format(seconds)}`;
4141
};
4242

43+
export const formatSecondsToHoursAndMinutes = (secs: number) => {
44+
// time would look like 00:01:20 if on average it takes 80.3 seconds to respond
45+
const time = new Date(Math.round(secs) * 1000)
46+
.toISOString()
47+
.substring(11, 19);
48+
const [hours, minutes, seconds] = time.split(':');
49+
50+
return {hours, minutes, seconds};
51+
};
52+
53+
const defaultFormatterFn = (n: number) => String(n).padStart(2, '0');
54+
55+
export const formatSecondsToHoursAndMinutesV2 = (
56+
secs: number,
57+
formatter = defaultFormatterFn
58+
) => {
59+
const seconds = secs % 60;
60+
const minutes = Math.floor(secs / 60) % 60;
61+
const hours = Math.floor(secs / 60 / 60);
62+
63+
return {
64+
hours: formatter(hours),
65+
minutes: formatter(minutes),
66+
seconds: formatter(seconds),
67+
};
68+
};
69+
4370
export const isValidUuid = (id: any) => {
4471
if (!id || typeof id !== 'string' || !id.length) {
4572
return false;
@@ -50,7 +77,7 @@ export const isValidUuid = (id: any) => {
5077
return regex.test(id);
5178
};
5279

53-
export const updateQueryParams = (query: object) => {
80+
export const updateQueryParams = (query: Record<any, any>) => {
5481
if (window.history.pushState) {
5582
window.history.pushState(
5683
null,

lib/chat_api/messages/helpers.ex

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,12 @@ defmodule ChatApi.Messages.Helpers do
4141
end
4242

4343
@spec build_first_reply_updates(map(), Message.t()) :: map()
44-
defp build_first_reply_updates(updates, %Message{user_id: assignee_id} = message) do
44+
defp build_first_reply_updates(
45+
updates,
46+
%Message{user_id: assignee_id, inserted_at: first_replied_at} = message
47+
) do
4548
if is_first_agent_reply?(message) do
46-
Map.merge(updates, %{assignee_id: assignee_id})
49+
Map.merge(updates, %{assignee_id: assignee_id, first_replied_at: first_replied_at})
4750
else
4851
updates
4952
end

0 commit comments

Comments
 (0)