feat: Improve the rendering of CSV exports (#8914)

Improve the rendering of the datestamp
This commit is contained in:
Pranav Raj S
2024-02-12 20:01:58 -08:00
committed by GitHub
parent 33a6ad9f7e
commit c607f09be0
9 changed files with 139 additions and 19 deletions

View File

@@ -45,12 +45,8 @@ module Api::V2::Accounts::ReportsHelper
def generate_readable_report_metrics(report_metric) def generate_readable_report_metrics(report_metric)
[ [
report_metric[:conversations_count], report_metric[:conversations_count],
time_to_minutes(report_metric[:avg_first_response_time]), Reports::TimeFormatPresenter.new(report_metric[:avg_first_response_time]).format,
time_to_minutes(report_metric[:avg_resolution_time]) Reports::TimeFormatPresenter.new(report_metric[:avg_resolution_time]).format
] ]
end end
def time_to_minutes(time_in_seconds)
(time_in_seconds / 60).to_i
end
end end

View File

@@ -0,0 +1,33 @@
class Reports::TimeFormatPresenter
include ActionView::Helpers::TextHelper
attr_reader :seconds
def initialize(seconds)
@seconds = seconds.to_i
end
def format
return '--' if seconds.nil? || seconds.zero?
days, remainder = seconds.divmod(86_400)
hours, remainder = remainder.divmod(3600)
minutes, seconds = remainder.divmod(60)
format_components(days: days, hours: hours, minutes: minutes, seconds: seconds)
end
private
def format_components(components)
formatted_components = components.filter_map do |unit, value|
next if value.zero?
I18n.t("time_units.#{unit}", count: value)
end
return I18n.t('time_units.seconds', count: 0) if formatted_components.empty?
formatted_components.first(2).join(' ')
end
end

View File

@@ -1,3 +1,5 @@
<%= CSVSafe.generate_line [I18n.t('reports.period', since: Date.strptime(params[:since], '%s'), until: Date.strptime(params[:until], '%s'))] %>
<% headers = [ <% headers = [
I18n.t('reports.agent_csv.agent_name'), I18n.t('reports.agent_csv.agent_name'),
I18n.t('reports.agent_csv.conversations_count'), I18n.t('reports.agent_csv.conversations_count'),
@@ -9,4 +11,3 @@
<% @report_data.each do |row| %> <% @report_data.each do |row| %>
<%= CSVSafe.generate_line row -%> <%= CSVSafe.generate_line row -%>
<% end %> <% end %>
<%= CSVSafe.generate_line [I18n.t('reports.period', since: Date.strptime(params[:since], '%s'), until: Date.strptime(params[:until], '%s'))] %>

View File

@@ -1,4 +1,5 @@
<%= CSV.generate_line [I18n.t('reports.conversation_traffic_csv.timezone'), @timezone] %> <%= CSV.generate_line [I18n.t('reports.conversation_traffic_csv.timezone'), @timezone] %>
<% @report_data.each do |row| %> <% @report_data.each do |row| %>
<%= CSVSafe.generate_line row -%> <%= CSVSafe.generate_line row -%>
<% end %> <% end %>

View File

@@ -1,3 +1,5 @@
<%= CSVSafe.generate_line [I18n.t('reports.period', since: Date.strptime(params[:since], '%s'), until: Date.strptime(params[:until], '%s'))] %>
<% headers = [ <% headers = [
I18n.t('reports.inbox_csv.inbox_name'), I18n.t('reports.inbox_csv.inbox_name'),
I18n.t('reports.inbox_csv.inbox_type'), I18n.t('reports.inbox_csv.inbox_type'),
@@ -10,4 +12,3 @@
<% @report_data.each do |row| %> <% @report_data.each do |row| %>
<%= CSVSafe.generate_line row -%> <%= CSVSafe.generate_line row -%>
<% end %> <% end %>
<%= CSVSafe.generate_line [I18n.t('reports.period', since: Date.strptime(params[:since], '%s'), until: Date.strptime(params[:until], '%s'))] %>

View File

@@ -1,3 +1,5 @@
<%= CSVSafe.generate_line [I18n.t('reports.period', since: Date.strptime(params[:since], '%s'), until: Date.strptime(params[:until], '%s'))] %>
<% headers = [ <% headers = [
I18n.t('reports.label_csv.label_title'), I18n.t('reports.label_csv.label_title'),
I18n.t('reports.label_csv.conversations_count'), I18n.t('reports.label_csv.conversations_count'),
@@ -9,4 +11,3 @@
<% @report_data.each do |row| %> <% @report_data.each do |row| %>
<%= CSVSafe.generate_line row -%> <%= CSVSafe.generate_line row -%>
<% end %> <% end %>
<%= CSVSafe.generate_line [I18n.t('reports.period', since: Date.strptime(params[:since], '%s'), until: Date.strptime(params[:until], '%s'))] %>

View File

@@ -1,3 +1,5 @@
<%= CSVSafe.generate_line [I18n.t('reports.period', since: Date.strptime(params[:since], '%s'), until: Date.strptime(params[:until], '%s'))] %>
<% headers = [ <% headers = [
I18n.t('reports.team_csv.team_name'), I18n.t('reports.team_csv.team_name'),
I18n.t('reports.team_csv.conversations_count'), I18n.t('reports.team_csv.conversations_count'),
@@ -9,4 +11,3 @@
<% @report_data.each do |row| %> <% @report_data.each do |row| %>
<%= CSVSafe.generate_line row -%> <%= CSVSafe.generate_line row -%>
<% end %> <% end %>
<%= CSVSafe.generate_line [I18n.t('reports.period', since: Date.strptime(params[:since], '%s'), until: Date.strptime(params[:until], '%s'))] %>

View File

@@ -83,25 +83,25 @@ en:
utc_warning: The report generated is in UTC timezone utc_warning: The report generated is in UTC timezone
agent_csv: agent_csv:
agent_name: Agent name agent_name: Agent name
conversations_count: Conversations count conversations_count: Assigned conversations
avg_first_response_time: Avg first response time (Minutes) avg_first_response_time: Avg first response time
avg_resolution_time: Avg resolution time (Minutes) avg_resolution_time: Avg resolution time
inbox_csv: inbox_csv:
inbox_name: Inbox name inbox_name: Inbox name
inbox_type: Inbox type inbox_type: Inbox type
conversations_count: No. of conversations conversations_count: No. of conversations
avg_first_response_time: Avg first response time (Minutes) avg_first_response_time: Avg first response time
avg_resolution_time: Avg resolution time (Minutes) avg_resolution_time: Avg resolution time
label_csv: label_csv:
label_title: Label label_title: Label
conversations_count: No. of conversations conversations_count: No. of conversations
avg_first_response_time: Avg first response time (Minutes) avg_first_response_time: Avg first response time
avg_resolution_time: Avg resolution time (Minutes) avg_resolution_time: Avg resolution time
team_csv: team_csv:
team_name: Team name team_name: Team name
conversations_count: Conversations count conversations_count: Conversations count
avg_first_response_time: Avg first response time (Minutes) avg_first_response_time: Avg first response time
avg_resolution_time: Avg resolution time (Minutes) avg_resolution_time: Avg resolution time
conversation_traffic_csv: conversation_traffic_csv:
timezone: Timezone timezone: Timezone
default_group_by: day default_group_by: day
@@ -245,3 +245,16 @@ en:
inbox_name: Inbox inbox_name: Inbox
inbox_type: Inbox Type inbox_type: Inbox Type
button: Open conversation button: Open conversation
time_units:
days:
one: "%{count} day"
other: "%{count} days"
hours:
one: "%{count} hour"
other: "%{count} hours"
minutes:
one: "%{count} minute"
other: "%{count} minutes"
seconds:
one: "%{count} second"
other: "%{count} seconds"

View File

@@ -0,0 +1,73 @@
require 'rails_helper'
RSpec.describe Reports::TimeFormatPresenter do
describe '#format' do
context 'when formatting days' do
it 'formats single day correctly' do
expect(described_class.new(86_400).format).to eq '1 day'
end
it 'formats multiple days correctly' do
expect(described_class.new(172_800).format).to eq '2 days'
end
it 'includes seconds with days correctly' do
expect(described_class.new(86_401).format).to eq '1 day 1 second'
end
it 'includes hours with days correctly' do
expect(described_class.new(93_600).format).to eq '1 day 2 hours'
end
it 'includes minutes with days correctly' do
expect(described_class.new(86_461).format).to eq '1 day 1 minute'
end
end
context 'when formatting hours' do
it 'formats single hour correctly' do
expect(described_class.new(3600).format).to eq '1 hour'
end
it 'formats multiple hours correctly' do
expect(described_class.new(7200).format).to eq '2 hours'
end
it 'includes seconds with hours correctly' do
expect(described_class.new(3601).format).to eq '1 hour 1 second'
end
it 'includes minutes with hours correctly' do
expect(described_class.new(3660).format).to eq '1 hour 1 minute'
end
end
context 'when formatting minutes' do
it 'formats single minute correctly' do
expect(described_class.new(60).format).to eq '1 minute'
end
it 'formats multiple minutes correctly' do
expect(described_class.new(120).format).to eq '2 minutes'
end
it 'includes seconds with minutes correctly' do
expect(described_class.new(62).format).to eq '1 minute 2 seconds'
end
end
context 'when formatting seconds' do
it 'formats multiple seconds correctly' do
expect(described_class.new(56).format).to eq '56 seconds'
end
it 'handles floating-point seconds by truncating to the nearest lower second' do
expect(described_class.new(55.2).format).to eq '55 seconds'
end
it 'formats single second correctly' do
expect(described_class.new(1).format).to eq '1 second'
end
end
end
end