Skip to content

Commit

Permalink
Minor cleanup + refactoring + some frontend tests (#513)
Browse files Browse the repository at this point in the history
* Minor cleanup, address lint warning, add utils.test.ts for frontend utils

* More cleanup

* Clean up handle_post_creation_conversation_updates
  • Loading branch information
reichert621 authored Jan 8, 2021
1 parent 397eaf4 commit b4c2212
Show file tree
Hide file tree
Showing 13 changed files with 218 additions and 66 deletions.
2 changes: 1 addition & 1 deletion assets/src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@ export const deleteCompany = async (id: string, token = getAccessToken()) => {

export const createNewConversation = async (
customerId: string,
params?: object,
params?: Record<any, any>,
token = getAccessToken()
) => {
if (!token) {
Expand Down
6 changes: 1 addition & 5 deletions assets/src/components/account/support.ts
Original file line number Diff line number Diff line change
Expand Up @@ -672,11 +672,7 @@ export const timezones: Array<Timezone> = [
},
];

/**
*
* @type {Array.<{ offset: string, label: string, tzCode: string }>}
*/
export var minimalTimezoneSet = [
export const minimalTimezoneSet: Array<Timezone> = [
{
offset: '-11:00',
label: '(GMT-11:00) Pago Pago',
Expand Down
2 changes: 2 additions & 0 deletions assets/src/components/common.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import Radio from 'antd/lib/radio';
import Result from 'antd/lib/result';
import Select from 'antd/lib/select';
import Spin from 'antd/lib/spin';
import Statistic from 'antd/lib/statistic';
import Table from 'antd/lib/table';
import Tag from 'antd/lib/tag';
import Tooltip from 'antd/lib/tooltip';
Expand Down Expand Up @@ -120,6 +121,7 @@ export {
Result,
Select,
Spin,
Statistic,
Table,
Tag,
Tooltip,
Expand Down
2 changes: 1 addition & 1 deletion assets/src/components/conversations/ChatMessageBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const renderers = {
type ChatMessageBoxProps = {
className?: string;
content: string;
sx?: object;
sx?: Record<any, any>;
};

const ChatMessageBox = ({className, content, sx}: ChatMessageBoxProps) => {
Expand Down
23 changes: 14 additions & 9 deletions assets/src/components/reporting/ReportingDashboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ import MessagesSentVsReceivedChart from './MessagesSentVsReceivedChart';
import MessagesByDayOfWeekChart from './MessagesByDayOfWeekChart';
import FirstResponseTimeByWeekChart from './FirstResponseTimeByWeekChart';
import CustomerBreakdownChart from './CustomerBreakdownChart';
import {ReportingDatum, secondsToHoursAndMinutes} from './support';
import {ReportingDatum} from './support';
import {formatSecondsToHoursAndMinutes} from '../../utils';
import logger from '../../logger';

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

formatCustomerBreakdownStats = (stats: Array<any>, field: string) => {
const MAX_NUM_SHOWN = 10;
const formatted = stats
.map((data) => ({
name: data[field] || 'Unknown',
value: data.count || 0,
}))
.sort((a, b) => b.value - a.value);

if (formatted.length <= 10) {
if (formatted.length <= MAX_NUM_SHOWN) {
return formatted;
}

const top = formatted.slice(0, 9);
const other = formatted.slice(9).reduce(
const top = formatted.slice(0, MAX_NUM_SHOWN - 1);
const other = formatted.slice(MAX_NUM_SHOWN - 1).reduce(
(acc, data) => {
return {...acc, value: acc.value + (data.value || 0)};
},
Expand Down Expand Up @@ -206,9 +208,11 @@ class ReportingDashboard extends React.Component<Props, State> {
};

formatResponseTimeStats = (responseTime: number) => {
const time = secondsToHoursAndMinutes(responseTime);
const [hour, minute, second] = time.split(':');
return `${hour} h ${minute} m ${second} s`;
const {hours, minutes, seconds} = formatSecondsToHoursAndMinutes(
responseTime
);

return `${hours} h ${minutes} m ${seconds} s`;
};

render() {
Expand Down Expand Up @@ -273,10 +277,11 @@ class ReportingDashboard extends React.Component<Props, State> {
<Box mb={2}>
<Text strong>Response Metrics</Text>
</Box>
{/* TODO: use antd <Statistic> instead? */}
<Box>
<Box mb={2}>
<Text>average first response time: </Text>
<Text style={{fontWeight: 'bold'}}>{responseTimeStats}</Text>
<Text>Average first response time: </Text>
<Text strong>{responseTimeStats}</Text>
</Box>
</Box>
<FirstResponseTimeByWeekChart data={responseTimeByWeekDay} />
Expand Down
5 changes: 0 additions & 5 deletions assets/src/components/reporting/support.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,3 @@ export const FAKE_DATA: Array<ReportingDatum> = [
conversations: 12,
},
];

export const secondsToHoursAndMinutes = (seconds: number) => {
//time would look like 00:01:20 if on average it takes 80.3 seconds to respond
return new Date(Math.round(seconds) * 1000).toISOString().substring(11, 19);
};
2 changes: 1 addition & 1 deletion assets/src/components/sessions/SessionsOverview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ class SessionsOverview extends React.Component<Props, State> {
}
};

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

return sessionStatusMetadataById[sessionId] || {};
Expand Down
144 changes: 144 additions & 0 deletions assets/src/utils.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
import dayjs from 'dayjs';
import {
formatRelativeTime,
formatDiffDuration,
formatSecondsToHoursAndMinutes,
formatSecondsToHoursAndMinutesV2,
} from './utils';

describe('formatRelativeTime', () => {
test('handles seconds correctly', () => {
const day = dayjs().subtract(10, 'second');

expect(formatRelativeTime(day)).toEqual('10 seconds ago');
});

test('handles minutes correctly', () => {
const day = dayjs().subtract(150, 'second');

expect(formatRelativeTime(day)).toEqual('2 minutes ago');
});

test('handles hours correctly', () => {
const day = dayjs().subtract(90, 'minute');

expect(formatRelativeTime(day)).toEqual('1 hour ago');
});

test('handles hours correctly', () => {
const day = dayjs().subtract(100, 'hour');

expect(formatRelativeTime(day)).toEqual('4 days ago');
});
});

describe('formatDiffDuration', () => {
test('handles seconds correctly', () => {
const start = dayjs();
const finish = dayjs().add(10, 'second');

expect(formatDiffDuration(start, finish)).toEqual('00:00:10');
});

test('handles minutes correctly', () => {
const start = dayjs();
const finish = dayjs().add(205, 'second');

expect(formatDiffDuration(start, finish)).toEqual('00:03:25');
});

test('handles hours correctly', () => {
const start = dayjs();
const finish = dayjs().add(400, 'minute');

expect(formatDiffDuration(start, finish)).toEqual('06:40:00');
});
});

describe('formatSecondsToHoursAndMinutes', () => {
test('handles seconds correctly', () => {
expect(formatSecondsToHoursAndMinutes(0)).toEqual({
hours: '00',
minutes: '00',
seconds: '00',
});

expect(formatSecondsToHoursAndMinutes(50)).toEqual({
hours: '00',
minutes: '00',
seconds: '50',
});
});

test('handles minutes correctly', () => {
expect(formatSecondsToHoursAndMinutes(60)).toEqual({
hours: '00',
minutes: '01',
seconds: '00',
});

expect(formatSecondsToHoursAndMinutes(80)).toEqual({
hours: '00',
minutes: '01',
seconds: '20',
});
});

test('handles hours correctly', () => {
expect(formatSecondsToHoursAndMinutes(3600)).toEqual({
hours: '01',
minutes: '00',
seconds: '00',
});

expect(formatSecondsToHoursAndMinutes(4000)).toEqual({
hours: '01',
minutes: '06',
seconds: '40',
});
});
});

describe('formatSecondsToHoursAndMinutesV2', () => {
test('handles seconds correctly', () => {
expect(formatSecondsToHoursAndMinutesV2(0)).toEqual({
hours: '00',
minutes: '00',
seconds: '00',
});

expect(formatSecondsToHoursAndMinutesV2(50)).toEqual({
hours: '00',
minutes: '00',
seconds: '50',
});
});

test('handles minutes correctly', () => {
expect(formatSecondsToHoursAndMinutesV2(60)).toEqual({
hours: '00',
minutes: '01',
seconds: '00',
});

expect(formatSecondsToHoursAndMinutesV2(80)).toEqual({
hours: '00',
minutes: '01',
seconds: '20',
});
});

test('handles hours correctly', () => {
expect(formatSecondsToHoursAndMinutesV2(3600)).toEqual({
hours: '01',
minutes: '00',
seconds: '00',
});

expect(formatSecondsToHoursAndMinutesV2(4000)).toEqual({
hours: '01',
minutes: '06',
seconds: '40',
});
});
});
31 changes: 29 additions & 2 deletions assets/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,39 @@ export const formatDiffDuration = (start: dayjs.Dayjs, finish: dayjs.Dayjs) => {
const diff = finish.diff(start, 's');
const seconds = diff % 60;
const mins = Math.floor(diff / 60) % 60;
const hrs = Math.floor(mins / 60);
const hrs = Math.floor(diff / 60 / 60);
const format = (n: number) => String(n).padStart(2, '0');

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

export const formatSecondsToHoursAndMinutes = (secs: number) => {
// time would look like 00:01:20 if on average it takes 80.3 seconds to respond
const time = new Date(Math.round(secs) * 1000)
.toISOString()
.substring(11, 19);
const [hours, minutes, seconds] = time.split(':');

return {hours, minutes, seconds};
};

const defaultFormatterFn = (n: number) => String(n).padStart(2, '0');

export const formatSecondsToHoursAndMinutesV2 = (
secs: number,
formatter = defaultFormatterFn
) => {
const seconds = secs % 60;
const minutes = Math.floor(secs / 60) % 60;
const hours = Math.floor(secs / 60 / 60);

return {
hours: formatter(hours),
minutes: formatter(minutes),
seconds: formatter(seconds),
};
};

export const isValidUuid = (id: any) => {
if (!id || typeof id !== 'string' || !id.length) {
return false;
Expand All @@ -50,7 +77,7 @@ export const isValidUuid = (id: any) => {
return regex.test(id);
};

export const updateQueryParams = (query: object) => {
export const updateQueryParams = (query: Record<any, any>) => {
if (window.history.pushState) {
window.history.pushState(
null,
Expand Down
7 changes: 5 additions & 2 deletions lib/chat_api/messages/helpers.ex
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,12 @@ defmodule ChatApi.Messages.Helpers do
end

@spec build_first_reply_updates(map(), Message.t()) :: map()
defp build_first_reply_updates(updates, %Message{user_id: assignee_id} = message) do
defp build_first_reply_updates(
updates,
%Message{user_id: assignee_id, inserted_at: first_replied_at} = message
) do
if is_first_agent_reply?(message) do
Map.merge(updates, %{assignee_id: assignee_id})
Map.merge(updates, %{assignee_id: assignee_id, first_replied_at: first_replied_at})
else
updates
end
Expand Down
Loading

0 comments on commit b4c2212

Please sign in to comment.