sincerely 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +31 -0
  3. data/app/assets/config/sincerely.js +2 -0
  4. data/app/assets/images/sincerely/arrow_left.svg +1 -0
  5. data/app/assets/images/sincerely/check.svg +3 -0
  6. data/app/assets/images/sincerely/chevron_left.svg +1 -0
  7. data/app/assets/images/sincerely/clock.svg +1 -0
  8. data/app/assets/images/sincerely/code.svg +1 -0
  9. data/app/assets/images/sincerely/eye.svg +1 -0
  10. data/app/assets/images/sincerely/logout.svg +1 -0
  11. data/app/assets/images/sincerely/menu.svg +1 -0
  12. data/app/assets/images/sincerely/moon.svg +1 -0
  13. data/app/assets/images/sincerely/pencil.svg +4 -0
  14. data/app/assets/images/sincerely/plus.svg +3 -0
  15. data/app/assets/images/sincerely/progress_spinner.svg +3 -0
  16. data/app/assets/images/sincerely/spinner.svg +3 -0
  17. data/app/assets/images/sincerely/sun.svg +1 -0
  18. data/app/assets/images/sincerely/warning_circle.svg +4 -0
  19. data/app/assets/javascripts/sincerely/charts.js +115 -0
  20. data/app/assets/javascripts/sincerely/clickable_rows.js +29 -0
  21. data/app/assets/javascripts/sincerely/layout.js +104 -0
  22. data/app/assets/javascripts/sincerely/send_form.js +243 -0
  23. data/app/assets/javascripts/sincerely/template_form.js +44 -0
  24. data/app/assets/javascripts/sincerely/template_preview.js +12 -0
  25. data/app/assets/javascripts/sincerely/theme_init.js +9 -0
  26. data/app/assets/stylesheets/sincerely/charts.css +250 -0
  27. data/app/assets/stylesheets/sincerely/components.css +632 -0
  28. data/app/assets/stylesheets/sincerely/layout.css +233 -0
  29. data/app/assets/stylesheets/sincerely/navigation.css +198 -0
  30. data/app/assets/stylesheets/sincerely/send_form.css +287 -0
  31. data/app/assets/stylesheets/sincerely/template_form.css +74 -0
  32. data/app/assets/stylesheets/sincerely/template_preview.css +75 -0
  33. data/app/assets/stylesheets/sincerely/variables.css +88 -0
  34. data/app/controllers/sincerely/application_controller.rb +3 -72
  35. data/app/controllers/sincerely/concerns/authorization.rb +21 -0
  36. data/app/controllers/sincerely/concerns/delivery_metrics.rb +51 -0
  37. data/app/controllers/sincerely/concerns/event_filtering.rb +58 -0
  38. data/app/controllers/sincerely/concerns/event_timeline.rb +41 -0
  39. data/app/controllers/sincerely/concerns/notification_timeline.rb +73 -0
  40. data/app/controllers/sincerely/concerns/notifications.rb +47 -0
  41. data/app/controllers/sincerely/concerns/pagination.rb +39 -0
  42. data/app/controllers/sincerely/concerns/periods.rb +40 -0
  43. data/app/controllers/sincerely/dashboard_controller.rb +30 -88
  44. data/app/controllers/sincerely/delivery_events_controller.rb +13 -21
  45. data/app/controllers/sincerely/engagement_events_controller.rb +13 -22
  46. data/app/controllers/sincerely/notifications_controller.rb +68 -49
  47. data/app/controllers/sincerely/send_controller.rb +82 -67
  48. data/app/controllers/sincerely/templates_controller.rb +37 -8
  49. data/app/helpers/sincerely/application_helper.rb +22 -0
  50. data/app/helpers/sincerely/chart_helper.rb +79 -0
  51. data/app/views/layouts/sincerely/application.html.erb +24 -528
  52. data/app/views/sincerely/dashboard/index.html.erb +25 -256
  53. data/app/views/sincerely/delivery_events/index.html.erb +6 -38
  54. data/app/views/sincerely/engagement_events/index.html.erb +6 -38
  55. data/app/views/sincerely/notifications/index.html.erb +7 -23
  56. data/app/views/sincerely/notifications/show.html.erb +4 -4
  57. data/app/views/sincerely/send/new.html.erb +8 -522
  58. data/app/views/sincerely/shared/_event.html.erb +21 -0
  59. data/app/views/sincerely/shared/_line_chart.html.erb +38 -0
  60. data/app/views/sincerely/shared/_notification_type_filter.html.erb +9 -0
  61. data/app/views/sincerely/shared/_status_option.html.erb +1 -0
  62. data/app/views/sincerely/shared/_template_option.html.erb +3 -0
  63. data/app/views/sincerely/templates/_form.html.erb +8 -107
  64. data/app/views/sincerely/templates/edit.html.erb +2 -2
  65. data/app/views/sincerely/templates/index.html.erb +7 -15
  66. data/app/views/sincerely/templates/new.html.erb +2 -2
  67. data/app/views/sincerely/templates/preview.html.erb +7 -26
  68. data/app/views/sincerely/templates/show.html.erb +3 -3
  69. data/lib/config/sincerely_config.rb +2 -2
  70. data/lib/sincerely/delivery_systems/email_aws_ses.rb +2 -2
  71. data/lib/sincerely/engine.rb +4 -0
  72. data/lib/sincerely/mixins/notification_model.rb +5 -1
  73. data/lib/sincerely/services/process_delivery_event.rb +9 -7
  74. data/lib/sincerely/templates/notification_template.rb +1 -1
  75. data/lib/sincerely/version.rb +1 -1
  76. metadata +52 -4
  77. data/sincerely.gemspec +0 -37
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sincerely
4
+ module ChartHelper
5
+ DANGER_COLOR = '#d4183d'
6
+
7
+ STATE_COLORS = {
8
+ 'draft' => '#9ca3af',
9
+ 'accepted' => '#b9e0b8',
10
+ 'delivered' => '#10b981',
11
+ 'opened' => '#78c6cc',
12
+ 'clicked' => '#bdd9db',
13
+ 'bounced' => DANGER_COLOR,
14
+ 'rejected' => DANGER_COLOR,
15
+ 'complained' => DANGER_COLOR,
16
+ 'delayed' => '#f97316'
17
+ }.freeze
18
+
19
+ DEFAULT_COLOR = '#6b7280'
20
+
21
+ LINE_CHART = {
22
+ width: 800, height: 220,
23
+ padding_left: 45, padding_right: 20,
24
+ padding_top: 20, padding_bottom: 30
25
+ }.freeze
26
+
27
+ DONUT_RADIUS = 68
28
+
29
+ def state_color(state)
30
+ STATE_COLORS[state.to_s] || DEFAULT_COLOR
31
+ end
32
+
33
+ def line_chart_config(series, labels)
34
+ plot_width = LINE_CHART[:width] - LINE_CHART[:padding_left] - LINE_CHART[:padding_right]
35
+ plot_height = LINE_CHART[:height] - LINE_CHART[:padding_top] - LINE_CHART[:padding_bottom]
36
+
37
+ max_value = [series.values.flatten.max || 0, 1].max
38
+ magnitude = 10**Math.log10(max_value).floor
39
+ max_y = [((max_value.to_f / magnitude).ceil * magnitude).to_i, 1].max
40
+ x_step = labels.length > 1 ? plot_width.to_f / (labels.length - 1) : plot_width
41
+
42
+ LINE_CHART.merge(plot_width:, plot_height:, max_y:, x_step:)
43
+ end
44
+
45
+ def line_chart_points(values, config)
46
+ values.each_with_index.map do |value, i|
47
+ x = config[:padding_left] + (i * config[:x_step])
48
+ y = config[:padding_top] + config[:plot_height] - (value.to_f / config[:max_y] * config[:plot_height])
49
+ "#{x.round(2)},#{y.round(2)}"
50
+ end.join(' ')
51
+ end
52
+
53
+ def line_chart_area_points(points_str, values, config)
54
+ bottom_y = config[:padding_top] + config[:plot_height]
55
+ last_x = config[:padding_left] + ((values.length - 1) * config[:x_step])
56
+ "#{config[:padding_left]},#{bottom_y} #{points_str} #{last_x},#{bottom_y}"
57
+ end
58
+
59
+ def donut_segment_data(notifications_by_state)
60
+ total = notifications_by_state.values.sum
61
+ circumference = 2 * Math::PI * DONUT_RADIUS
62
+ offset = 0
63
+
64
+ notifications_by_state.map do |state, count|
65
+ dash_length = circumference * (count.to_f / total)
66
+ visible_dash = [dash_length + 0.5, circumference].min
67
+ segment = {
68
+ state:, count:,
69
+ color: state_color(state),
70
+ visible_dash:,
71
+ gap: [circumference - visible_dash, 0].max,
72
+ offset: -offset
73
+ }
74
+ offset += dash_length
75
+ segment
76
+ end
77
+ end
78
+ end
79
+ end