diff --git a/api/src/chat/dto/context-var.dto.ts b/api/src/chat/dto/context-var.dto.ts index 3819f5c2..7bed0ac3 100644 --- a/api/src/chat/dto/context-var.dto.ts +++ b/api/src/chat/dto/context-var.dto.ts @@ -8,7 +8,7 @@ */ import { ApiProperty, PartialType } from '@nestjs/swagger'; -import { IsNotEmpty, IsString } from 'class-validator'; +import { IsBoolean, IsNotEmpty, IsOptional, IsString } from 'class-validator'; export class ContextVarCreateDto { @ApiProperty({ description: 'Context var label', type: String }) @@ -22,6 +22,8 @@ export class ContextVarCreateDto { name: string; @ApiProperty({ description: 'Is context var permanent', type: Boolean }) + @IsOptional() + @IsBoolean() permanent?: boolean; } diff --git a/api/src/chat/services/bot.service.ts b/api/src/chat/services/bot.service.ts index 9a8ca91b..01c4b635 100644 --- a/api/src/chat/services/bot.service.ts +++ b/api/src/chat/services/bot.service.ts @@ -70,11 +70,12 @@ export class BotService { event.getSenderForeignId(), ); // Process message : Replace tokens with context data and then send the message + const recipient = event.getSender(); const envelope: StdOutgoingEnvelope = await this.blockService.processMessage( block, context, - event.getSender().context, + recipient.context, fallback, conservationId, ); @@ -88,7 +89,6 @@ export class BotService { this.eventEmitter.emit('hook:stats:entry', 'all_messages', 'All Messages'); // Trigger sent message event - const recipient = event.getSender(); const sentMessage: MessageCreateDto = { mid: response && 'mid' in response ? response.mid : '', message: envelope.message, diff --git a/api/src/chat/services/context-var.service.ts b/api/src/chat/services/context-var.service.ts index 00578aff..99356b2e 100644 --- a/api/src/chat/services/context-var.service.ts +++ b/api/src/chat/services/context-var.service.ts @@ -21,14 +21,19 @@ export class ContextVarService extends BaseService { super(repository); } + /** + * Retrieves a mapping of context variable names to their corresponding `ContextVar` objects for a given block. + * + * @param {Block | BlockFull} block - The block containing the capture variables to retrieve context variables for. + * @returns {Promise>} A promise that resolves to a record mapping context variable names to `ContextVar` objects. + */ async getContextVarsByBlock( block: Block | BlockFull, ): Promise> { - return ( - await this.find({ - name: { $in: block.capture_vars.map((cv) => cv.context_var) }, - }) - ).reduce((acc, cv) => { + const vars = await this.find({ + name: { $in: block.capture_vars.map(({ context_var }) => context_var) }, + }); + return vars.reduce((acc, cv) => { acc[cv.name] = cv; return acc; }, {}); diff --git a/frontend/src/components/context-vars/ContextVarDialog.tsx b/frontend/src/components/context-vars/ContextVarDialog.tsx index 5a396187..3b973684 100644 --- a/frontend/src/components/context-vars/ContextVarDialog.tsx +++ b/frontend/src/components/context-vars/ContextVarDialog.tsx @@ -7,9 +7,16 @@ * 3. SaaS Restriction: This software, or any derivative of it, may not be used to offer a competing product or service (SaaS) without prior written consent from Hexastack. Offering the software as a service or using it in a commercial cloud environment without express permission is strictly prohibited. */ -import { Dialog, DialogActions, DialogContent } from "@mui/material"; +import { + Dialog, + DialogActions, + DialogContent, + FormControlLabel, + FormHelperText, + Switch, +} from "@mui/material"; import { FC, useEffect } from "react"; -import { useForm } from "react-hook-form"; +import { Controller, useForm } from "react-hook-form"; import { useTranslation } from "react-i18next"; import DialogButtons from "@/app-components/buttons/DialogButtons"; @@ -58,6 +65,7 @@ export const ContextVarDialog: FC = ({ setValue, handleSubmit, formState: { errors }, + control, } = useForm({ defaultValues: { name: data?.name || "", label: data?.label || "" }, }); @@ -129,6 +137,19 @@ export const ContextVarDialog: FC = ({ InputLabelProps={{ shrink: true }} /> + + ( + } + label={t("label.permanent")} + /> + )} + /> + {t("help.permanent")} + diff --git a/frontend/src/i18n/en/translation.json b/frontend/src/i18n/en/translation.json index a3b4a5ca..69fc736f 100644 --- a/frontend/src/i18n/en/translation.json +++ b/frontend/src/i18n/en/translation.json @@ -699,7 +699,8 @@ "supported_message_type_others": "Only generic template messages are supported.", "notification_type_regular": "Sound/Vibration", "notification_type_silent_push": "On-screen notification only", - "notification_type_no_push": "No notification" + "notification_type_no_push": "No notification", + "permanent": "When enabled, the variable value will be stored in the subscriber's profile and retained for future conversations." }, "charts": { "messages": "Messages", diff --git a/frontend/src/i18n/fr/translation.json b/frontend/src/i18n/fr/translation.json index 89c47a9e..a23bf751 100644 --- a/frontend/src/i18n/fr/translation.json +++ b/frontend/src/i18n/fr/translation.json @@ -697,7 +697,8 @@ "supported_message_type_others": "Seuls les messages de modèle générique sont pris en charge.", "notification_type_regular": "Son/Vibration", "notification_type_silent_push": "Notification à l'écran uniquement", - "notification_type_no_push": "Aucune notification" + "notification_type_no_push": "Aucune notification", + "permanent": "Lorsqu'elle est activée, cette variable sera stockée dans le profil de l'abonné(e) et conservée pour les futures conversations." }, "charts": { "messages": "Messages", diff --git a/frontend/src/types/context-var.types.ts b/frontend/src/types/context-var.types.ts index 35b48a71..0cf795ee 100644 --- a/frontend/src/types/context-var.types.ts +++ b/frontend/src/types/context-var.types.ts @@ -19,11 +19,7 @@ export interface IContextVarAttributes { export interface IContextVarStub extends IBaseSchema, - OmitPopulate { - name: string; - label: string; - permanent: boolean; -} + OmitPopulate {} export interface IContextVar extends IContextVarStub, IFormat {}