agx-chat-web 0.4.9

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 (154) hide show
  1. package/README.md +9 -0
  2. package/dist/agx-chat.js +3 -0
  3. package/dist/agx-chat.js.LICENSE.txt +303 -0
  4. package/dist/agx-chat.js.map +1 -0
  5. package/dist/agx-chat.min.js +3 -0
  6. package/dist/agx-chat.min.js.LICENSE.txt +303 -0
  7. package/dist/agx-chat.min.js.map +1 -0
  8. package/dist/esm/__tests__/app/Messenger/classes/slaCalculations.spec.d.ts +1 -0
  9. package/dist/esm/__tests__/app/Messenger/classes/slaCalculations.spec.js +46 -0
  10. package/dist/esm/__tests__/app/Messenger/classes/slaCalculations.spec.js.map +1 -0
  11. package/dist/esm/app/Messenger/classes/slaCalculations.d.ts +30 -0
  12. package/dist/esm/app/Messenger/classes/slaCalculations.js +142 -0
  13. package/dist/esm/app/Messenger/classes/slaCalculations.js.map +1 -0
  14. package/dist/esm/app/Messenger/components/ChatButton/ChatButton.d.ts +14 -0
  15. package/dist/esm/app/Messenger/components/ChatButton/ChatButton.js +31 -0
  16. package/dist/esm/app/Messenger/components/ChatButton/ChatButton.js.map +1 -0
  17. package/dist/esm/app/Messenger/components/ChatTabs/ChatTabs.d.ts +9 -0
  18. package/dist/esm/app/Messenger/components/ChatTabs/ChatTabs.js +15 -0
  19. package/dist/esm/app/Messenger/components/ChatTabs/ChatTabs.js.map +1 -0
  20. package/dist/esm/app/Messenger/components/ImagesContainer/ImagesContainer.d.ts +3 -0
  21. package/dist/esm/app/Messenger/components/ImagesContainer/ImagesContainer.js +24 -0
  22. package/dist/esm/app/Messenger/components/ImagesContainer/ImagesContainer.js.map +1 -0
  23. package/dist/esm/app/Messenger/components/IncomingMessage/IncomingMessage.d.ts +3 -0
  24. package/dist/esm/app/Messenger/components/IncomingMessage/IncomingMessage.js +33 -0
  25. package/dist/esm/app/Messenger/components/IncomingMessage/IncomingMessage.js.map +1 -0
  26. package/dist/esm/app/Messenger/components/InfiniteScroll/InfiniteScroll.d.ts +11 -0
  27. package/dist/esm/app/Messenger/components/InfiniteScroll/InfiniteScroll.js +37 -0
  28. package/dist/esm/app/Messenger/components/InfiniteScroll/InfiniteScroll.js.map +1 -0
  29. package/dist/esm/app/Messenger/components/InputFile/InputFile.d.ts +8 -0
  30. package/dist/esm/app/Messenger/components/InputFile/InputFile.js +59 -0
  31. package/dist/esm/app/Messenger/components/InputFile/InputFile.js.map +1 -0
  32. package/dist/esm/app/Messenger/components/MessageBallon/MessageBalloon.d.ts +8 -0
  33. package/dist/esm/app/Messenger/components/MessageBallon/MessageBalloon.js +32 -0
  34. package/dist/esm/app/Messenger/components/MessageBallon/MessageBalloon.js.map +1 -0
  35. package/dist/esm/app/Messenger/components/MessengerAvatar/MessengerAvatar.d.ts +3 -0
  36. package/dist/esm/app/Messenger/components/MessengerAvatar/MessengerAvatar.js +13 -0
  37. package/dist/esm/app/Messenger/components/MessengerAvatar/MessengerAvatar.js.map +1 -0
  38. package/dist/esm/app/Messenger/components/MessengerThemeWrapper/MessengerThemeWrapper.d.ts +40 -0
  39. package/dist/esm/app/Messenger/components/MessengerThemeWrapper/MessengerThemeWrapper.js +39 -0
  40. package/dist/esm/app/Messenger/components/MessengerThemeWrapper/MessengerThemeWrapper.js.map +1 -0
  41. package/dist/esm/app/Messenger/components/SearchInput/SearchInput.d.ts +10 -0
  42. package/dist/esm/app/Messenger/components/SearchInput/SearchInput.js +32 -0
  43. package/dist/esm/app/Messenger/components/SearchInput/SearchInput.js.map +1 -0
  44. package/dist/esm/app/Messenger/components/Select/Select.d.ts +13 -0
  45. package/dist/esm/app/Messenger/components/Select/Select.js +16 -0
  46. package/dist/esm/app/Messenger/components/Select/Select.js.map +1 -0
  47. package/dist/esm/app/Messenger/components/SenderMessages/SenderMessages.d.ts +3 -0
  48. package/dist/esm/app/Messenger/components/SenderMessages/SenderMessages.js +32 -0
  49. package/dist/esm/app/Messenger/components/SenderMessages/SenderMessages.js.map +1 -0
  50. package/dist/esm/app/Messenger/components/SystemMessage/SystemMessage.d.ts +3 -0
  51. package/dist/esm/app/Messenger/components/SystemMessage/SystemMessage.js +14 -0
  52. package/dist/esm/app/Messenger/components/SystemMessage/SystemMessage.js.map +1 -0
  53. package/dist/esm/app/Messenger/components/TextArea/TextArea.d.ts +8 -0
  54. package/dist/esm/app/Messenger/components/TextArea/TextArea.js +14 -0
  55. package/dist/esm/app/Messenger/components/TextArea/TextArea.js.map +1 -0
  56. package/dist/esm/app/Messenger/hooks/useConversations.d.ts +11 -0
  57. package/dist/esm/app/Messenger/hooks/useConversations.js +59 -0
  58. package/dist/esm/app/Messenger/hooks/useConversations.js.map +1 -0
  59. package/dist/esm/app/Messenger/hooks/useThemes.d.ts +31 -0
  60. package/dist/esm/app/Messenger/hooks/useThemes.js +11 -0
  61. package/dist/esm/app/Messenger/hooks/useThemes.js.map +1 -0
  62. package/dist/esm/app/Messenger/icons/AttachFileIcon.d.ts +3 -0
  63. package/dist/esm/app/Messenger/icons/AttachFileIcon.js +10 -0
  64. package/dist/esm/app/Messenger/icons/AttachFileIcon.js.map +1 -0
  65. package/dist/esm/app/Messenger/icons/CloseIcon.d.ts +1 -0
  66. package/dist/esm/app/Messenger/icons/CloseIcon.js +9 -0
  67. package/dist/esm/app/Messenger/icons/CloseIcon.js.map +1 -0
  68. package/dist/esm/app/Messenger/icons/EmptyIcon.d.ts +1 -0
  69. package/dist/esm/app/Messenger/icons/EmptyIcon.js +8 -0
  70. package/dist/esm/app/Messenger/icons/EmptyIcon.js.map +1 -0
  71. package/dist/esm/app/Messenger/icons/MessageIcon.d.ts +5 -0
  72. package/dist/esm/app/Messenger/icons/MessageIcon.js +12 -0
  73. package/dist/esm/app/Messenger/icons/MessageIcon.js.map +1 -0
  74. package/dist/esm/app/Messenger/icons/ReadIcon.d.ts +3 -0
  75. package/dist/esm/app/Messenger/icons/ReadIcon.js +7 -0
  76. package/dist/esm/app/Messenger/icons/ReadIcon.js.map +1 -0
  77. package/dist/esm/app/Messenger/icons/SearchIcon.d.ts +1 -0
  78. package/dist/esm/app/Messenger/icons/SearchIcon.js +8 -0
  79. package/dist/esm/app/Messenger/icons/SearchIcon.js.map +1 -0
  80. package/dist/esm/app/Messenger/icons/TimerIcon.d.ts +1 -0
  81. package/dist/esm/app/Messenger/icons/TimerIcon.js +6 -0
  82. package/dist/esm/app/Messenger/icons/TimerIcon.js.map +1 -0
  83. package/dist/esm/app/Messenger/icons/TrashIcon.d.ts +5 -0
  84. package/dist/esm/app/Messenger/icons/TrashIcon.js +7 -0
  85. package/dist/esm/app/Messenger/icons/TrashIcon.js.map +1 -0
  86. package/dist/esm/app/Messenger/views/MessengerList.d.ts +39 -0
  87. package/dist/esm/app/Messenger/views/MessengerList.js +50 -0
  88. package/dist/esm/app/Messenger/views/MessengerList.js.map +1 -0
  89. package/dist/esm/app/Messenger/views/MessengerListItem.d.ts +11 -0
  90. package/dist/esm/app/Messenger/views/MessengerListItem.js +87 -0
  91. package/dist/esm/app/Messenger/views/MessengerListItem.js.map +1 -0
  92. package/dist/esm/app/Messenger/views/MessengerMessages.d.ts +23 -0
  93. package/dist/esm/app/Messenger/views/MessengerMessages.js +133 -0
  94. package/dist/esm/app/Messenger/views/MessengerMessages.js.map +1 -0
  95. package/dist/esm/app/Messenger/views/NewFormChat.d.ts +10 -0
  96. package/dist/esm/app/Messenger/views/NewFormChat.js +64 -0
  97. package/dist/esm/app/Messenger/views/NewFormChat.js.map +1 -0
  98. package/dist/esm/index.d.ts +8 -0
  99. package/dist/esm/index.js +9 -0
  100. package/dist/esm/index.js.map +1 -0
  101. package/dist/esm/setupTests.d.ts +1 -0
  102. package/dist/esm/setupTests.js +6 -0
  103. package/dist/esm/setupTests.js.map +1 -0
  104. package/dist/esm/types.d.ts +134 -0
  105. package/dist/esm/types.js +2 -0
  106. package/dist/esm/types.js.map +1 -0
  107. package/package.json +67 -0
  108. package/src/__tests__/app/Messenger/classes/slaCalculations.spec.ts +115 -0
  109. package/src/app/Messenger/classes/slaCalculations.ts +165 -0
  110. package/src/app/Messenger/components/ChatButton/ChatButton.tsx +63 -0
  111. package/src/app/Messenger/components/ChatTabs/ChatTabs.less +18 -0
  112. package/src/app/Messenger/components/ChatTabs/ChatTabs.tsx +32 -0
  113. package/src/app/Messenger/components/ImagesContainer/ImagesContainer.less +64 -0
  114. package/src/app/Messenger/components/ImagesContainer/ImagesContainer.tsx +40 -0
  115. package/src/app/Messenger/components/IncomingMessage/IncomingMessage.tsx +59 -0
  116. package/src/app/Messenger/components/InfiniteScroll/InfiniteScroll.tsx +52 -0
  117. package/src/app/Messenger/components/InputFile/InputFile.tsx +106 -0
  118. package/src/app/Messenger/components/InputFile/inputFile.less +52 -0
  119. package/src/app/Messenger/components/MessageBallon/MessageBalloon.tsx +88 -0
  120. package/src/app/Messenger/components/MessengerAvatar/MessengerAvatar.tsx +21 -0
  121. package/src/app/Messenger/components/MessengerThemeWrapper/MessengerThemeWrapper.tsx +58 -0
  122. package/src/app/Messenger/components/SearchInput/SearchInput.less +45 -0
  123. package/src/app/Messenger/components/SearchInput/SearchInput.tsx +68 -0
  124. package/src/app/Messenger/components/Select/Select.less +22 -0
  125. package/src/app/Messenger/components/Select/Select.tsx +41 -0
  126. package/src/app/Messenger/components/SenderMessages/SenderMessages.tsx +52 -0
  127. package/src/app/Messenger/components/SystemMessage/SystemMessage.tsx +23 -0
  128. package/src/app/Messenger/components/TextArea/TextArea.tsx +31 -0
  129. package/src/app/Messenger/components/TextArea/Textarea.less +22 -0
  130. package/src/app/Messenger/hooks/useConversations.tsx +80 -0
  131. package/src/app/Messenger/hooks/useThemes.tsx +14 -0
  132. package/src/app/Messenger/icons/AttachFileIcon.tsx +11 -0
  133. package/src/app/Messenger/icons/CloseIcon.tsx +11 -0
  134. package/src/app/Messenger/icons/EmptyIcon.tsx +11 -0
  135. package/src/app/Messenger/icons/MessageIcon.tsx +18 -0
  136. package/src/app/Messenger/icons/ReadIcon.tsx +9 -0
  137. package/src/app/Messenger/icons/SearchIcon.tsx +12 -0
  138. package/src/app/Messenger/icons/TimerIcon.tsx +10 -0
  139. package/src/app/Messenger/icons/TrashIcon.tsx +13 -0
  140. package/src/app/Messenger/views/Messenger.less +610 -0
  141. package/src/app/Messenger/views/MessengerList.tsx +172 -0
  142. package/src/app/Messenger/views/MessengerListItem.tsx +136 -0
  143. package/src/app/Messenger/views/MessengerMessages.tsx +287 -0
  144. package/src/app/Messenger/views/NewFormChat.tsx +126 -0
  145. package/src/assets/right-arrow.svg +10 -0
  146. package/src/index.ts +17 -0
  147. package/src/react-app-env.d.ts +16 -0
  148. package/src/setupTests.ts +5 -0
  149. package/src/styles/abstracts/animations.less +8 -0
  150. package/src/styles/abstracts/mixins.less +5 -0
  151. package/src/styles/abstracts/variables.less +25 -0
  152. package/src/styles/base/base.less +6 -0
  153. package/src/styles/index.less +6 -0
  154. package/src/types.ts +166 -0
