Skip to content

Commit 2541311

Browse files
authored
Merge pull request #220 from iceljc/features/refine-chat-window
add logout event
2 parents a8a6437 + e524d47 commit 2541311

File tree

10 files changed

+149
-100
lines changed

10 files changed

+149
-100
lines changed
Lines changed: 68 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,85 +1,86 @@
11
<script>
2-
import { fade } from 'svelte/transition';
3-
import { onMount } from 'svelte';
4-
import { PUBLIC_LIVECHAT_HOST, PUBLIC_LIVECHAT_ENTRY_ICON } from '$env/static/public';
5-
import { getSettingDetail } from '$lib/services/setting-service';
2+
import { fade } from 'svelte/transition';
3+
import { onMount } from 'svelte';
4+
import { PUBLIC_LIVECHAT_HOST, PUBLIC_LIVECHAT_ENTRY_ICON } from '$env/static/public';
5+
import { getSettingDetail } from '$lib/services/setting-service';
66
7-
let showChatIcon = false;
8-
let showChatBox = false;
9-
let chatUrl = PUBLIC_LIVECHAT_HOST;
7+
let showChatIcon = false;
8+
let showChatBox = false;
9+
let chatUrl = PUBLIC_LIVECHAT_HOST;
1010
11-
onMount(async () => {
12-
const agentSettings = await getSettingDetail("Agent");
13-
chatUrl = `${PUBLIC_LIVECHAT_HOST}chat/${agentSettings.hostAgentId}?isFrame=true`;
14-
showChatIcon = true;
15-
});
11+
onMount(async () => {
12+
const agentSettings = await getSettingDetail("Agent");
13+
chatUrl = `${PUBLIC_LIVECHAT_HOST}chat/${agentSettings.hostAgentId}?isFrame=true`;
14+
showChatIcon = true;
15+
});
1616
17-
// Handle event from iframe
18-
window.onmessage = async function(e) {
19-
if (e.data.action == 'close') {
20-
showChatIcon = true;
21-
showChatBox = false;
22-
}
23-
};
17+
// Handle event from iframe
18+
window.onmessage = async function(e) {
19+
if (e.data.action == 'close') {
20+
showChatIcon = true;
21+
showChatBox = false;
22+
}
23+
};
2424
25-
function handleChatBox() {
26-
showChatIcon = false;
27-
showChatBox = true;
28-
}
25+
function handleChatBox() {
26+
showChatIcon = false;
27+
showChatBox = true;
28+
}
2929
</script>
3030

