@chat21/chat21-web-widget 5.1.25 → 5.1.26-rc1
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.
- package/.github/workflows/docker-community-push-latest.yml +23 -13
- package/.github/workflows/docker-image-tag-community-tag-push.yml +22 -12
- package/CHANGELOG.md +67 -11
- package/Dockerfile +4 -5
- package/angular.json +2 -1
- package/deploy_amazon_beta.sh +17 -7
- package/package.json +1 -1
- package/src/app/app.component.html +8 -1
- package/src/app/app.component.scss +59 -0
- package/src/app/app.component.ts +62 -27
- package/src/app/component/conversation-detail/conversation/conversation.component.ts +18 -4
- package/src/app/component/conversation-detail/conversation-audio-recorder/conversation-audio-recorder.component.ts +16 -3
- package/src/app/component/conversation-detail/conversation-footer/conversation-footer.component.scss +25 -0
- package/src/app/component/conversation-detail/conversation-footer/conversation-footer.component.ts +34 -1
- package/src/app/component/launcher-button/launcher-button.component.html +1 -1
- package/src/app/component/launcher-button/launcher-button.component.ts +3 -2
- package/src/app/component/message-attachment/message-attachment.component.scss +1 -1
- package/src/app/providers/translator.service.ts +2 -0
- package/src/app/utils/globals.ts +1 -1
- package/src/assets/i18n/en.json +1 -0
- package/src/assets/i18n/es.json +1 -0
- package/src/assets/i18n/fr.json +1 -0
- package/src/assets/i18n/it.json +1 -0
- package/src/chat21-core/providers/tiledesk/tiledesk-requests.service.ts +1 -1
- package/src/chat21-core/utils/utils.ts +5 -2
- package/src/iframe-style.css +5 -5
- package/src/launch.js +6 -61
- package/src/launch_template.js +6 -61
- package/deploy_amazon_prod.sh +0 -41
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
name: Docker Image Community latest CI
|
|
2
2
|
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
5
|
branches: [ master ]
|
|
6
|
-
pull_request:
|
|
7
|
-
branches: [ master ]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [ master ]
|
|
8
8
|
|
|
9
9
|
jobs:
|
|
10
10
|
push_to_registry:
|
|
@@ -12,12 +12,22 @@ jobs:
|
|
|
12
12
|
runs-on: ubuntu-latest
|
|
13
13
|
|
|
14
14
|
steps:
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
15
|
+
- name: Check out the repo
|
|
16
|
+
uses: actions/checkout@v2
|
|
17
|
+
|
|
18
|
+
- name: Set up Docker Buildx
|
|
19
|
+
uses: docker/setup-buildx-action@v2
|
|
20
|
+
|
|
21
|
+
- name: Log in to Docker Hub
|
|
22
|
+
uses: docker/login-action@v2
|
|
23
|
+
with:
|
|
24
|
+
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
25
|
+
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
26
|
+
|
|
27
|
+
- name: Build and push multiarch Docker image
|
|
28
|
+
uses: docker/build-push-action@v3
|
|
29
|
+
with:
|
|
30
|
+
context: .
|
|
31
|
+
push: true
|
|
32
|
+
platforms: linux/amd64,linux/arm64
|
|
33
|
+
tags: chat21/chat21-web-widget:latest
|
|
@@ -3,20 +3,30 @@ name: Publish Docker Community image tags
|
|
|
3
3
|
on:
|
|
4
4
|
push:
|
|
5
5
|
tags:
|
|
6
|
-
- '**'
|
|
7
|
-
jobs:
|
|
6
|
+
- '**' # Trigger su qualsiasi tag
|
|
8
7
|
|
|
8
|
+
jobs:
|
|
9
9
|
push_to_registry:
|
|
10
10
|
name: Push Docker image to Docker Hub
|
|
11
11
|
runs-on: ubuntu-latest
|
|
12
|
+
|
|
12
13
|
steps:
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
14
|
+
- name: Check out the repo
|
|
15
|
+
uses: actions/checkout@v2
|
|
16
|
+
|
|
17
|
+
- name: Set up Docker Buildx
|
|
18
|
+
uses: docker/setup-buildx-action@v2
|
|
19
|
+
|
|
20
|
+
- name: Log in to Docker Hub
|
|
21
|
+
uses: docker/login-action@v2
|
|
22
|
+
with:
|
|
23
|
+
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
24
|
+
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
25
|
+
|
|
26
|
+
- name: Build and push multiarch Docker image
|
|
27
|
+
uses: docker/build-push-action@v3
|
|
28
|
+
with:
|
|
29
|
+
context: .
|
|
30
|
+
push: true
|
|
31
|
+
platforms: linux/amd64,linux/arm64
|
|
32
|
+
tags: chat21/chat21-web-widget:${{ github.ref_name }}
|
package/CHANGELOG.md
CHANGED
|
@@ -6,26 +6,33 @@
|
|
|
6
6
|
### **Copyrigth**:
|
|
7
7
|
*Tiledesk SRL*
|
|
8
8
|
|
|
9
|
-
# 5.1.
|
|
9
|
+
# 5.1.26-rc1
|
|
10
|
+
- **bug fixed**: improved audio recording/upload flow by ignoring empty recorder chunks, preserving the recorder MIME type when creating the audio blob/file, and uploading audio directly without Base64 conversion
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
# 5.1.25-rc1
|
|
10
14
|
- **bug fixed**: attachment buttons in messages now respect the container max width and wrap/break long labels instead of being clipped
|
|
11
15
|
|
|
12
|
-
# 5.1.24
|
|
16
|
+
# 5.1.24-rc2
|
|
17
|
+
- **bug fixed**: minor fix in marked pipe to avoid rendering html tags
|
|
18
|
+
|
|
19
|
+
# 5.1.24-rc1
|
|
13
20
|
- **security**: hardened Markdown link rendering by blocking dangerous protocols (e.g. `javascript:`, `data:`, `vbscript:`) and preventing unsafe links from being rendered as anchors
|
|
14
21
|
- **changed**: refactored `MarkedPipe` to simplify Markdown parsing, improve link rendering via a custom `marked` renderer, and streamline newline handling (`\\n` → `\n`)
|
|
15
22
|
|
|
16
|
-
# 5.1.
|
|
17
|
-
- **changed**: API for upload a file/iamges
|
|
18
|
-
|
|
19
|
-
# 5.1.22
|
|
20
|
-
- **changed**: Updated Launch.js for Wix and Shopify by bypassing scrdoc
|
|
21
|
-
|
|
22
|
-
# 5.1.21
|
|
23
|
+
# 5.1.20-rc3
|
|
23
24
|
- **bug fixed**: saved the widget's size state to local storage (in HP conversations)
|
|
24
25
|
|
|
25
|
-
# 5.1.20
|
|
26
|
+
# 5.1.20-rc2
|
|
27
|
+
- **changed**: API for upload a file/iamges
|
|
26
28
|
- **changed**: marked pipe do not render /n
|
|
27
29
|
|
|
30
|
+
# 5.1.20-rc1
|
|
31
|
+
- **changed**: API for upload a file/iamges
|
|
32
|
+
|
|
28
33
|
# 5.1.19
|
|
34
|
+
|
|
35
|
+
# 5.1.19-rc1
|
|
29
36
|
- **bug fixed**: show bottom scroll button and unread message badge only when I'm not at the bottom of the page
|
|
30
37
|
- **changed**: allow HTML code to be inserted into messages, but do not parse the code. Ensure coexistence with Markdown.
|
|
31
38
|
- **bug fixed**: after sending a multi-line message, the text area remains open on multiple lines.
|
|
@@ -35,6 +42,7 @@
|
|
|
35
42
|
- **changed**: saved the widget's size state to local storage. The parameter flow is (default → storage → settings → URL)
|
|
36
43
|
|
|
37
44
|
# 5.1.18
|
|
45
|
+
# 5.1.15-rc3
|
|
38
46
|
- **added**: Implemented Shadow DOM in the text component to isolate HTML and Markdown rendering in a safe and protected context
|
|
39
47
|
- **changed**: Adapted text component styles to support Shadow DOM (removed ::ng-deep, added styles for common markdown elements)
|
|
40
48
|
- **security**: HTML/Markdown content is now rendered in an isolated Shadow DOM, improving security and preventing interference with the rest of the application
|
|
@@ -45,6 +53,12 @@
|
|
|
45
53
|
# 5.1.16
|
|
46
54
|
- **changed**: "close chat" header conversation menu button enabled in chatbot-panel.html
|
|
47
55
|
|
|
56
|
+
# 5.1.15-rc2
|
|
57
|
+
- **bug-fixed**: Bug fix for ifame message width
|
|
58
|
+
|
|
59
|
+
# 5.1.15-rc1
|
|
60
|
+
- **changed**: Load local translations before remote ones
|
|
61
|
+
|
|
48
62
|
# 5.1.15
|
|
49
63
|
- **changed**: Load local translations before remote ones
|
|
50
64
|
|
|
@@ -53,14 +67,56 @@
|
|
|
53
67
|
|
|
54
68
|
# 5.1.13
|
|
55
69
|
- **bug-fixed**: set default widget size
|
|
70
|
+
|
|
71
|
+
# 5.1.7-rc16
|
|
72
|
+
- **bug-fixed**: set default widget size
|
|
73
|
+
|
|
74
|
+
# 5.1.7-rc15
|
|
75
|
+
- **bug-fixed**: set the color of the buttons with visibility control to the font color
|
|
76
|
+
|
|
77
|
+
# 5.1.7-rc14
|
|
78
|
+
- **bug-fixed**: departmentId and departmentName is incorrect in attributes
|
|
79
|
+
|
|
80
|
+
# 5.1.7-rc13
|
|
81
|
+
- **changed**: Force authentication if ageChangeVisibilityDesktop or PageChangeVisibilityMobile is OPEN
|
|
82
|
+
|
|
83
|
+
# 5.1.7-rc12
|
|
84
|
+
- **changed**: Set the default autoStart value to false
|
|
85
|
+
- **added**: Added the open widget loading spinner
|
|
86
|
+
- **changed**: Load the widget without authentication and display the speech bubble
|
|
87
|
+
|
|
88
|
+
# 5.1.7-rc11
|
|
89
|
+
- **changed**: set default value autoStart false
|
|
90
|
+
- **added**:added loading spinner
|
|
91
|
+
|
|
92
|
+
# 5.1.7-rc10
|
|
93
|
+
- **changed**: load widget without authentication and display the balloon
|
|
94
|
+
|
|
95
|
+
# 5.1.7-rc9
|
|
96
|
+
- **removed**: 'DOMAIN_NOT_ALLOWED' in textarea footer component
|
|
97
|
+
|
|
98
|
+
# 5.1.7-rc8
|
|
99
|
+
# changes in the branch
|
|
100
|
+
- **changed**: Load local translations before remote ones
|
|
101
|
+
- **bug-fixed**: set default widget size
|
|
56
102
|
- **changed**: Updated the translations of the tooltips in the footer-component
|
|
57
103
|
- **changed**: Refactored the network-offline component and made it generic for displaying errors (now error-alert.component)
|
|
58
|
-
|
|
104
|
+
|
|
105
|
+
# 5.1.7-rc7
|
|
106
|
+
- **bug-fixed**: button new_conversation always appear. added subscription to conversationAdded
|
|
107
|
+
|
|
108
|
+
# 5.1.7-rc6
|
|
109
|
+
- **added**: Added MAX_ATTACHMENT_ERROR error message when uploading a file larger than 10 MB
|
|
59
110
|
|
|
60
111
|
# 5.1.12
|
|
61
112
|
- **bug-fixed**: check showEmojiFooterButton to enable/disable emojii
|
|
62
113
|
- **bug-fixed**: markdown is fired as an emojii and blocked by isEmojii check fn
|
|
63
114
|
|
|
115
|
+
# 5.1.7-rc7
|
|
116
|
+
- **bug-fixed**: button new_conversation always appear. added subscription to conversationAdded
|
|
117
|
+
|
|
118
|
+
# 5.1.7-rc6
|
|
119
|
+
- **added**: Added MAX_ATTACHMENT_ERROR error message when uploading a file larger than 10 MB
|
|
64
120
|
|
|
65
121
|
# 5.1.7-rc5
|
|
66
122
|
- **bug-fixed**: bug fixed BUTTON STYLES
|
package/Dockerfile
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
### STAGE 1: Build ###
|
|
2
2
|
|
|
3
3
|
# We label our stage as ‘builder’
|
|
4
|
-
FROM node:20.12.2-alpine3.19 as builder
|
|
4
|
+
FROM --platform=$BUILDPLATFORM node:20.12.2-alpine3.19 as builder
|
|
5
5
|
|
|
6
6
|
COPY package.json package-lock.json ./
|
|
7
7
|
|
|
@@ -15,12 +15,11 @@ COPY . .
|
|
|
15
15
|
|
|
16
16
|
## Build the angular app in production mode and store the artifacts in dist folder
|
|
17
17
|
|
|
18
|
-
RUN npx ng build --configuration="prod" --output-path=dist --base-href=./ --output-hashing=none
|
|
19
18
|
|
|
19
|
+
RUN npx ng build --configuration="prod" --output-path=dist --base-href=./ --output-hashing=none
|
|
20
20
|
|
|
21
21
|
### STAGE 2: Setup ###
|
|
22
|
-
|
|
23
|
-
FROM nginx:1.14.1-alpine
|
|
22
|
+
FROM --platform=$BUILDPLATFORM nginx:1.14.1-alpine
|
|
24
23
|
|
|
25
24
|
## Copy our default nginx config
|
|
26
25
|
COPY nginx.conf /etc/nginx/nginx.conf
|
|
@@ -33,4 +32,4 @@ COPY --from=builder /ng-app/dist/browser /usr/share/nginx/html
|
|
|
33
32
|
|
|
34
33
|
RUN echo "Chat21 Web Widget Started!!"
|
|
35
34
|
|
|
36
|
-
CMD ["/bin/sh",
|
|
35
|
+
CMD ["/bin/sh", "-c", "envsubst < /usr/share/nginx/html/widget-config-template.json > /usr/share/nginx/html/widget-config.json && exec nginx -g 'daemon off;'"]
|
package/angular.json
CHANGED
|
@@ -44,7 +44,8 @@
|
|
|
44
44
|
"src/environments/real_data/widget-config-docker.json",
|
|
45
45
|
"src/environments/real_data/widget-config-native-mqtt.json",
|
|
46
46
|
"src/environments/real_data/widget-config-native-prod.json",
|
|
47
|
-
"src/environments/real_data/widget-config-aws-stage.json"
|
|
47
|
+
"src/environments/real_data/widget-config-aws-stage.json",
|
|
48
|
+
"src/environments/real_data/widget-config-aws-aruba.json"
|
|
48
49
|
],
|
|
49
50
|
"styles": [
|
|
50
51
|
"src/app/sass/styles.scss"
|
package/deploy_amazon_beta.sh
CHANGED
|
@@ -2,8 +2,16 @@
|
|
|
2
2
|
version=`node -e 'console.log(require("./package.json").version)'`
|
|
3
3
|
echo "version $version"
|
|
4
4
|
|
|
5
|
+
npm i
|
|
6
|
+
|
|
7
|
+
cp src/environments/real_data/environment.pre.ts src/environments/environment.pre.ts
|
|
8
|
+
|
|
5
9
|
ng build --configuration="pre" --aot=true --base-href
|
|
6
10
|
|
|
11
|
+
### SET HASHING : START ###
|
|
12
|
+
cp ./src/launch_template.js ./dist/browser/launch.js
|
|
13
|
+
node ./src/build_launch.js
|
|
14
|
+
### SET HASHING : END ###
|
|
7
15
|
|
|
8
16
|
# ########## --->>>> NATIVE-MQTT folder START <<<<<------ ########## #
|
|
9
17
|
|
|
@@ -23,15 +31,17 @@ ng build --configuration="pre" --aot=true --base-href
|
|
|
23
31
|
|
|
24
32
|
|
|
25
33
|
# ########## --->>>> FIREBASE folder START <<<<<------ ########## #
|
|
26
|
-
cd dist
|
|
27
|
-
aws s3 sync . s3://tiledesk-widget-pre/v5/$version/ --cache-control max-age=300
|
|
28
|
-
aws s3 sync . s3://tiledesk-widget-pre/v5/ --cache-control
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
cd ..
|
|
34
|
+
cd dist/browser
|
|
35
|
+
aws s3 sync . s3://tiledesk-widget-pre/v5/$version/ --cache-control max-age=300 --exclude='launch.js' #7days
|
|
36
|
+
aws s3 sync . s3://tiledesk-widget-pre/v5/$version/ --cache-control "no-store,no-cache,private" --exclude='*' --include='launch.js'
|
|
37
|
+
aws s3 sync . s3://tiledesk-widget-pre/v5/ --cache-control max-age=300 --exclude='launch.js' #7days
|
|
38
|
+
aws s3 sync . s3://tiledesk-widget-pre/v5/ --cache-control "no-store,no-cache,private" --exclude='*' --include='launch.js'
|
|
39
|
+
cd ../..
|
|
33
40
|
|
|
34
41
|
aws cloudfront create-invalidation --distribution-id E2V5O0YPR61V8P --paths "/*"
|
|
42
|
+
|
|
43
|
+
git restore src/environments/environment.pre.ts
|
|
44
|
+
|
|
35
45
|
# echo new version deployed $NEW_VER/$NEW_BUILD/ on s3://tiledesk-widget-pre/v2
|
|
36
46
|
echo new version deployed $version/ on s3://tiledesk-widget-pre/v5 and s3://tiledesk-widget-pre/v5/$version/
|
|
37
47
|
echo available on https://s3.eu-west-1.amazonaws.com/tiledesk-widget-pre/v5/index.html
|
package/package.json
CHANGED
|
@@ -145,5 +145,12 @@
|
|
|
145
145
|
<chat-launcher-button *ngIf="isInitialized"
|
|
146
146
|
(onButtonClicked)="onOpenCloseWidget($event)">
|
|
147
147
|
</chat-launcher-button>
|
|
148
|
-
|
|
148
|
+
|
|
149
|
+
<!-- Loading Spinner -->
|
|
150
|
+
<div *ngIf="loading" class="tiledesk-loading-overlay">
|
|
151
|
+
<div class="tiledesk-loading-spinner">
|
|
152
|
+
<div class="spinner-circle"></div>
|
|
153
|
+
<div class="loading-text">{{ translationMap.get('LABEL_LOADING') }}</div>
|
|
154
|
+
</div>
|
|
155
|
+
</div>
|
|
149
156
|
</div>
|
|
@@ -761,4 +761,63 @@ chat-root {
|
|
|
761
761
|
}
|
|
762
762
|
}
|
|
763
763
|
|
|
764
|
+
// ========= BEGIN: LOADING SPINNER ========= //
|
|
765
|
+
.tiledesk-loading-overlay {
|
|
766
|
+
position: absolute;
|
|
767
|
+
top: 0;
|
|
768
|
+
left: 0;
|
|
769
|
+
width: 100%;
|
|
770
|
+
height: 100%;
|
|
771
|
+
background-color: rgba(248, 249, 250, 0.95);
|
|
772
|
+
display: flex;
|
|
773
|
+
justify-content: center;
|
|
774
|
+
align-items: center;
|
|
775
|
+
z-index: 9999;
|
|
776
|
+
backdrop-filter: blur(2px);
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
.tiledesk-loading-spinner {
|
|
780
|
+
display: flex;
|
|
781
|
+
flex-direction: column;
|
|
782
|
+
align-items: center;
|
|
783
|
+
gap: 16px;
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
.spinner-circle {
|
|
787
|
+
width: 50px;
|
|
788
|
+
height: 50px;
|
|
789
|
+
border: 4px solid rgba(59, 130, 246, 0.2);
|
|
790
|
+
border-top-color: #3b82f6;
|
|
791
|
+
border-radius: 50%;
|
|
792
|
+
animation: spin 0.8s linear infinite;
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
@keyframes spin {
|
|
796
|
+
0% {
|
|
797
|
+
transform: rotate(0deg);
|
|
798
|
+
}
|
|
799
|
+
100% {
|
|
800
|
+
transform: rotate(360deg);
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
.loading-text {
|
|
805
|
+
font-family: var(--font-family-bubble-message, 'Roboto', 'Google Sans', Helvetica, Arial, sans-serif);
|
|
806
|
+
font-size: 14px;
|
|
807
|
+
font-weight: 500;
|
|
808
|
+
color: #3b82f6;
|
|
809
|
+
letter-spacing: 0.5px;
|
|
810
|
+
animation: pulse 1.5s ease-in-out infinite;
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
@keyframes pulse {
|
|
814
|
+
0%, 100% {
|
|
815
|
+
opacity: 1;
|
|
816
|
+
}
|
|
817
|
+
50% {
|
|
818
|
+
opacity: 0.5;
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
// ========= END: LOADING SPINNER ========= //
|
|
822
|
+
|
|
764
823
|
}
|
package/src/app/app.component.ts
CHANGED
|
@@ -106,6 +106,10 @@ export class AppComponent implements OnInit, AfterViewInit, OnDestroy {
|
|
|
106
106
|
|
|
107
107
|
forceDisconnect: boolean = false;
|
|
108
108
|
|
|
109
|
+
//network status
|
|
110
|
+
isOnline: boolean = true;
|
|
111
|
+
loading: boolean = false;
|
|
112
|
+
|
|
109
113
|
// alert error message
|
|
110
114
|
isShowErrorMessage: boolean = false;
|
|
111
115
|
errorMessage: string = '';
|
|
@@ -149,7 +153,7 @@ export class AppComponent implements OnInit, AfterViewInit, OnDestroy {
|
|
|
149
153
|
this.logger.info('[APP-CONF]---------------- ngAfterViewInit: APP.COMPONENT ---------------- ')
|
|
150
154
|
|
|
151
155
|
// Initialize translation map and enable buttons
|
|
152
|
-
const keys = ['MAXIMIZE', 'MINIMIZE', 'CENTER', 'BUTTON_CLOSE_TO_ICON'];
|
|
156
|
+
const keys = ['MAXIMIZE', 'MINIMIZE', 'CENTER', 'BUTTON_CLOSE_TO_ICON', 'LABEL_LOADING'];
|
|
153
157
|
this.translationMap = this.translateService.translateLanguage(keys);
|
|
154
158
|
this.isButtonsDisabled = false;
|
|
155
159
|
|
|
@@ -316,8 +320,15 @@ export class AppComponent implements OnInit, AfterViewInit, OnDestroy {
|
|
|
316
320
|
this.g.setIsOpen(isOpen)
|
|
317
321
|
this.appStorageService.setItem('isOpen', isOpen)
|
|
318
322
|
}
|
|
319
|
-
|
|
320
|
-
|
|
323
|
+
|
|
324
|
+
if(this.g.onPageChangeVisibilityDesktop === 'last'){
|
|
325
|
+
this.logger.debug('[APP-COMP2] ------this.g.isOpen: ', this.g.isOpen)
|
|
326
|
+
if(this.g.isOpen){
|
|
327
|
+
this.g.autoStart = true;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
|
|
321
332
|
/**CHECK IF JWT IS IN URL PARAMETERS */
|
|
322
333
|
this.logger.debug('[APP-COMP] check if token is passed throw url: ', this.g.jwt);
|
|
323
334
|
if (this.g.jwt) {
|
|
@@ -354,10 +365,6 @@ export class AppComponent implements OnInit, AfterViewInit, OnDestroy {
|
|
|
354
365
|
this.subscriptions.push(obsSettingsService);
|
|
355
366
|
this.globalSettingsService.initWidgetParamiters(this.g, this.el);
|
|
356
367
|
|
|
357
|
-
// SET AUDIO
|
|
358
|
-
this.audio = new Audio();
|
|
359
|
-
this.audio.src = this.g.baseLocation + URL_SOUND_LIST_CONVERSATION;
|
|
360
|
-
this.audio.load();
|
|
361
368
|
}
|
|
362
369
|
|
|
363
370
|
private initAll() {
|
|
@@ -448,7 +455,7 @@ export class AppComponent implements OnInit, AfterViewInit, OnDestroy {
|
|
|
448
455
|
that.triggerOnAuthStateChanged(that.stateLoggedUser);
|
|
449
456
|
that.logger.debug('[APP-COMP] 1 - IMPOSTO STATO CONNESSO UTENTE ', autoStart);
|
|
450
457
|
|
|
451
|
-
|
|
458
|
+
this.initAudioNotification()
|
|
452
459
|
|
|
453
460
|
new Promise(async (resolve, reject)=> {
|
|
454
461
|
that.typingService.initialize(this.g.tenant);
|
|
@@ -474,26 +481,30 @@ export class AppComponent implements OnInit, AfterViewInit, OnDestroy {
|
|
|
474
481
|
that.listenToWidgetClick()
|
|
475
482
|
}
|
|
476
483
|
|
|
484
|
+
/** DDP IF AUTOSTART IS FALSE, SHOW WIDGET */
|
|
485
|
+
if(!autoStart){
|
|
486
|
+
that.logger.info('[APP-COMP] AUTOSTART IS FALSE AND LOGGED SUCCESSFULLY ');
|
|
487
|
+
this.g.setParameter('isShown', true, true);
|
|
488
|
+
}
|
|
477
489
|
|
|
478
490
|
|
|
479
491
|
} else if (state && state === AUTH_STATE_OFFLINE && !this.forceDisconnect) {
|
|
480
492
|
/** non sono loggato */
|
|
481
493
|
that.logger.info('[APP-COMP] OFFLINE - NO CURRENT USER AUTENTICATE: ');
|
|
482
494
|
that.g.setParameter('isLogged', false);
|
|
483
|
-
that.hideWidget();
|
|
495
|
+
// that.hideWidget();
|
|
484
496
|
// that.g.setParameter('isShown', false, true);
|
|
485
497
|
that.triggerOnAuthStateChanged(that.stateLoggedUser);
|
|
486
|
-
if (autoStart) {
|
|
498
|
+
if (autoStart || this.g.onPageChangeVisibilityDesktop === 'open' || this.g.onPageChangeVisibilityMobile === 'open') {
|
|
487
499
|
that.authenticate();
|
|
488
500
|
}
|
|
489
|
-
}else if(state && state === AUTH_STATE_CLOSE ){
|
|
501
|
+
} else if(state && state === AUTH_STATE_CLOSE ){
|
|
490
502
|
that.logger.info('[APP-COMP] CLOSE - CHANNEL CLOSED: ', this.chatManager);
|
|
491
503
|
if(this.g.recipientId){
|
|
492
504
|
this.chatManager.removeConversationHandler(this.g.recipientId)
|
|
493
505
|
this.g.recipientId = null;
|
|
494
506
|
}
|
|
495
|
-
}
|
|
496
|
-
|
|
507
|
+
}
|
|
497
508
|
|
|
498
509
|
});
|
|
499
510
|
this.subscriptions.push(subAuthStateChanged);
|
|
@@ -738,6 +749,8 @@ export class AppComponent implements OnInit, AfterViewInit, OnDestroy {
|
|
|
738
749
|
// divWidgetContainer.style.display = 'block';
|
|
739
750
|
// }
|
|
740
751
|
// }, 500);
|
|
752
|
+
|
|
753
|
+
this.loading = false;
|
|
741
754
|
}
|
|
742
755
|
// ========= end:: START UI ============//
|
|
743
756
|
|
|
@@ -846,7 +859,13 @@ export class AppComponent implements OnInit, AfterViewInit, OnDestroy {
|
|
|
846
859
|
this.appStorageService.setItem('attributes', JSON.stringify(attributes));
|
|
847
860
|
return attributes;
|
|
848
861
|
}
|
|
849
|
-
|
|
862
|
+
|
|
863
|
+
// SET AUDIO
|
|
864
|
+
private initAudioNotification(){
|
|
865
|
+
this.audio = new Audio();
|
|
866
|
+
this.audio.src = this.g.baseLocation + URL_SOUND_LIST_CONVERSATION;
|
|
867
|
+
this.audio.load();
|
|
868
|
+
}
|
|
850
869
|
|
|
851
870
|
private async initConversationsHandler(tenant: string, senderId: string) {
|
|
852
871
|
this.logger.debug('[APP-COMP] initialize: ListConversationsComponent');
|
|
@@ -1605,23 +1624,46 @@ export class AppComponent implements OnInit, AfterViewInit, OnDestroy {
|
|
|
1605
1624
|
this.f21_close();
|
|
1606
1625
|
}
|
|
1607
1626
|
|
|
1627
|
+
|
|
1628
|
+
/** DDP reload widget */
|
|
1629
|
+
async reloadWidget() {
|
|
1630
|
+
this.openCloseWidget();
|
|
1631
|
+
this.logger.debug('[APP-COMP-1] AAA - hideWidget');
|
|
1632
|
+
await Promise.all([
|
|
1633
|
+
this.authenticate(),
|
|
1634
|
+
// this.initAll()
|
|
1635
|
+
]);
|
|
1636
|
+
this.logger.debug('[APP-COMP-1] CCC - showWidget');
|
|
1637
|
+
}
|
|
1638
|
+
|
|
1639
|
+
|
|
1608
1640
|
/**
|
|
1609
1641
|
* LAUNCHER BUTTON:
|
|
1610
1642
|
* onClick button open/close widget
|
|
1611
1643
|
*/
|
|
1612
1644
|
onOpenCloseWidget($event) {
|
|
1645
|
+
this.logger.debug('[APP-COMP] onOpenCloseWidget', $event, this.g.isLogged);
|
|
1646
|
+
if(!this.g.isLogged){
|
|
1647
|
+
this.reloadWidget();
|
|
1648
|
+
} else {
|
|
1649
|
+
this.openCloseWidget();
|
|
1650
|
+
}
|
|
1651
|
+
}
|
|
1652
|
+
|
|
1653
|
+
/** DDP show widget */
|
|
1654
|
+
openCloseWidget() {
|
|
1613
1655
|
this.g.setParameter('displayEyeCatcherCard', 'none');
|
|
1614
1656
|
// const conversationActive: ConversationModel = JSON.parse(this.appStorageService.getItem('activeConversation'));
|
|
1615
1657
|
const recipientId : string = this.appStorageService.getItem('recipientId')
|
|
1616
1658
|
this.g.setParameter('recipientId', recipientId);
|
|
1617
1659
|
this.logger.debug('[APP-COMP] openCloseWidget', recipientId, this.g.isOpen, this.g.startFromHome);
|
|
1660
|
+
|
|
1618
1661
|
if (this.g.isOpen === false) {
|
|
1619
1662
|
if(this.forceDisconnect){
|
|
1620
1663
|
this.logger.log('[FORCE] onOpenCloseWidget --> reconnect', this.forceDisconnect)
|
|
1621
1664
|
this.messagingAuthService.createCustomToken(this.g.tiledeskToken)
|
|
1622
1665
|
this.forceDisconnect = false;
|
|
1623
1666
|
}
|
|
1624
|
-
|
|
1625
1667
|
if (!recipientId) {
|
|
1626
1668
|
if(this.g.singleConversation){
|
|
1627
1669
|
this.isOpenHome = false;
|
|
@@ -1641,29 +1683,22 @@ export class AppComponent implements OnInit, AfterViewInit, OnDestroy {
|
|
|
1641
1683
|
this.isOpenHome = false;
|
|
1642
1684
|
this.isOpenConversation = true;
|
|
1643
1685
|
this.startUI()
|
|
1644
|
-
// this.isOpenSelectionDepartment = false;
|
|
1645
1686
|
}
|
|
1646
|
-
// if (!conversationActive && !this.g.startFromHome) {
|
|
1647
|
-
// this.isOpenHome = false;
|
|
1648
|
-
// this.isOpenConversation = true;
|
|
1649
|
-
// this.startNwConversation();
|
|
1650
|
-
// } else if (conversationActive) {
|
|
1651
|
-
// this.isOpenHome = false;
|
|
1652
|
-
// this.isOpenConversation = true;
|
|
1653
|
-
// }
|
|
1654
|
-
// this.g.startFromHome = true;
|
|
1655
1687
|
this.triggerOnOpenEvent();
|
|
1656
|
-
|
|
1657
1688
|
} else {
|
|
1658
1689
|
this.triggerOnCloseEvent();
|
|
1659
1690
|
}
|
|
1660
1691
|
//change status to the widget
|
|
1661
1692
|
this.g.setIsOpen(!this.g.isOpen);
|
|
1662
1693
|
this.appStorageService.setItem('isOpen', this.g.isOpen);
|
|
1663
|
-
|
|
1694
|
+
//show loading if widget is open and user is not logged
|
|
1695
|
+
if(this.g.isOpen === true && !this.g.isLogged){
|
|
1696
|
+
this.loading = true;
|
|
1697
|
+
}
|
|
1664
1698
|
// this.saveBadgeNewConverstionNumber();
|
|
1665
1699
|
}
|
|
1666
1700
|
|
|
1701
|
+
|
|
1667
1702
|
/**
|
|
1668
1703
|
* MODAL SELECTION DEPARTMENT:
|
|
1669
1704
|
* selected department
|
|
@@ -470,7 +470,7 @@ export class ConversationComponent implements OnInit, AfterViewInit, OnChanges {
|
|
|
470
470
|
return this.isConversationArchived;
|
|
471
471
|
}
|
|
472
472
|
|
|
473
|
-
//FALLBACK TO TILEDESK
|
|
473
|
+
// //FALLBACK TO TILEDESK
|
|
474
474
|
const requests_list = await this.tiledeskRequestService.getMyRequests().catch(err => {
|
|
475
475
|
this.logger.error('[CONV-COMP] getConversationDetail: error getting request from Tiledesk', err);
|
|
476
476
|
this.isConversationArchived=true
|
|
@@ -488,9 +488,9 @@ export class ConversationComponent implements OnInit, AfterViewInit, OnChanges {
|
|
|
488
488
|
return this.isConversationArchived
|
|
489
489
|
}
|
|
490
490
|
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
491
|
+
this.isConversationArchived = false;
|
|
492
|
+
return null;
|
|
493
|
+
}
|
|
494
494
|
|
|
495
495
|
/**
|
|
496
496
|
* this.g.recipientId:
|
|
@@ -840,6 +840,20 @@ export class ConversationComponent implements OnInit, AfterViewInit, OnChanges {
|
|
|
840
840
|
this.subscriptions.push(subscribe);
|
|
841
841
|
}
|
|
842
842
|
|
|
843
|
+
subscribtionKey = 'conversationsAdded';
|
|
844
|
+
subscribtion = this.subscriptions.find(item => item.key === subscribtionKey);
|
|
845
|
+
if(!subscribtion){
|
|
846
|
+
|
|
847
|
+
subscribtion = this.chatManager.conversationsHandlerService.conversationChanged.pipe(takeUntil(this.unsubscribe$)).subscribe((conversation) => {
|
|
848
|
+
this.logger.debug('[CONV-COMP] ***** DATAIL conversationsChanged *****', conversation, this.conversationWith, this.isConversationArchived);
|
|
849
|
+
if(conversation && conversation.recipient === this.conversationId){
|
|
850
|
+
this.isConversationArchived = false
|
|
851
|
+
}
|
|
852
|
+
});
|
|
853
|
+
const subscribe = {key: subscribtionKey, value: subscribtion };
|
|
854
|
+
this.subscriptions.push(subscribe);
|
|
855
|
+
}
|
|
856
|
+
|
|
843
857
|
subscribtionKey = 'messageWait';
|
|
844
858
|
subscribtion = this.subscriptions.find(item => item.key === subscribtionKey);
|
|
845
859
|
if (!subscribtion) {
|
|
@@ -38,19 +38,32 @@ export class ConversationAudioRecorderComponent {
|
|
|
38
38
|
this.startTime = Date.now();
|
|
39
39
|
navigator.mediaDevices.getUserMedia({ audio: true })
|
|
40
40
|
.then(stream => {
|
|
41
|
+
|
|
42
|
+
this.audioChunks = [];
|
|
43
|
+
|
|
41
44
|
this.mediaRecorder = new MediaRecorder(stream);
|
|
42
45
|
this.mediaRecorder.start();
|
|
43
46
|
this.isRecording = true;
|
|
44
47
|
this.startRecordingEvent.emit();
|
|
45
48
|
this.mediaRecorder.addEventListener('dataavailable', (event) => {
|
|
46
|
-
|
|
49
|
+
if (event.data && event.data.size > 0) {
|
|
50
|
+
this.audioChunks.push(event.data);
|
|
51
|
+
}
|
|
47
52
|
});
|
|
48
53
|
|
|
49
54
|
this.mediaRecorder.addEventListener('stop', () => {
|
|
50
|
-
|
|
55
|
+
// ✅ MIME REALE del recorder
|
|
56
|
+
const mimeType = this.mediaRecorder.mimeType;
|
|
57
|
+
this.audioBlob = new Blob(this.audioChunks, {
|
|
58
|
+
type: mimeType
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
// ⭐ chiude microfono
|
|
62
|
+
stream.getTracks().forEach(track => track.stop());
|
|
63
|
+
|
|
64
|
+
this.audioChunks = [];
|
|
51
65
|
this.rawAudioUrl = URL.createObjectURL(this.audioBlob);
|
|
52
66
|
this.audioUrl = this.sanitizer.bypassSecurityTrustUrl(this.rawAudioUrl);
|
|
53
|
-
this.audioChunks = [];
|
|
54
67
|
this.endRecordingEvent.emit(this.audioBlob);
|
|
55
68
|
});
|
|
56
69
|
})
|
package/src/app/component/conversation-detail/conversation-footer/conversation-footer.component.scss
CHANGED
|
@@ -419,3 +419,28 @@ textarea:active{
|
|
|
419
419
|
border: none;
|
|
420
420
|
// margin: -2px -2px 0px;
|
|
421
421
|
}
|
|
422
|
+
|
|
423
|
+
|
|
424
|
+
// aggiungi un'animazione di fade in e fade out quando .star-rating-widget è visibile con transition
|
|
425
|
+
.star-rating-widget {
|
|
426
|
+
transition: all 0.5s ease-in-out;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
.star-rating-widget {
|
|
430
|
+
position: absolute;
|
|
431
|
+
left: 0;
|
|
432
|
+
right: 0;
|
|
433
|
+
bottom: -52px;
|
|
434
|
+
height: 100%;
|
|
435
|
+
width: 100%;
|
|
436
|
+
flex-direction: row;
|
|
437
|
+
justify-content: center;
|
|
438
|
+
background-color: rgb(255, 255, 255);
|
|
439
|
+
flex-wrap: nowrap;
|
|
440
|
+
&.active {
|
|
441
|
+
bottom: 0px;
|
|
442
|
+
}
|
|
443
|
+
&.inactive {
|
|
444
|
+
bottom: -52px;
|
|
445
|
+
}
|
|
446
|
+
}
|
package/src/app/component/conversation-detail/conversation-footer/conversation-footer.component.ts
CHANGED
|
@@ -87,6 +87,7 @@ export class ConversationFooterComponent implements OnInit, OnChanges {
|
|
|
87
87
|
|
|
88
88
|
file_size_limit = FILE_SIZE_LIMIT;
|
|
89
89
|
attachmentTooltip: string = '';
|
|
90
|
+
isErrorNetwork: boolean = false;
|
|
90
91
|
|
|
91
92
|
|
|
92
93
|
convertColorToRGBA = convertColorToRGBA;
|
|
@@ -513,14 +514,46 @@ export class ConversationFooterComponent implements OnInit, OnChanges {
|
|
|
513
514
|
onSendRecording(audioBlob: Blob | null) {
|
|
514
515
|
this.isStartRec = false;
|
|
515
516
|
if (audioBlob) {
|
|
516
|
-
this.
|
|
517
|
+
this.prepareAndUpload(audioBlob);
|
|
518
|
+
// this.convertBlobToBase64(audioBlob);
|
|
517
519
|
this.isStopRec = false;
|
|
518
520
|
} else {
|
|
519
521
|
this.isStopRec = false;
|
|
520
522
|
}
|
|
521
523
|
}
|
|
522
524
|
|
|
525
|
+
prepareAndUpload(audioBlob: Blob) {
|
|
523
526
|
|
|
527
|
+
this.isFilePendingToUpload = true;
|
|
528
|
+
|
|
529
|
+
// ⭐ NON modificare il MIME
|
|
530
|
+
const mimeType = audioBlob.type;
|
|
531
|
+
|
|
532
|
+
const size = audioBlob.size;
|
|
533
|
+
const uid = Date.now().toString(36);
|
|
534
|
+
|
|
535
|
+
// estensione coerente col MIME REALE
|
|
536
|
+
let ext = 'mp3';
|
|
537
|
+
const fileName = `audio-${uid}.${ext}`;
|
|
538
|
+
|
|
539
|
+
const file = new File([audioBlob], fileName, {
|
|
540
|
+
type: mimeType,
|
|
541
|
+
lastModified: Date.now()
|
|
542
|
+
});
|
|
543
|
+
|
|
544
|
+
// ✅ metadata SENZA base64
|
|
545
|
+
const metadata = {
|
|
546
|
+
name: fileName,
|
|
547
|
+
type: 'audio/mp3',
|
|
548
|
+
uid: uid,
|
|
549
|
+
size: size
|
|
550
|
+
};
|
|
551
|
+
|
|
552
|
+
this.logger.log('[UPLOAD] metadata:', metadata);
|
|
553
|
+
|
|
554
|
+
// stesso metodo che già usi
|
|
555
|
+
this.uploadSingle(metadata, file, '');
|
|
556
|
+
}
|
|
524
557
|
|
|
525
558
|
// Funzione per convertire Blob in Base64 usando FileReader
|
|
526
559
|
async convertBlobToBase64(audioBlob: Blob) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<!-- tabindex="000"-->
|
|
2
2
|
|
|
3
3
|
<button aflauncherbutton #aflauncherbutton id="c21-launcher-button" class="c21-button-clean scale-in-center"
|
|
4
|
-
*ngIf="g.
|
|
4
|
+
*ngIf="g.isOpen == false"
|
|
5
5
|
[ngClass]="{'c21-align-left' : g.align === 'left', 'c21-align-right' : g.align !== 'left'}"
|
|
6
6
|
[ngStyle]="{ 'background-color': g.baloonImage? null: g.themeColor, 'bottom': g.marginY+'px!important', 'left':(g.align==='left')?g.marginX+'px!important':'', 'right':(g.align==='right')?g.marginX+'px!important':'', 'width': g.launcherWidth, 'height': g.launcherHeight, 'border-radius': g.baloonShape}"
|
|
7
7
|
(click)="openCloseWidget()"
|
|
@@ -67,8 +67,9 @@ export class LauncherButtonComponent implements OnInit, AfterViewInit {
|
|
|
67
67
|
// this.g.isOpen = !this.g.isOpen;
|
|
68
68
|
// this.g.setIsOpen(!this.g.isOpen);
|
|
69
69
|
// this.appStorageService.setItem('isOpen', this.g.isOpen);
|
|
70
|
-
|
|
71
|
-
}
|
|
70
|
+
|
|
71
|
+
}
|
|
72
|
+
this.onButtonClicked.emit( this.g.isOpen );
|
|
72
73
|
}
|
|
73
74
|
|
|
74
75
|
}
|
|
@@ -302,6 +302,7 @@ export class TranslatorService {
|
|
|
302
302
|
'CLOSED',
|
|
303
303
|
'LABEL_PREVIEW',
|
|
304
304
|
'MAX_ATTACHMENT',
|
|
305
|
+
'MAX_ATTACHMENT_ERROR',
|
|
305
306
|
'EMOJI'
|
|
306
307
|
];
|
|
307
308
|
|
|
@@ -358,6 +359,7 @@ export class TranslatorService {
|
|
|
358
359
|
globals.LABEL_PREVIEW = res['LABEL_PREVIEW']
|
|
359
360
|
globals.LABEL_ERROR_FIELD_REQUIRED= res['LABEL_ERROR_FIELD_REQUIRED']
|
|
360
361
|
globals.MAX_ATTACHMENT = res['MAX_ATTACHMENT']
|
|
362
|
+
globals.MAX_ATTACHMENT_ERROR = res['MAX_ATTACHMENT_ERROR']
|
|
361
363
|
globals.EMOJI = res['EMOJI']
|
|
362
364
|
|
|
363
365
|
|
package/src/app/utils/globals.ts
CHANGED
|
@@ -247,7 +247,7 @@ export class Globals {
|
|
|
247
247
|
|
|
248
248
|
// ============ BEGIN: SET EXTERNAL PARAMETERS ==============//
|
|
249
249
|
this.baseLocation = 'https://widget.tiledesk.com/v2';
|
|
250
|
-
this.autoStart =
|
|
250
|
+
this.autoStart = false;
|
|
251
251
|
/** start Authentication and startUI */
|
|
252
252
|
this.startHidden = false;
|
|
253
253
|
/** show/hide all widget -> js call: showAllWidget */
|
package/src/assets/i18n/en.json
CHANGED
|
@@ -96,5 +96,6 @@
|
|
|
96
96
|
"EMOJI_NOT_ELLOWED":"Emoji not allowed",
|
|
97
97
|
"DOMAIN_NOT_ALLOWED":"URL contains a non-allowed domain",
|
|
98
98
|
"MAX_ATTACHMENT": "Max allowed size {{FILE_SIZE_LIMIT}}Mb",
|
|
99
|
+
"MAX_ATTACHMENT_ERROR": "The file exceeds the maximum allowed size",
|
|
99
100
|
"EMOJI": "Emoji"
|
|
100
101
|
}
|
package/src/assets/i18n/es.json
CHANGED
|
@@ -96,5 +96,6 @@
|
|
|
96
96
|
"EMOJI_NOT_ELLOWED":"Emoji no permitido",
|
|
97
97
|
"DOMAIN_NOT_ALLOWED":"La URL contiene un dominio no permitido",
|
|
98
98
|
"MAX_ATTACHMENT": "Tamaño máximo permitido {{FILE_SIZE_LIMIT}}Mb",
|
|
99
|
+
"MAX_ATTACHMENT_ERROR": "El archivo supera el tamaño máximo permitido",
|
|
99
100
|
"EMOJI": "Emoji"
|
|
100
101
|
}
|
package/src/assets/i18n/fr.json
CHANGED
|
@@ -96,5 +96,6 @@
|
|
|
96
96
|
"EMOJI_NOT_ELLOWED":"Emoji non autorisé",
|
|
97
97
|
"DOMAIN_NOT_ALLOWED":"L'URL contient un domaine non autorisé",
|
|
98
98
|
"MAX_ATTACHMENT": "Taille maximale autorisée {{FILE_SIZE_LIMIT}}Mo",
|
|
99
|
+
"MAX_ATTACHMENT_ERROR": "Le fichier dépasse la taille maximale autorisée",
|
|
99
100
|
"EMOJI": "Emoji"
|
|
100
101
|
}
|
package/src/assets/i18n/it.json
CHANGED
|
@@ -94,5 +94,6 @@
|
|
|
94
94
|
"EMOJI_NOT_ELLOWED":"Emoji non consentiti",
|
|
95
95
|
"DOMAIN_NOT_ALLOWED":"L'URL contiene un dominio non consentito",
|
|
96
96
|
"MAX_ATTACHMENT": "Dimensione massima consentita {{FILE_SIZE_LIMIT}}Mb",
|
|
97
|
+
"MAX_ATTACHMENT_ERROR": "Il file supera la dimensione massima consentita",
|
|
97
98
|
"EMOJI": "Emoji"
|
|
98
99
|
}
|
|
@@ -71,7 +71,7 @@ export class TiledeskRequestsService {
|
|
|
71
71
|
|
|
72
72
|
public getMyRequests(): Promise<{ requests: Array<any>}> {
|
|
73
73
|
this.tiledeskToken = this.appStorage.getItem('tiledeskToken')
|
|
74
|
-
const url = this.URL_TILEDESK_REQUEST + '
|
|
74
|
+
const url = this.URL_TILEDESK_REQUEST + 'me?preflight=true'
|
|
75
75
|
this.logger.log('[TILEDESK-SERVICE] - GET REQUEST url ', url);
|
|
76
76
|
const httpOptions = {
|
|
77
77
|
headers: new HttpHeaders({
|
|
@@ -773,6 +773,11 @@ export function isAllowedUrlInText(text: string, allowedUrls: string[]) {
|
|
|
773
773
|
return nonWhitelistedDomains.length === 0;
|
|
774
774
|
}
|
|
775
775
|
|
|
776
|
+
// function extractUrls(text: string): string[] {
|
|
777
|
+
// const urlRegex = /https?:\/\/[^\s]+/g;
|
|
778
|
+
// return text.match(urlRegex) || [];
|
|
779
|
+
// }
|
|
780
|
+
|
|
776
781
|
function extractUrls(text: string): string[] {
|
|
777
782
|
// Rileva URL con o senza protocollo (http/https)
|
|
778
783
|
const urlRegex = /\b((https?:\/\/)?(www\.)?[a-z0-9.-]+\.[a-z]{2,})(\/[^\s]*)?/gi;
|
|
@@ -787,5 +792,3 @@ function extractUrls(text: string): string[] {
|
|
|
787
792
|
}
|
|
788
793
|
|
|
789
794
|
|
|
790
|
-
|
|
791
|
-
|
package/src/iframe-style.css
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
bottom: 0px;
|
|
14
14
|
width: auto;
|
|
15
15
|
height: auto;
|
|
16
|
-
display:
|
|
16
|
+
display: block;
|
|
17
17
|
z-index: 3000000000; /*999999*/;
|
|
18
18
|
}
|
|
19
19
|
|
|
@@ -84,12 +84,12 @@
|
|
|
84
84
|
max-width: 1024px;
|
|
85
85
|
max-height: 100%;
|
|
86
86
|
|
|
87
|
-
transition:
|
|
87
|
+
/* transition:
|
|
88
88
|
width 300ms,
|
|
89
89
|
height 300ms,
|
|
90
90
|
max-height 300ms,
|
|
91
91
|
transform 300ms cubic-bezier(0, 1.2, 1, 1),
|
|
92
|
-
opacity 300ms ease-out;
|
|
92
|
+
opacity 300ms ease-out; */
|
|
93
93
|
/* per migliorare le prestazioni quando si usa transform */
|
|
94
94
|
will-change: transform, opacity, width, height;
|
|
95
95
|
}
|
|
@@ -175,14 +175,14 @@
|
|
|
175
175
|
}
|
|
176
176
|
|
|
177
177
|
#tiledesk-container.open #tiledeskdiv.min-size {
|
|
178
|
-
transition: width 200ms, height 200ms, max-height 200ms, transform 300ms cubic-bezier(0, 1.2, 1, 1), opacity 83ms ease-out;
|
|
178
|
+
/* transition: width 200ms, height 200ms, max-height 200ms, transform 300ms cubic-bezier(0, 1.2, 1, 1), opacity 83ms ease-out; */
|
|
179
179
|
width: var(--iframeMinWidth);
|
|
180
180
|
height: var(--iframeMinHeight);
|
|
181
181
|
}
|
|
182
182
|
|
|
183
183
|
#tiledesk-container.open #tiledeskdiv.max-size {
|
|
184
184
|
/* transition: width 1s, height 1s; */
|
|
185
|
-
transition: width 200ms, height 200ms, max-height 200ms, transform 300ms cubic-bezier(0, 1.2, 1, 1), opacity 83ms ease-out;
|
|
185
|
+
/* transition: width 200ms, height 200ms, max-height 200ms, transform 300ms cubic-bezier(0, 1.2, 1, 1), opacity 83ms ease-out; */
|
|
186
186
|
width: var(--iframeMaxWidth);
|
|
187
187
|
height: var(--iframeMaxHeight);
|
|
188
188
|
}
|
package/src/launch.js
CHANGED
|
@@ -217,68 +217,13 @@ function loadIframe(tiledeskScriptBaseLocation) {
|
|
|
217
217
|
|
|
218
218
|
iDiv.appendChild(ifrm);
|
|
219
219
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
// Metodo 1: Blob URL (più compatibile con CSP di Wix e altre piattaforme)
|
|
227
|
-
// Usa Blob URL come metodo principale perché è meno spesso bloccato da CSP rispetto a srcdoc
|
|
228
|
-
if (typeof Blob !== 'undefined' && typeof URL !== 'undefined' && URL.createObjectURL) {
|
|
229
|
-
try {
|
|
230
|
-
var blob = new Blob([htmlContent], { type: 'text/html;charset=utf-8' });
|
|
231
|
-
blobUrl = URL.createObjectURL(blob);
|
|
232
|
-
iframe.src = blobUrl;
|
|
233
|
-
|
|
234
|
-
// Cleanup del blob URL dopo il caricamento per liberare memoria
|
|
235
|
-
var originalOnload = iframe.onload;
|
|
236
|
-
iframe.onload = function() {
|
|
237
|
-
// Revoca il blob URL dopo un delay per assicurarsi che tutto sia caricato
|
|
238
|
-
setTimeout(function() {
|
|
239
|
-
if (blobUrl) {
|
|
240
|
-
try {
|
|
241
|
-
URL.revokeObjectURL(blobUrl);
|
|
242
|
-
blobUrl = null;
|
|
243
|
-
} catch(e) {
|
|
244
|
-
console.warn('Error revoking blob URL:', e);
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
}, 1000);
|
|
248
|
-
if (originalOnload) originalOnload.call(this);
|
|
249
|
-
};
|
|
250
|
-
return; // Blob URL impostato con successo
|
|
251
|
-
} catch(e) {
|
|
252
|
-
console.warn('Blob URL not available, trying srcdoc:', e);
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
// Metodo 2: srcdoc (fallback se Blob URL non disponibile)
|
|
257
|
-
// Skip per localhost (usa document.write per compatibilità sviluppo)
|
|
258
|
-
if (!isLocalhost && 'srcdoc' in iframe) {
|
|
259
|
-
try {
|
|
260
|
-
iframe.srcdoc = htmlContent;
|
|
261
|
-
return; // srcdoc impostato
|
|
262
|
-
} catch(e) {
|
|
263
|
-
console.warn('srcdoc not allowed, trying document.write:', e);
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
// Metodo 3: document.write (fallback finale, funziona su localhost e browser vecchi)
|
|
268
|
-
if (isLocalhost || (iframe.contentWindow && iframe.contentWindow.document)) {
|
|
269
|
-
try {
|
|
270
|
-
iframe.contentWindow.document.open();
|
|
271
|
-
iframe.contentWindow.document.write(htmlContent);
|
|
272
|
-
iframe.contentWindow.document.close();
|
|
273
|
-
return; // document.write completato
|
|
274
|
-
} catch(e) {
|
|
275
|
-
console.error('All iframe loading methods failed:', e);
|
|
276
|
-
}
|
|
277
|
-
}
|
|
220
|
+
if(tiledeskScriptBaseLocation.includes('localhost')){
|
|
221
|
+
ifrm.contentWindow.document.open();
|
|
222
|
+
ifrm.contentWindow.document.write(srcTileDesk);
|
|
223
|
+
ifrm.contentWindow.document.close();
|
|
224
|
+
}else {
|
|
225
|
+
ifrm.srcdoc = srcTileDesk
|
|
278
226
|
}
|
|
279
|
-
|
|
280
|
-
// Carica il contenuto dell'iframe con fallback automatico
|
|
281
|
-
loadIframeContent(ifrm, srcTileDesk, tiledeskScriptBaseLocation);
|
|
282
227
|
|
|
283
228
|
|
|
284
229
|
}
|
package/src/launch_template.js
CHANGED
|
@@ -218,68 +218,13 @@ function loadIframe(tiledeskScriptBaseLocation) {
|
|
|
218
218
|
|
|
219
219
|
iDiv.appendChild(ifrm);
|
|
220
220
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
// Metodo 1: Blob URL (più compatibile con CSP di Wix e altre piattaforme)
|
|
228
|
-
// Usa Blob URL come metodo principale perché è meno spesso bloccato da CSP rispetto a srcdoc
|
|
229
|
-
if (typeof Blob !== 'undefined' && typeof URL !== 'undefined' && URL.createObjectURL) {
|
|
230
|
-
try {
|
|
231
|
-
var blob = new Blob([htmlContent], { type: 'text/html;charset=utf-8' });
|
|
232
|
-
blobUrl = URL.createObjectURL(blob);
|
|
233
|
-
iframe.src = blobUrl;
|
|
234
|
-
|
|
235
|
-
// Cleanup del blob URL dopo il caricamento per liberare memoria
|
|
236
|
-
var originalOnload = iframe.onload;
|
|
237
|
-
iframe.onload = function() {
|
|
238
|
-
// Revoca il blob URL dopo un delay per assicurarsi che tutto sia caricato
|
|
239
|
-
setTimeout(function() {
|
|
240
|
-
if (blobUrl) {
|
|
241
|
-
try {
|
|
242
|
-
URL.revokeObjectURL(blobUrl);
|
|
243
|
-
blobUrl = null;
|
|
244
|
-
} catch(e) {
|
|
245
|
-
console.warn('Error revoking blob URL:', e);
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
}, 1000);
|
|
249
|
-
if (originalOnload) originalOnload.call(this);
|
|
250
|
-
};
|
|
251
|
-
return; // Blob URL impostato con successo
|
|
252
|
-
} catch(e) {
|
|
253
|
-
console.warn('Blob URL not available, trying srcdoc:', e);
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
// Metodo 2: srcdoc (fallback se Blob URL non disponibile)
|
|
258
|
-
// Skip per localhost (usa document.write per compatibilità sviluppo)
|
|
259
|
-
if (!isLocalhost && 'srcdoc' in iframe) {
|
|
260
|
-
try {
|
|
261
|
-
iframe.srcdoc = htmlContent;
|
|
262
|
-
return; // srcdoc impostato
|
|
263
|
-
} catch(e) {
|
|
264
|
-
console.warn('srcdoc not allowed, trying document.write:', e);
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
// Metodo 3: document.write (fallback finale, funziona su localhost e browser vecchi)
|
|
269
|
-
if (isLocalhost || (iframe.contentWindow && iframe.contentWindow.document)) {
|
|
270
|
-
try {
|
|
271
|
-
iframe.contentWindow.document.open();
|
|
272
|
-
iframe.contentWindow.document.write(htmlContent);
|
|
273
|
-
iframe.contentWindow.document.close();
|
|
274
|
-
return; // document.write completato
|
|
275
|
-
} catch(e) {
|
|
276
|
-
console.error('All iframe loading methods failed:', e);
|
|
277
|
-
}
|
|
278
|
-
}
|
|
221
|
+
if(tiledeskScriptBaseLocation.includes('localhost')){
|
|
222
|
+
ifrm.contentWindow.document.open();
|
|
223
|
+
ifrm.contentWindow.document.write(srcTileDesk);
|
|
224
|
+
ifrm.contentWindow.document.close();
|
|
225
|
+
}else {
|
|
226
|
+
ifrm.srcdoc = srcTileDesk
|
|
279
227
|
}
|
|
280
|
-
|
|
281
|
-
// Carica il contenuto dell'iframe con fallback automatico
|
|
282
|
-
loadIframeContent(ifrm, srcTileDesk, tiledeskScriptBaseLocation);
|
|
283
228
|
|
|
284
229
|
|
|
285
230
|
}
|
package/deploy_amazon_prod.sh
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
# npm version patch
|
|
2
|
-
version=`node -e 'console.log(require("./package.json").version)'`
|
|
3
|
-
echo "version $version"
|
|
4
|
-
|
|
5
|
-
npm i
|
|
6
|
-
|
|
7
|
-
cp src/environments/real_data/environment.prod.ts src/environments/environment.prod.ts
|
|
8
|
-
|
|
9
|
-
# --build-optimizer=false if localstorage is disabled (webview) appears https://github.com/firebase/angularfire/issues/970
|
|
10
|
-
ng build --configuration="prod" --aot=true
|
|
11
|
-
##--base-href='./v5/' --output-hashing none
|
|
12
|
-
|
|
13
|
-
### SET HASHING : START ###
|
|
14
|
-
cp ./src/launch_template.js ./dist/browser/launch.js
|
|
15
|
-
node ./src/build_launch.js
|
|
16
|
-
### SET HASHING : END ###
|
|
17
|
-
|
|
18
|
-
#### FIREBASE #####
|
|
19
|
-
# cd dist
|
|
20
|
-
# # aws s3 sync . s3://tiledesk-widget/v5/latest/
|
|
21
|
-
# aws s3 sync . s3://tiledesk-widget/v5/$version/ --cache-control max-age=300
|
|
22
|
-
# aws s3 sync . s3://tiledesk-widget/v5/ --cache-control max-age=300
|
|
23
|
-
# cd ..
|
|
24
|
-
|
|
25
|
-
# #### MQTT #####
|
|
26
|
-
cd dist/browser
|
|
27
|
-
# aws s3 sync . s3://tiledesk-widget/v5/latest/
|
|
28
|
-
aws s3 sync . s3://tiledesk-widget/v6/$version/ --cache-control max-age=86400 --exclude='launch.js' #8days
|
|
29
|
-
aws s3 sync . s3://tiledesk-widget/v6/$version/ --cache-control "no-store,no-cache,private" --exclude='*' --include='launch.js'
|
|
30
|
-
aws s3 sync . s3://tiledesk-widget/v6/ --cache-control max-age=86400 --exclude='launch.js' #8days
|
|
31
|
-
aws s3 sync . s3://tiledesk-widget/v6/ --cache-control "no-store,no-cache,private" --exclude='*' --include='launch.js'
|
|
32
|
-
cd ../..
|
|
33
|
-
|
|
34
|
-
aws cloudfront create-invalidation --distribution-id E3EJDWEHY08CZZ --paths "/*"
|
|
35
|
-
|
|
36
|
-
git restore src/environments/environment.prod.ts
|
|
37
|
-
|
|
38
|
-
echo new version deployed $version on s3://tiledesk-widget/v6
|
|
39
|
-
echo available on https://s3.eu-west-1.amazonaws.com/tiledesk-widget/v6/index.html
|
|
40
|
-
echo https://widget.tiledesk.com/v6/index.html
|
|
41
|
-
echo https://widget.tiledesk.com/v6/$version/index.html
|