package/package.json ADDED
@@ -0,0 +1,67 @@
1
+ {
2
+ "name": "agx-chat-web",
3
+ "version": "0.4.9",
4
+ "description": "Chat application using React and less",
5
+ "author": {
6
+ "name": "Jeiel Alves",
7
+ "email": "jeiel.oliveira@agxsoftware.com"
8
+ },
9
+ "license": "MIT",
10
+ "main": "./dist/agx-chat.min.js",
11
+ "types": "./dist/esm/index.d.ts",
12
+ "files": [
13
+ "dist",
14
+ "src/**/*"
15
+ ],
16
+ "repository": "git@github.com:AGX-Software/chat-web.git",
17
+ "peerDependencies": {
18
+ "react": ">=16",
19
+ "react-dom": ">=16",
20
+ "react-simple-image-viewer": "^1.2.2",
21
+ "dayjs": "^1.11.9"
22
+ },
23
+ "scripts": {
24
+ "clean": "shx rm -rf dist",
25
+ "build": "yarn clean && tsc && webpack",
26
+ "build-dev": "tsc && webpack",
27
+ "lint": "eslint \"{**/*,*}.{js,ts,jsx,tsx}\"",
28
+ "test": "jest --config jestconfig.json",
29
+ "deploy": "yarn build && npm publish"
30
+ },
31
+ "jest": {
32
+ "preset": "ts-jest",
33
+ "testEnvironment": "node",
34
+ "setupFilesAfterEnv": [
35
+ "./jestconfig.json"
36
+ ]
37
+ },
38
+ "devDependencies": {
39
+ "@testing-library/react": "^13.4.0",
40
+ "@types/jest": "^29.2.5",
41
+ "@types/react": "^17.0.0",
42
+ "@typescript-eslint/eslint-plugin": "^5.48.1",
43
+ "@typescript-eslint/parser": "^5.48.1",
44
+ "css-loader": "^6.7.3",
45
+ "eslint": "^8.31.0",
46
+ "eslint-plugin-only-warn": "^1.1.0",
47
+ "eslint-plugin-react": "^7.31.11",
48
+ "eslint-plugin-react-hooks": "^4.6.0",
49
+ "jest": "^29.3.1",
50
+ "jest-canvas-mock": "^2.4.0",
51
+ "jest-environment-jsdom": "^29.3.1",
52
+ "less": "^4.1.3",
53
+ "less-loader": "^11.1.0",
54
+ "react-simple-image-viewer": "^1.2.2",
55
+ "shx": "^0.3.4",
56
+ "style-loader": "^3.3.1",
57
+ "svg-url-loader": "^8.0.0",
58
+ "terser-webpack-plugin": "^5.3.6",
59
+ "ts-jest": "^29.1.1",
60
+ "ts-loader": "^9.4.2",
61
+ "typescript": "^4.9.4",
62
+ "uglifyjs-webpack-plugin": "^2.2.0",
63
+ "webpack": "^5.75.0",
64
+ "webpack-cli": "^5.0.1",
65
+ "dayjs": "^1.11.9"
66
+ }
67
+ }
@@ -0,0 +1,115 @@
1
+ import {describe, expect, it} from '@jest/globals'
2
+ import { SlaDates, timeAsDayjs } from '../../../../app/Messenger/classes/slaCalculations'
3
+ const workingHours = { start: 9, end: 18 }
4
+
5
+ describe('slaCalculations class', () => {
6
+ it('Should return true seconds in working hour', () => {
7
+ const sla = new SlaDates(
8
+ 1300,
9
+ )
10
+
11
+ expect(sla.canUpdateClock(timeAsDayjs('2023-07-21T10:19:29.224+00:00', { applyTimezone: false }))).toBeTruthy()
12
+ })
13
+
14
+ it('Should return false seconds from canUpdateClock', () => {
15
+ const sla = new SlaDates(
16
+ 1300
17
+ )
18
+
19
+ expect(sla.canUpdateClock(timeAsDayjs('2023-07-21T20:19:29.224+00:00', { applyTimezone: false }))).toBeFalsy()
20
+ })
21
+
22
+ it('Should return false in holiday', () => {
23
+ const sla = new SlaDates(
24
+ 1300
25
+ )
26
+
27
+ expect(sla.canUpdateClock(
28
+ timeAsDayjs('2023-10-12T10:19:29.224+00:00', { applyTimezone: false })
29
+ )).toBeFalsy()
30
+ })
31
+
32
+ it('Should return 3600 seconds diffence', () => {
33
+ const sla = new SlaDates(
34
+ 3600
35
+ )
36
+
37
+ expect(sla.getDifferenceInSeconds(
38
+ timeAsDayjs('2023-07-19T09:19:29.224+00:00', { applyTimezone: false }),
39
+ timeAsDayjs('2023-07-19T10:19:29.224+00:00', { applyTimezone: false }),
40
+ workingHours
41
+ )).toBe(3600)
42
+ })
43
+
44
+ it('Should return 7200 seconds diffence', () => {
45
+ const sla = new SlaDates(
46
+ 3600
47
+ )
48
+
49
+ expect(sla.getDifferenceInSeconds(
50
+ timeAsDayjs('2023-10-12T09:19:29.224+00:00', { applyTimezone: false }),
51
+ timeAsDayjs('2023-10-12T11:19:29.224+00:00', { applyTimezone: false }),
52
+ workingHours
53
+ )).toBe(0)
54
+ })
55
+
56
+ it('Should return 7200 seconds diffence', () => {
57
+ const sla = new SlaDates(
58
+ 3600
59
+ )
60
+
61
+ expect(sla.getDifferenceInSeconds(
62
+ timeAsDayjs('2023-07-21T17:00:00.000+00:00', { applyTimezone: false }),
63
+ timeAsDayjs('2023-07-24T10:00:00.000+00:00', { applyTimezone: false }),
64
+ workingHours
65
+ )).toBe(7200)
66
+ })
67
+
68
+ it('Should return 64800 seconds diffence', () => {
69
+ const sla = new SlaDates(
70
+ 3600
71
+ )
72
+
73
+ expect(sla.getDifferenceInSeconds(
74
+ timeAsDayjs('2023-07-21T09:00:00.000+00:00', { applyTimezone: false }),
75
+ timeAsDayjs('2023-07-24T18:00:00.000+00:00', { applyTimezone: false }),
76
+ workingHours
77
+ )).toBe(64800)
78
+ })
79
+
80
+ it('Should return 43200 seconds diffence', () => {
81
+ const sla = new SlaDates(
82
+ 3600
83
+ )
84
+
85
+ expect(sla.getDifferenceInSeconds(
86
+ timeAsDayjs('2023-07-21T09:00:00.000+00:00', { applyTimezone: false }),
87
+ timeAsDayjs('2023-07-24T12:00:00.000+00:00', { applyTimezone: false }),
88
+ workingHours
89
+ )).toBe(43200)
90
+ })
91
+
92
+ it('Should return 1800 seconds diffence', () => {
93
+ const sla = new SlaDates(
94
+ 3600
95
+ )
96
+
97
+ expect(sla.getDifferenceInSeconds(
98
+ timeAsDayjs('2023-07-24T07:00:00.000+00:00', { applyTimezone: false }),
99
+ timeAsDayjs('2023-07-24T09:30:00.000+00:00', { applyTimezone: false }),
100
+ workingHours
101
+ )).toBe(1800)
102
+ })
103
+
104
+ it('Should return 3600 seconds diffence', () => {
105
+ const sla = new SlaDates(
106
+ 3600
107
+ )
108
+
109
+ expect(sla.getDifferenceInSeconds(
110
+ timeAsDayjs('2023-07-24T22:00:00.000+00:00', { applyTimezone: false }),
111
+ timeAsDayjs('2023-07-25T10:00:00.000+00:00', { applyTimezone: false }),
112
+ workingHours
113
+ )).toBe(3600)
114
+ })
115
+ })
@@ -0,0 +1,165 @@
1
+ import dayjs, { ConfigType, Dayjs } from 'dayjs'
2
+ import dayjsBR from 'dayjs/locale/pt-br'
3
+ import utc from 'dayjs/plugin/utc'
4
+ import timezone from 'dayjs/plugin/timezone'
5
+ import isToday from 'dayjs/plugin/isToday'
6
+ const serverTz = 'America/Sao_Paulo'
7
+
8
+ dayjs.extend(utc)
9
+ dayjs.extend(timezone)
10
+ dayjs.extend(isToday)
11
+ dayjs.locale(dayjsBR)
12
+
13
+ export const timeAsDayjs = (value: ConfigType = new Date(), options?: {server?: boolean, applyTimezone?: boolean}): Dayjs => {
14
+ const server = options?.server
15
+ const applyTimezone = options?.applyTimezone
16
+
17
+ let timezone = dayjs.tz.guess()
18
+ if (!(applyTimezone ?? true)) timezone = 'GMT'
19
+ else if (server ?? false) timezone = serverTz
20
+
21
+ return dayjs.tz(value, timezone)
22
+ }
23
+
24
+ export const time = (value: ConfigType = new Date(), options?: {server?: boolean, applyTimezone?: boolean}): Date => {
25
+ const server = options?.server
26
+ const applyTimezone = options?.applyTimezone
27
+ let aux: Dayjs
28
+
29
+ if (!(applyTimezone ?? true)) aux = dayjs.tz(value, 'GMT') // Set applyTimezone to false when timezone is applied incorrectly (usually when working with JSDate and timestamps)
30
+ else if (server ?? false) aux = dayjs.tz(value, serverTz)
31
+ else aux = dayjs.tz(value, dayjs.tz.guess())
32
+
33
+ return new Date(Date.UTC(aux.year(), aux.month(), aux.date(), aux.hour(), aux.minute(), aux.second(), aux.millisecond()))
34
+ }
35
+
36
+ export class SlaDates {
37
+ public seconds: number | null
38
+
39
+ constructor (seconds: number) {
40
+ this.seconds = seconds
41
+ }
42
+
43
+ private holidays = {
44
+ 2023: [
45
+ '09-07',
46
+ '10-12',
47
+ '10-17',
48
+ '11-02',
49
+ '11-15',
50
+ '11-20',
51
+ '12-25'
52
+ ]
53
+ }
54
+
55
+ private isWorkingDay (date: Dayjs) {
56
+ const dayOfWeek = date.day();
57
+ return dayOfWeek >= 1 && dayOfWeek <= 5 // Monday to Friday (1 to 5)
58
+ }
59
+
60
+ private isWorkingHour (date: Dayjs) {
61
+ const hour = date.hour()
62
+ return hour >= 9 && hour <= 18 // Between 9 AM and 5 PM (inclusive)
63
+ }
64
+
65
+ public isWeekendOrHoliday (date: Dayjs | Date | string): boolean {
66
+ const weekDay = timeAsDayjs(date, { applyTimezone: false }).day()
67
+ if ([6, 0].includes(weekDay)) return true
68
+
69
+ const formatedDate = timeAsDayjs(date).format('MM-DD')
70
+ const isHollyday = this.holidays[2023].includes(formatedDate)
71
+ return isHollyday
72
+ }
73
+
74
+ private isHoliday (date: Dayjs) {
75
+ const formatedDate = timeAsDayjs(date, { applyTimezone: false }).format('MM-DD')
76
+ const isHollyday = this.holidays[2023].includes(formatedDate)
77
+ return isHollyday
78
+ }
79
+
80
+ public canUpdateClock (date: Dayjs) {
81
+ const isWorking = this.isWorkingDay(date) && this.isWorkingHour(date)
82
+ return !this.isWeekendOrHoliday(date) && isWorking
83
+ }
84
+
85
+ public getDiffInSeconds (startDate: dayjs.Dayjs, endDate: dayjs.Dayjs): number {
86
+ const diffInSeconds = endDate.diff(startDate, 'second')
87
+ return diffInSeconds
88
+ }
89
+
90
+ calculateWorkingTime (startDate: Dayjs, endDate: Dayjs, workingHours: { start: number, end: number }) {
91
+ let current = startDate.clone()
92
+ let workingTime = 0;
93
+
94
+ while (current.isBefore(endDate)) {
95
+ // Skip weekends (Saturday and Sunday) and Holydays
96
+
97
+ if (this.isWorkingDay(current) && !this.isHoliday(current)) {
98
+ const startOfDay = current.clone().startOf('day').add(workingHours.start, 'hour');
99
+ const endOfDay = current.clone().startOf('day').add(workingHours.end, 'hour');
100
+
101
+ if (current.isBefore(startOfDay)) {
102
+ // If current time is before the start of working hours, move to the start of working hours
103
+ current = startOfDay.clone();
104
+ }
105
+
106
+ if (current.isAfter(endOfDay)) {
107
+
108
+ current = current.clone().add(1, 'day').startOf('day')
109
+
110
+ } else if (endDate.isAfter(endOfDay)) {
111
+ // If end date is after the end of working hours, add a full working day
112
+
113
+ workingTime += Math.abs(endOfDay.clone().diff(current, 'second'));
114
+ current = current.clone().add(1, 'day').startOf('day').add(workingHours.start, 'hour');
115
+
116
+ } else {
117
+ // Calculate working time for the last day (end date)
118
+ workingTime += Math.abs(endDate.clone().diff(current, 'second'));
119
+
120
+ break;
121
+ }
122
+ } else {
123
+ // Move to the next day
124
+ current = current.clone().add(1, 'day').startOf('day')
125
+ }
126
+ }
127
+
128
+ return workingTime;
129
+ }
130
+
131
+ // Function to calculate the difference in seconds between two dates considering working hours
132
+ getDifferenceInSeconds (startDate: Dayjs, endDate: Dayjs, workingHours: { start: number, end: number }) {
133
+
134
+ if (endDate.isBefore(startDate)) {
135
+ throw new Error('End date should be after the start date.');
136
+ }
137
+
138
+ const workingTimeInSeconds = this.calculateWorkingTime(startDate, endDate, workingHours);
139
+ return workingTimeInSeconds
140
+ }
141
+
142
+ static secondsInHours (currentSeconds: number) {
143
+ const hours = Math.floor(currentSeconds / 3600);
144
+ const minutes = Math.floor((currentSeconds % 3600) / 60);
145
+ const seconds = currentSeconds % 60;
146
+ return `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;
147
+ }
148
+
149
+ static getColorsByTime (seconds: number) {
150
+ const hours = seconds / 3600;
151
+ if (hours <= 2) {
152
+ return '#00CF7B'
153
+ }
154
+
155
+ if (hours >= 2 && hours < 3) {
156
+ return '#FF9838'
157
+ }
158
+
159
+ if (hours >= 3 && hours < 4) {
160
+ return '#DD4E4E'
161
+ }
162
+
163
+ return '#151919'
164
+ }
165
+ }
@@ -0,0 +1,63 @@
1
+ import React from 'react'
2
+ import useTheme from '../../hooks/useThemes'
3
+
4
+ interface INewChatButton {
5
+ removeActiveItem: (e: React.MouseEvent<HTMLElement, MouseEvent>) => void
6
+ messegerView: 'empty' | 'messages' | 'newChat',
7
+ chatButtons: {
8
+ label: string
9
+ onClick: () => void
10
+ type: string
11
+ canSee: boolean
12
+ disabled?: boolean
13
+ }[]
14
+ }
15
+
16
+ function ChatButtons({ chatButtons, removeActiveItem }: INewChatButton) {
17
+ const { theme } = useTheme()
18
+
19
+ const getButtonType = (type: string, disabled?: boolean) => {
20
+ if (type === 'primary') return {
21
+ background: disabled ? theme?.buttonsDisabled : theme?.buttonPrimary,
22
+ color: theme?.buttonPrimaryText
23
+ }
24
+
25
+ if (type === 'outlined') return {
26
+ background: 'transparent',
27
+ color: theme?.asideFontColor,
28
+ border: `${theme?.asideFontColor} 1px solid`
29
+ }
30
+ return
31
+ }
32
+
33
+ return (
34
+ <>
35
+ {
36
+ chatButtons.map((button => {
37
+ return (
38
+ button.canSee &&
39
+ <>
40
+ <button
41
+ key={`button-${button.label}`}
42
+ className={
43
+ button.disabled ? 'messenger__chat-button messenger__chat-button--disabled'
44
+ : 'messenger__chat-button'
45
+ }
46
+ onClick={(event) => {
47
+ button.onClick()
48
+ removeActiveItem(event)
49
+ }}
50
+ style={
51
+ getButtonType(button.type, button.disabled)
52
+ }>
53
+ {button.label}
54
+ </button>
55
+ </>
56
+ )
57
+ }))
58
+ }
59
+ </>
60
+ )
61
+ }
62
+
63
+ export default ChatButtons
@@ -0,0 +1,18 @@
1
+ .chat-tabs {
2
+ display: flex;
3
+ justify-content: center;
4
+ align-items: center;
5
+ &__button {
6
+ background: transparent;
7
+ border: none;
8
+ border-bottom: 1px solid transparent;
9
+ cursor: pointer;
10
+ padding: 0.5rem 1rem;
11
+ margin-bottom: 0.5rem;
12
+
13
+ &--active {
14
+ border-bottom: 1px solid white;
15
+ transition: 0.5s;
16
+ }
17
+ }
18
+ }
@@ -0,0 +1,32 @@
1
+ import useTheme from '../../hooks/useThemes'
2
+ import { activeItem } from '../../views/MessengerListItem'
3
+ import React from 'react'
4
+
5
+ interface IProps {
6
+ handleChangeTickets: (tab: string) => void
7
+ chatListTabs: { value: string, label: string }[]
8
+ }
9
+
10
+ function ChatTabs ({handleChangeTickets, chatListTabs }: IProps) {
11
+ const { theme }= useTheme()
12
+ return (
13
+ <div className="chat-tabs" style={
14
+ {color: theme.asideFontColor}
15
+ }>
16
+ {chatListTabs.map((tab, index )=> {return (
17
+ <button
18
+ key={`chatListTab-${index}`}
19
+ className={`chat-tabs__button ${ index === 0 && 'chat-tabs__button--active'}`}
20
+ onClick={(e) => {
21
+ handleChangeTickets(tab.value)
22
+ activeItem(e, 'chat-tabs__button', 'chat-tabs__button--active')
23
+ }}
24
+ >
25
+ {tab.label}
26
+ </button>
27
+ )})}
28
+ </div>
29
+ )
30
+ }
31
+
32
+ export default ChatTabs
@@ -0,0 +1,64 @@
1
+ .images-container {
2
+ width: 100%;
3
+ height: 90%;
4
+ border: 2px solid @secondary-bg-color-chat;
5
+ background-color: @component-background;
6
+ border-bottom: none;
7
+ border-radius: 0 @border-radius 0 0;
8
+
9
+ &__close {
10
+ width: 100%;
11
+ position: relative;
12
+ margin-top: 15px;
13
+ display: flex;
14
+ justify-content: flex-end;
15
+ align-items: center;
16
+
17
+ &--icon {
18
+ width: 32px;
19
+ height: 32px;
20
+ cursor: pointer;
21
+ background-color: transparent;
22
+ outline: none;
23
+ border: none;
24
+
25
+ &:hover {
26
+ opacity: 75%;
27
+ transition: 200ms;
28
+ }
29
+
30
+ &::before,
31
+ &::after {
32
+ position: absolute;
33
+ right: 25px;
34
+ top: 0;
35
+ content: ' ';
36
+ height: 33px;
37
+ width: 2px;
38
+ background-color: red;
39
+ }
40
+
41
+ &:after{
42
+ transform: rotate(45deg);
43
+ }
44
+
45
+ &:before{
46
+ transform: rotate(-45deg);
47
+ }
48
+ }
49
+ }
50
+
51
+ &__container {
52
+ width: 100%;
53
+ height: 100%;
54
+
55
+ display: flex;
56
+ align-items: center;
57
+ justify-content: center;
58
+ }
59
+
60
+ &__image {
61
+ max-width: 700px;
62
+ max-height: 300px;
63
+ }
64
+ }
@@ -0,0 +1,40 @@
1
+ import React, { useEffect, useState } from 'react'
2
+ import { IImagesContainer } from 'types'
3
+
4
+ function ImagesContainer ({ file, onClose }: IImagesContainer) {
5
+ const [b64, setB64] = useState<string>('')
6
+
7
+ useEffect(() => {
8
+ function getBase64 (file: File) {
9
+ return new Promise((resolve, reject) => {
10
+ const reader = new FileReader()
11
+ reader.readAsDataURL(file)
12
+ reader.onload = () => resolve(reader.result)
13
+ reader.onerror = (error) => reject(error)
14
+ })
15
+ }
16
+
17
+ if (file) getBase64(file).then(base64 => setB64(base64 as string))
18
+ }, [file])
19
+
20
+ return (
21
+ <div className="images-container">
22
+ <div className="images-container__close">
23
+ <button
24
+ className="images-container__close--icon"
25
+ onClick={onClose}
26
+ />
27
+ </div>
28
+
29
+ <div className="images-container__container">
30
+ <img
31
+ alt='arquivos enviados pelo chat agx'
32
+ src={b64}
33
+ className="images-container__image"
34
+ />
35
+ </div>
36
+ </div>
37
+ )
38
+ }
39
+
40
+ export default ImagesContainer
@@ -0,0 +1,59 @@
1
+ import useTheme from '../../hooks/useThemes'
2
+ import React, { useCallback, useState } from 'react'
3
+ import { IInconmingMessage } from 'types'
4
+ import MessengerAvatar from '../MessengerAvatar/MessengerAvatar'
5
+ import ReactSimpleImageViewer from '../../../../../node_modules/react-simple-image-viewer'
6
+ function IncomingMessage ({ date, message, user, hasFile, file, isSystemMessage, formatDate, id }: IInconmingMessage) {
7
+ const {theme} = useTheme()
8
+ const [currentImage, setCurrentImage] = useState(0);
9
+ const [isViewerOpen, setIsViewerOpen] = useState(false);
10
+
11
+ const openImageViewer = useCallback((index) => {
12
+ setCurrentImage(index);
13
+ setIsViewerOpen(true);
14
+ }, []);
15
+
16
+ const closeImageViewer = () => {
17
+ setCurrentImage(0);
18
+ setIsViewerOpen(false);
19
+ };
20
+
21
+ return (
22
+ <div
23
+ className="messenger__messages-row--received"
24
+ id={id}
25
+ >
26
+ {(user.avatar || user.name) && !isSystemMessage && (
27
+ <div className="messenger__message-avatar mr-2">
28
+ <MessengerAvatar image={user.avatar}>{user.name.slice(0, 1)}</MessengerAvatar>
29
+ </div>
30
+ )}
31
+
32
+ <div className="messenger__messages-received" style={{background: theme?.messengerIncomerColor}}>
33
+ {!isSystemMessage && <p className="messenger__message-title">{user.name}</p>}
34
+
35
+ <span>
36
+ {hasFile && (
37
+ <div className="messenger__message--file">
38
+ <img src={file?.location} width={200} alt="imagem na mensagem" onClick={() => openImageViewer(currentImage)}/>
39
+ </div>
40
+ )}
41
+ <p className="messenger__message">{message}</p>
42
+ <p className="messenger__message--date">{formatDate(date) ?? new Date(date).toString()}</p>
43
+ </span>
44
+
45
+ </div>
46
+ {file && isViewerOpen &&
47
+ <ReactSimpleImageViewer
48
+ src={[file.location]}
49
+ currentIndex={0}
50
+ disableScroll={false}
51
+ closeOnClickOutside={true}
52
+ onClose={closeImageViewer}
53
+ />
54
+ }
55
+ </div>
56
+ )
57
+ }
58
+
59
+ export default IncomingMessage
@@ -0,0 +1,52 @@
1
+ import React, { ReactNode, CSSProperties } from 'react'
2
+
3
+ interface IInfiniteScroll {
4
+ loading: boolean
5
+ more: boolean
6
+ fetch: () => void
7
+ children: ReactNode
8
+ loadingCover: React.ReactElement
9
+ root: Element | null
10
+ }
11
+
12
+ const style: CSSProperties = {
13
+ width: 25,
14
+ height: 25,
15
+ visibility: 'hidden'
16
+ }
17
+
18
+ function InfiniteScroll({ loading, loadingCover, more, fetch, children, root }: IInfiniteScroll) {
19
+ const [infiniteElement, SetInfiniteElement] = React.useState<HTMLDivElement | null>(null)
20
+
21
+ React.useEffect(() => {
22
+ if (!root) return
23
+ const currentElement = infiniteElement
24
+ const observer = new IntersectionObserver(entries => {
25
+ const first = entries[0]
26
+ if (first.isIntersecting === true) fetch()
27
+ }, {
28
+ root,
29
+ rootMargin: '400px',
30
+ threshold: .5
31
+ })
32
+
33
+ if (currentElement) {
34
+ observer.observe(currentElement)
35
+ }
36
+
37
+ return () => {
38
+ if (currentElement) observer.unobserve(currentElement)
39
+ }
40
+
41
+ }, [infiniteElement])
42
+
43
+ return (
44
+ <>
45
+ {children}
46
+ {loading && loadingCover}
47
+ {(more && !loading) && <div ref={SetInfiniteElement} style={style}></div>}
48
+ </>
49
+ )
50
+ }
51
+
52
+ export default InfiniteScroll