3131
<div class="fixed-bottom float-bottom-right">
32-
{#if showChatBox}
33-
<div transition:fade={{ delay: 250, duration: 300 }}>
34-
<iframe
35-
src={chatUrl}
36-
width="380px"
37-
height="650px"
38-
class="border border-2 rounded-3 m-3 float-end chat-iframe"
39-
title="live chat"
40-
>
41-
</iframe>
42-
</div>
43-
{/if}
32+
{#if showChatBox}
33+
<div transition:fade={{ delay: 250, duration: 300 }}>
34+
<iframe
35+
src={chatUrl}
36+
width="380px"
37+
height="650px"
38+
class="border border-2 rounded-3 m-3 float-end chat-iframe"
39+
title="live chat"
40+
id="chat-frame"
41+
>
42+
</iframe>
43+
</div>
44+
{/if}
4445

45-
{#if showChatIcon}
46-
<div class="mb-3 float-end wave-effect" transition:fade={{ delay: 100, duration: 500 }}>
47-
<button class="btn btn-transparent" on:click={handleChatBox}>
48-
<img alt="live chat" class="avatar-md rounded-circle" src={PUBLIC_LIVECHAT_ENTRY_ICON} />
49-
</button>
50-
</div>
51-
{/if}
46+
{#if showChatIcon}
47+
<div class="mb-3 float-end wave-effect" transition:fade={{ delay: 100, duration: 500 }}>
48+
<button class="btn btn-transparent" on:click={() => handleChatBox()}>
49+
<img alt="live chat" class="avatar-md rounded-circle" src={PUBLIC_LIVECHAT_ENTRY_ICON} />
50+
</button>
51+
</div>
52+
{/if}
5253
</div>
5354

5455
<style>
55-
.wave-effect:hover {
56-
animation: wave 0.82s cubic-bezier(.36,.07,.19,.97) both;
57-
transform: translate3d(0, 0, 0);
58-
backface-visibility: hidden;
59-
perspective: 1000px;
60-
}
61-
62-
@keyframes wave {
63-
10%, 90% {
64-
transform: translate3d(-1px, 0, 0);
65-
}
66-
67-
20%, 80% {
68-
transform: translate3d(2px, 0, 0);
56+
.wave-effect:hover {
57+
animation: wave 0.82s cubic-bezier(.36,.07,.19,.97) both;
58+
transform: translate3d(0, 0, 0);
59+
backface-visibility: hidden;
60+
perspective: 1000px;
6961
}
7062
71-
30%, 50%, 70% {
72-
transform: translate3d(-4px, 0, 0);
73-
}
63+
@keyframes wave {
64+
10%, 90% {
65+
transform: translate3d(-1px, 0, 0);
66+
}
67+
68+
20%, 80% {
69+
transform: translate3d(2px, 0, 0);
70+
}
7471
75-
40%, 60% {
76-
transform: translate3d(4px, 0, 0);
72+
30%, 50%, 70% {
73+
transform: translate3d(-4px, 0, 0);
74+
}
75+
76+
40%, 60% {
77+
transform: translate3d(4px, 0, 0);
78+
}
7779
}
78-
}
7980
80-
.float-bottom-right {
81-
width: fit-content;
82-
margin-right: 0px;
83-
margin-left: auto;
84-
}
81+
.float-bottom-right {
82+
width: fit-content;
83+
margin-right: 0px;
84+
margin-left: auto;
85+
}
8586
</style>

src/lib/common/ProfileDropdown.svelte

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,13 @@
1515
if (browser){
1616
resetLocalStorage(true);
1717
}
18+
19+
const chatFrame = document.getElementById('chat-frame');
20+
if (chatFrame) {
21+
// @ts-ignore
22+
chatFrame.contentWindow.postMessage({ action: "logout" }, "*");
23+
}
24+
1825
goto('login');
1926
};
2027
@@ -57,7 +64,7 @@
5764
role="button"
5865
tabindex="0"
5966
on:keydown={() => {}}
60-
on:click={logout}
67+
on:click={() => logout()}
6168
>
6269
<i class="bx bx-power-off font-size-16 align-middle me-1 text-danger" /> <span>{$_('Logout')}</span>
6370
</div>

src/lib/helpers/enums.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ export const RichType = Object.freeze(richType);
2828
const elementType = {
2929
Text: "text",
3030
Video: "video",
31-
File: "file"
31+
File: "file",
32+
Web: "web_url"
3233
};
3334
export const ElementType = Object.freeze(elementType);
3435

src/lib/helpers/store.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import { writable } from 'svelte/store';
33
import { browser } from '$app/environment';
44

5+
const userKey = "user";
56
const conversationKey = "conversation";
67
const conversationUserStatesKey = "conversation_user_states";
78
const conversationSearchOptionKey = "conversation_search_option";
@@ -16,7 +17,7 @@ export const userStore = writable({ id: "", full_name: "", expires: 0, token: nu
1617
export function getUserStore() {
1718
if (browser) {
1819
// Access localStorage only if in the browser context
19-
let json = localStorage.getItem('user');
20+
let json = localStorage.getItem(userKey);
2021
if (json)
2122
return JSON.parse(json);
2223
else
@@ -29,7 +30,7 @@ export function getUserStore() {
2930

3031
userStore.subscribe(value => {
3132
if (browser && value.token) {
32-
localStorage.setItem('user', JSON.stringify(value));
33+
localStorage.setItem(userKey, JSON.stringify(value));
3334
}
3435
});
3536

src/lib/scss/custom/pages/_chat.scss

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -749,6 +749,10 @@
749749
margin-left: 0px !important;
750750
border-radius: 10px;
751751
}
752+
753+
.btn-link {
754+
background-color: unset !important;
755+
}
752756
}
753757
}
754758
}

src/routes/(home)/+page.svelte

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -41,17 +41,17 @@
4141
<Row class="justify-content-center mt-5">
4242
<Col sm="8">
4343
{#if showHomeImage}
44-
<div class="maintenance-img" transition:fade={{ delay: 300, duration: 500 }}>
45-
<img src={PUBLIC_HOME_IMAGE} alt="" style="max-width: 25vw;" />
46-
</div>
44+
<div class="maintenance-img" transition:fade={{ delay: 300, duration: 500 }}>
45+
<img src={PUBLIC_HOME_IMAGE} alt="" style="max-width: 25vw;" />
46+
</div>
4747
{/if}
4848
</Col>
4949
</Row>
5050
{#if showHomeSlogan}
51-
<h4 class="mt-5" transition:fade={{ delay: 500, duration: 500 }}>Let&#39;s <a href="login" class="btn btn-primary">get started</a> with {PUBLIC_BRAND_NAME}</h4>
52-
<p class="text-muted" transition:fade={{ delay: 800, duration: 500 }}>
53-
{PUBLIC_HOME_SLOGAN}
54-
</p>
51+
<h4 class="mt-5" transition:fade={{ delay: 500, duration: 500 }}>Let&#39;s <a href="login" class="btn btn-primary">get started</a> with {PUBLIC_BRAND_NAME}</h4>
52+
<p class="text-muted" transition:fade={{ delay: 800, duration: 500 }}>
53+
{PUBLIC_HOME_SLOGAN}
54+
</p>
5555
{/if}
5656
</div>
5757
</Col>

src/routes/chat/[agentId]/[conversationId]/chat-box.svelte

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@
1818
conversationStore,
1919
conversationUserStateStore,
2020
conversationUserMessageStore,
21-
conversationUserAttachmentStore
21+
conversationUserAttachmentStore,
22+
resetLocalStorage
2223
} from '$lib/helpers/store.js';
2324
import {
2425
sendMessageToHub,
@@ -166,6 +167,12 @@
166167
});
167168
168169
onMount(async () => {
170+
window.addEventListener('message', e => {
171+
if (e.data.action === 'logout') {
172+
resetLocalStorage(true);
173+
}
174+
});
175+
169176
autoScrollLog = true;
170177
dialogs = await GetDialogs(params.conversationId);
171178
conversationUser = await getConversationUser(params.conversationId);

src/routes/chat/[agentId]/[conversationId]/rich-content/rc-complex-options.svelte

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import { getContext, onMount } from "svelte";
33
import { fade } from 'svelte/transition';
44
import { Card, CardBody } from "@sveltestrap/sveltestrap";
5+
import { ElementType } from "$lib/helpers/enums";
56
67
/** @type {boolean} */
78
export let disabled = false;
@@ -35,6 +36,8 @@
3536
return {
3637
title: x.title,
3738
payload: x.payload,
39+
type: x.type,
40+
url: x.url,
3841
is_primary: x.is_primary,
3942
is_secondary: x.is_secondary,
4043
};
@@ -54,6 +57,8 @@
5457
return {
5558
title: x.title,
5659
payload: x.payload,
60+
type: x.type,
61+
url: x.url,
5762
is_primary: x.is_primary,
5863
is_secondary: x.is_secondary,
5964
};
@@ -75,7 +80,7 @@
7580
* @param {string} payload
7681
*/
7782
function innerConfirm(title, payload) {
78-
onConfirm && onConfirm(title, payload);
83+
onConfirm?.(title, payload);
7984
reset();
8085
}
8186
@@ -106,13 +111,23 @@
106111
{#if card.options?.length > 0}
107112
<div class="card-option-group">
108113
{#each card.options as option, i (i)}
109-
<button
110-
class={`btn btn-sm m-1 ${option.is_secondary ? 'btn-outline-secondary': 'btn-outline-primary'}`}
111-
disabled={disabled}
112-
on:click={(e) => handleClickOption(e, option)}
113-
>
114-
{option.title}
115-
</button>
114+
{#if option.type === ElementType.Web && option.url}
115+
<button
116+
class={`btn btn-sm btn-link m-1 ${option.is_secondary ? 'btn-outline-secondary': 'btn-outline-primary'}`}
117+
disabled={disabled}
118+
on:click={() => window.open(option.url)}
119+
>
120+
{option.title}
121+
</button>
122+
{:else}
123+
<button
124+
class={`btn btn-sm m-1 ${option.is_secondary ? 'btn-outline-secondary': 'btn-outline-primary'}`}
125+
disabled={disabled}
126+
on:click={(e) => handleClickOption(e, option)}
127+
>
128+
{option.title}
129+
</button>
130+
{/if}
116131
{/each}
117132
</div>
118133
{/if}

src/routes/chat/[agentId]/[conversationId]/rich-content/rc-plain-options.svelte

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@
5757
return {
5858
title: op.title,
5959
payload: op.payload,
60+
type: op.type,
61+
url: op.url,
6062
is_primary: op.is_primary,
6163
is_secondary: op.is_secondary,
6264
isClicked: false
@@ -144,15 +146,26 @@
144146
{#if plainOptions || fileOption}
145147
<div class="plain-option-container center-option">
146148
{#each plainOptions as option, index}
147-
<button
148-
class={`btn btn-sm m-1 ${option.is_secondary ? 'btn-outline-secondary': 'btn-outline-primary'}`}
149-
class:active={!!option.isClicked}
150-
disabled={disabled}
151-
in:fade={{ duration: duration }}
152-
on:click={(e) => handleClickOption(e, option, index)}
153-
>
154-
{option.title}
155-
</button>
149+
{#if option.type === ElementType.Web && option.url}
150+
<button
151+
class={`btn btn-sm btn-link m-1 ${option.is_secondary ? 'btn-outline-secondary': 'btn-outline-primary'}`}
152+
disabled={disabled}
153+
in:fade={{ duration: duration }}
154+
on:click={() => window.open(option.url)}
155+
>
156+
{option.title}
157+
</button>
158+
{:else}
159+
<button
160+
class={`btn btn-sm m-1 ${option.is_secondary ? 'btn-outline-secondary': 'btn-outline-primary'}`}
161+
class:active={!!option.isClicked}
162+
disabled={disabled}
163+
in:fade={{ duration: duration }}
164+
on:click={(e) => handleClickOption(e, option, index)}
165+
>
166+
{option.title}
167+
</button>
168+
{/if}
156169
{/each}
157170
{#if plainOptions && isMultiSelect}
158171
<button

0 commit comments

Comments
 (0)