Skip to content

Commit 4e91b2a

Browse files
Merge pull request #74 from squidit/feature/sq-67531.criar-componente-de-melhorias-dias-e-horarios
✨ feat: SQ-67531 Criar componente de Melhorias dias e horários
2 parents 6b0fabf + 3d47bc0 commit 4e91b2a

11 files changed

+282
-1
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@squidit/react-css",
3-
"version": "1.2.21",
3+
"version": "1.2.22",
44
"scripts": {
55
"format": "prettier --write --parser typescript '**/*.{ts,tsx}'",
66
"lint": "eslint src --ext js,ts,tsx",

src/components/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,3 +55,4 @@ export * from './sq-modal-profile-cache'
5555
export * from './sq-modal-footer'
5656
export * from './sq-card-profile'
5757
export * from './sq-form-profile-cache'
58+
export * from './sq-average-engagement-chart'
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import React from 'react'
2+
import SqAverageEngagementChart, { Props } from '../average-engagement-chart.component'
3+
4+
const SqAverageEngagementChartExample = (props: Props) => {
5+
return (
6+
<div
7+
style={{
8+
display: 'flex',
9+
justifyContent: 'center',
10+
alignItems: 'center',
11+
height: '100%',
12+
width: '600px',
13+
}}
14+
>
15+
<SqAverageEngagementChart {...props} />
16+
</div>
17+
)
18+
}
19+
20+
export default SqAverageEngagementChartExample
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { Meta, StoryObj } from '@storybook/react'
2+
import SqAverageEngagementChartExample from './average-engagement-chart.component.example'
3+
4+
const meta: Meta<typeof SqAverageEngagementChartExample> = {
5+
title: 'Components/SqAverageEngagementChart',
6+
parameters: {
7+
docs: {
8+
description: {
9+
component: 'A simple Average Engagement Chart component',
10+
},
11+
},
12+
},
13+
component: SqAverageEngagementChartExample,
14+
tags: ['autodocs'],
15+
}
16+
17+
export default meta
18+
type Story = StoryObj<typeof SqAverageEngagementChartExample>
19+
20+
export const Default: Story = {
21+
args: {
22+
dataSet: [
23+
[1, 2, 3, 4, 5, 6, 7, 8],
24+
[8, 9, 10, 11, 12, 13, 14, 15],
25+
[15, 16, 17, 18, 19, 20, 21, 22],
26+
[22, 23, 24, 25, 26, 27, 28, 29],
27+
[29, 30, 31, 32, 33, 34, 35, 36],
28+
[36, 37, 38, 39, 40, 41, 42, 43],
29+
[43, 44, 45, 46, 47, 48, 49, 30],
30+
],
31+
},
32+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
.engagement-chart {
2+
overflow: hidden;
3+
display: flex;
4+
justify-content: center;
5+
width: 100%;
6+
7+
tr td {
8+
word-break: break-all;
9+
overflow-wrap: break-word;
10+
text-overflow: ellipsis;
11+
}
12+
13+
td {
14+
font-size: 0.9rem;
15+
font-weight: bold;
16+
text-align: center;
17+
color: var(--text_color);
18+
border-radius: 50%;
19+
20+
@media (max-width: 576px) {
21+
font-size: 0.8rem;
22+
}
23+
}
24+
25+
.engagement-chart-values {
26+
position: relative;
27+
border-spacing: 2px;
28+
border-collapse: initial;
29+
width: 100%;
30+
31+
tbody {
32+
max-width: 100%;
33+
width: 100%;
34+
35+
td {
36+
.element-value {
37+
width: 100%;
38+
aspect-ratio: 1 / 1;
39+
padding: 0 0.75rem;
40+
border-radius: 50%;
41+
margin: 0 auto;
42+
}
43+
}
44+
}
45+
46+
tfoot,
47+
tfoot th,
48+
tfoot td {
49+
position: sticky;
50+
bottom: 0;
51+
color: var(--text_color);
52+
}
53+
}
54+
}
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
import React, { useCallback, useEffect, useLayoutEffect, useMemo, useState } from 'react'
2+
import { useTranslation } from 'react-i18next'
3+
4+
import './average-engagement-chart.component.scoped.scss'
5+
import SqObjectHelper from '@/src/helpers/sq-object/sq-object.helper'
6+
import { SqNumbersHelper } from '@/src/helpers'
7+
import i18n from '@/src/i18n'
8+
9+
interface Day {
10+
value: number
11+
percentage: number
12+
}
13+
14+
export interface Props extends React.HTMLAttributes<HTMLDivElement> {
15+
dataSet: number[][]
16+
color?: string
17+
}
18+
19+
const MIN_OPACITY = 0.2
20+
21+
export default function AverageEngagementChart({ dataSet, color = 'blue', className = '', ...props }: Props) {
22+
const tableElement = React.useRef<HTMLTableElement>(null)
23+
24+
const sqNumberHelper = useMemo(() => new SqNumbersHelper(), [])
25+
26+
/* Local variables */
27+
const timestamp = `random-id-${(1 + Date.now() + Math.random()).toString().replace('.', '')}`
28+
const weekdays = ['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday']
29+
const hours = ['00h', '03h', '06h', '09h', '12h', '15h', '18h', '21h']
30+
31+
const [data, setData] = useState<Day[][]>([])
32+
33+
const { t } = useTranslation('averageEngagementChart')
34+
35+
const setOpacity = useCallback(
36+
(value: number) => {
37+
const dataFlatted: number[] = dataSet?.flatMap((week) => week)
38+
const biggestValue: number = Math.max(...dataFlatted)
39+
40+
if (value < MIN_OPACITY || value === null) {
41+
return MIN_OPACITY
42+
}
43+
44+
if (value === biggestValue) {
45+
return 1
46+
}
47+
48+
const percentageValue: number = (value * 100) / biggestValue / 100
49+
50+
return percentageValue * (1 - MIN_OPACITY) + MIN_OPACITY
51+
},
52+
[dataSet],
53+
)
54+
55+
useEffect(() => {
56+
const processDataSet = () => {
57+
const dataMapped = dataSet.map(
58+
(week) =>
59+
week?.map((value) => ({
60+
value: value,
61+
percentage: setOpacity(value),
62+
})),
63+
)
64+
65+
setData(dataMapped)
66+
}
67+
68+
processDataSet()
69+
}, [dataSet, setOpacity])
70+
71+
useEffect(() => {
72+
const table = tableElement?.current
73+
if (!table) return
74+
75+
const rows = table.rows
76+
77+
if (table.tHead) {
78+
table.tHead.remove()
79+
}
80+
81+
// add a label to all rows
82+
for (let i = 0; i < rows.length; i++) {
83+
const row = rows[i]
84+
const label = weekdays[i]
85+
const labelCell = row.insertCell(0)
86+
labelCell.innerHTML = t(label)
87+
}
88+
89+
// check if table has tfoot and remove it
90+
if (table.tFoot) {
91+
table.tFoot.remove()
92+
}
93+
94+
// add a tfoot with the hours skipping the first cell
95+
const tfoot = table.createTFoot()
96+
const tfootRow = tfoot.insertRow()
97+
tfootRow.insertCell()
98+
for (const element of hours) {
99+
const cell = tfootRow.insertCell()
100+
cell.innerHTML = element
101+
}
102+
}, [data, t, weekdays, hours])
103+
104+
return (
105+
<div className={`engagement-chart ${className}`} {...props}>
106+
<table border={0} cellSpacing="0" cellPadding="0" style={{ width: '100%' }}>
107+
<tbody>
108+
<tr>
109+
<td>
110+
<table className="engagement-chart-values" ref={tableElement} id={timestamp} key={timestamp}>
111+
<tbody>
112+
{data?.map((week, index) => (
113+
<tr key={index}>
114+
{week?.map((obj, i) => (
115+
<td key={i}>
116+
<div
117+
className={`element-value background-${color}`}
118+
style={{ opacity: obj?.percentage }}
119+
data-tooltip={`${t('averageEngagement')}: ${sqNumberHelper?.formatStandardNumber({
120+
lang: i18n?.language,
121+
number: obj?.value,
122+
})}`}
123+
></div>
124+
</td>
125+
))}
126+
</tr>
127+
))}
128+
</tbody>
129+
</table>
130+
</td>
131+
</tr>
132+
</tbody>
133+
</table>
134+
</div>
135+
)
136+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { default as SqAverageEngagementChart } from './average-engagement-chart.component'
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"monday": "Mon",
3+
"tuesday": "Tue",
4+
"wednesday": "Wed",
5+
"thursday": "Thu",
6+
"friday": "Fri",
7+
"saturday": "Sat",
8+
"sunday": "Sun",
9+
"averageEngagement": "Engajamento médio"
10+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"monday": "Lun",
3+
"tuesday": "Mar",
4+
"wednesday": "Mié",
5+
"thursday": "Jue",
6+
"friday": "Vie",
7+
"saturday": "Sáb",
8+
"sunday": "Dom",
9+
"averageEngagement": "Engagement promedio"
10+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"monday": "Seg",
3+
"tuesday": "Ter",
4+
"wednesday": "Qua",
5+
"thursday": "Qui",
6+
"friday": "Sex",
7+
"saturday": "Sáb",
8+
"sunday": "Dom",
9+
"averageEngagement": "Engajamento médio"
10+
}

src/i18n.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@ import esSqModalProfileCache from '@components/sq-modal-profile-cache/locales/es
5959
import ptSqInputBirthdaySimple from '@components/inputs/sq-input-birthday-simple/locales/pt.json'
6060
import esSqInputBirthdaySimple from '@components/inputs/sq-input-birthday-simple/locales/es.json'
6161
import enSqInputBirthdaySimple from '@components/inputs/sq-input-birthday-simple/locales/en.json'
62+
import ptAverageEngagementChart from '@components/sq-average-engagement-chart/locales/pt.json'
63+
import enAverageEngagementChart from '@components/sq-average-engagement-chart/locales/en.json'
64+
import esAverageEngagementChart from '@components/sq-average-engagement-chart/locales/es.json'
6265

6366
const getResources = () => ({
6467
en: {
@@ -78,6 +81,7 @@ const getResources = () => ({
7881
sqInsufficientData: enSqInsufficientData,
7982
sqModalProfileCache: enSqModalProfileCache,
8083
sqInputBirthdaySimple: enSqInputBirthdaySimple,
84+
averageEngagementChart: enAverageEngagementChart,
8185
},
8286
pt: {
8387
globals: ptGlobals,
@@ -96,6 +100,7 @@ const getResources = () => ({
96100
sqInsufficientData: ptSqInsufficientData,
97101
sqModalProfileCache: ptSqModalProfileCache,
98102
sqInputBirthdaySimple: ptSqInputBirthdaySimple,
103+
averageEngagementChart: ptAverageEngagementChart,
99104
},
100105
es: {
101106
globals: esGlobals,
@@ -114,6 +119,7 @@ const getResources = () => ({
114119
sqInsufficientData: esSqInsufficientData,
115120
sqModalProfileCache: esSqModalProfileCache,
116121
sqInputBirthdaySimple: esSqInputBirthdaySimple,
122+
averageEngagementChart: esAverageEngagementChart,
117123
},
118124
})
119125

@@ -179,6 +185,7 @@ i18n
179185
'sqModalWelcomeCreatorsInsights',
180186
'sqGroupVerticalBarChart',
181187
'sqInputBirthdaySimple',
188+
'averageEngagementChart',
182189
],
183190
load: 'all',
184191
supportedLngs: ['en', 'pt', 'es'],

0 commit comments

Comments
 (0)