Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions src/lib/scss/custom/pages/_chat.scss
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,40 @@
min-width: 50px;
}
}

.card-group-container {
display: flex;
flex-wrap: wrap;
gap: 5px;
margin-top: 10px;

.card-element {
flex: 1 1 fit-content;
border-radius: 10px;
border-width: 2px;
max-width: 100%;
margin-bottom: 0px;

.card-element-title {
font-size: 1.1rem;
font-weight: 700;
}

.card-element-subtitle {
font-size: 0.8rem;
font-weight: 500;
}

.card-option-group {
margin-top: 5px;

.btn {
display: block;
margin-left: 0px !important;
}
}
}
}
}

.ctext-wrap {
Expand Down
6 changes: 3 additions & 3 deletions src/routes/chat/[agentId]/[conversationId]/chat-box.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -362,11 +362,11 @@
await sentTextMessage();
}

/** @param {string} payload */
async function confirmSelectedOption(payload) {
/** @param {string} answer */
async function confirmSelectedOption(answer) {
if (isSendingMsg || isThinking) return;

await sendChatMessage(payload);
await sendChatMessage(answer);
}

async function sentTextMessage() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
<script>
import { Card, CardBody } from "@sveltestrap/sveltestrap";
import { onMount } from "svelte";


/** @type {boolean} */
export let disableOption = false;

/** @type {boolean} */
export let fillPostback = false;

/** @type {any[]} */
export let options = [];

/** @type {(args0: string) => any} */
export let onConfirm;

/** @type {any[]} */
let cards = [];

onMount(() => {
cards = collectOptions(options);
});

/** @param {any[]} options */
function collectOptions(options) {
const res = options?.map(op => {
// @ts-ignore
const options = op.buttons?.map(x => {
return {
title: x.title,
payload: x.payload
};
}) || [];

return {
title: op.title,
subtitle: op.subtitle,
options: options
};
}) || [];

return res;
}

/**
* @param {any} e
* @param {any} option
*/
function handleClickOption(e, option) {
e.preventDefault();
innerConfirm(fillPostback ? option?.payload : option?.title);
}

/**
* @param {string} answer
*/
function innerConfirm(answer) {
onConfirm && onConfirm(answer);
reset();
}

function reset() {
cards = [];
}
</script>

{#if cards.length > 0}
<div class="card-group-container">
{#each cards as card, idx (idx)}
<Card class="card-element">
<CardBody>
{#if !!card.title}
<div class="card-element-title">{card.title}</div>
{/if}
{#if !!card.subtitle}
<div class="card-element-subtitle">{card.subtitle}</div>
{/if}
{#if card.options?.length > 0}
<div class="card-option-group">
{#each card.options as option, i (i)}
<button
class="btn btn-outline-primary btn-rounded btn-sm m-1"
disabled={disableOption}
on:click={(e) => handleClickOption(e, option)}
>
{option.title}
</button>
{/each}
</div>
{/if}
</CardBody>
</Card>
{/each}
</div>
{/if}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
/** @type {boolean} */
export let disableOption = false;

/** @type {boolean} */
export let fillPostback = false;

/** @type {any[]} */
export let options = [];

Expand All @@ -30,54 +33,43 @@

/** @param {any[]} options */
function collectOptions(options) {
/** @type {any[]} */
let res = [];
options?.map(op => {
if (!!!op.title || !!!op.payload) {
return;
}

if (op.buttons?.length > 0) {
// @ts-ignore
op.buttons?.map(x => {
if (!!x.title && !!x.payload) {
res.push({
title: x.title,
payload: x.payload,
isClicked: false
});
}
});
} else {
res.push({
title: op.title,
payload: op.payload,
isClicked: false
});
}
});
const res = options?.map(op => {
return {
title: op.title,
payload: op.payload,
isClicked: false
};
}) || [];

return res;
}

/**
* @param {any} e
* @param {string} payload
* @param {any} option
* @param {number} index
*/
function handleClickOption(e, payload, index) {
function handleClickOption(e, option, index) {
e.preventDefault();

if (!isMultiSelect) {
innerConfirm(payload);
innerConfirm(fillPostback ? option?.payload : option?.title);
} else {
localOptions = localOptions.map((op, idx) => {
if (idx === index) {
op.isClicked = !op.isClicked;
if (op.isClicked) {
answers = [...answers, op.payload];
if (fillPostback) {
answers = [...answers, op.payload];
} else {
answers = [...answers, op.title];
}
} else {
answers = answers.filter(a => a != op.payload);
if (fillPostback) {
answers = answers.filter(a => a != op.payload);
} else {
answers = answers.filter(a => a != op.title);
}
}
}
return op;
Expand All @@ -90,15 +82,15 @@
*/
function handleConfirm(e) {
e.preventDefault();
const payload = answers.join(separator);
innerConfirm(payload);
const answer = answers.join(separator);
innerConfirm(answer);
}

/**
* @param {string} payload
* @param {string} answer
*/
function innerConfirm(payload) {
onConfirm && onConfirm(payload);
function innerConfirm(answer) {
onConfirm && onConfirm(answer);
reset();
}

Expand All @@ -112,10 +104,24 @@
{#if localOptions.length > 0}
<div class="button-group">
{#each localOptions as option, index}
<button class="btn btn-outline-primary btn-rounded btn-sm m-1" class:active={!!option.isClicked} disabled={disableOption} on:click={(e) => handleClickOption(e, option.payload, index)}>{option.title}</button>
<button
class="btn btn-outline-primary btn-rounded btn-sm m-1"
class:active={!!option.isClicked}
disabled={disableOption}
on:click={(e) => handleClickOption(e, option, index)}
>
{option.title}
</button>
{/each}
{#if isMultiSelect}
<button class="btn btn-outline-success btn-rounded btn-sm m-1" name="confirm" disabled={disableOption || localOptions.every(x => !!!x.isClicked)} on:click={(e) => handleConfirm(e)}>{confirmBtnText}</button>
<button
class="btn btn-outline-success btn-rounded btn-sm m-1"
name="confirm"
disabled={disableOption || localOptions.every(x => !!!x.isClicked)}
on:click={(e) => handleConfirm(e)}
>
{confirmBtnText || 'Continue'}
</button>
{/if}
</div>
{/if}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import { RichType } from "$lib/helpers/enums";
import Markdown from "$lib/common/Markdown.svelte";
import RcOptions from "./rc-options.svelte";
import RcGenericOptions from "./rc-generic-options.svelte";

/** @type {any} */
export let message;
Expand All @@ -16,10 +17,10 @@
export let onConfirm = () => {};

/**
* @param {string} payload
* @param {string} answer
*/
function handleConfirm(payload) {
onConfirm && onConfirm(payload);
function handleConfirm(answer) {
onConfirm && onConfirm(answer);
}
</script>

Expand All @@ -31,12 +32,12 @@

{#if displayExtraElements}
{#if message?.rich_content?.message?.rich_type === RichType.QuickReply}
<RcOptions options={message?.rich_content?.message?.quick_replies} disableOption={disableOption} onConfirm={handleConfirm} />
<RcOptions options={message?.rich_content?.message?.quick_replies} fillPostback={message?.rich_content?.fill_postback} disableOption={disableOption} onConfirm={handleConfirm} />
{:else if message?.rich_content?.message?.rich_type === RichType.Button}
<RcOptions options={message?.rich_content?.message?.buttons} disableOption={disableOption} onConfirm={handleConfirm} />
<RcOptions options={message?.rich_content?.message?.buttons} fillPostback={message?.rich_content?.fill_postback} disableOption={disableOption} onConfirm={handleConfirm} />
{:else if message?.rich_content?.message?.rich_type === RichType.MultiSelect}
<RcOptions options={message?.rich_content?.message?.options} isMultiSelect disableOption={disableOption} onConfirm={handleConfirm} />
<RcOptions options={message?.rich_content?.message?.options} isMultiSelect fillPostback={message?.rich_content?.fill_postback} disableOption={disableOption} onConfirm={handleConfirm} />
{:else if message?.rich_content?.message?.rich_type === RichType.Generic}
<RcOptions options={message?.rich_content?.message?.elements} disableOption={disableOption} onConfirm={handleConfirm} />
<RcGenericOptions options={message?.rich_content?.message?.elements} disableOption={disableOption} onConfirm={handleConfirm} />
{/if}
{/if}