mirror of
https://github.com/hexastack/hexabot
synced 2024-12-02 00:54:56 +00:00
feat: minor adjustements
This commit is contained in:
parent
cc6e50e5d0
commit
eb7d6ebe3c
@ -70,6 +70,8 @@ export enum FileType {
|
|||||||
export enum PayloadType {
|
export enum PayloadType {
|
||||||
location = 'location',
|
location = 'location',
|
||||||
attachments = 'attachments',
|
attachments = 'attachments',
|
||||||
|
quick_reply = 'quick_reply',
|
||||||
|
button = 'button',
|
||||||
}
|
}
|
||||||
|
|
||||||
export type StdOutgoingTextMessage = { text: string };
|
export type StdOutgoingTextMessage = { text: string };
|
||||||
|
@ -7,11 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { IncomingAttachmentPayload } from './attachment';
|
import { IncomingAttachmentPayload } from './attachment';
|
||||||
|
import { PayloadType } from './message';
|
||||||
export enum PayloadType {
|
|
||||||
location = 'location',
|
|
||||||
attachments = 'attachments',
|
|
||||||
}
|
|
||||||
|
|
||||||
export type Payload =
|
export type Payload =
|
||||||
| {
|
| {
|
||||||
|
@ -13,10 +13,13 @@ import {
|
|||||||
import { BlockFull } from '@/chat/schemas/block.schema';
|
import { BlockFull } from '@/chat/schemas/block.schema';
|
||||||
import { FileType } from '@/chat/schemas/types/attachment';
|
import { FileType } from '@/chat/schemas/types/attachment';
|
||||||
import { ButtonType } from '@/chat/schemas/types/button';
|
import { ButtonType } from '@/chat/schemas/types/button';
|
||||||
import { OutgoingMessageFormat } from '@/chat/schemas/types/message';
|
import {
|
||||||
|
OutgoingMessageFormat,
|
||||||
|
PayloadType,
|
||||||
|
} from '@/chat/schemas/types/message';
|
||||||
import { BlockOptions, ContentOptions } from '@/chat/schemas/types/options';
|
import { BlockOptions, ContentOptions } from '@/chat/schemas/types/options';
|
||||||
import { Pattern } from '@/chat/schemas/types/pattern';
|
import { Pattern } from '@/chat/schemas/types/pattern';
|
||||||
import { PayloadType, QuickReplyType } from '@/chat/schemas/types/quick-reply';
|
import { QuickReplyType } from '@/chat/schemas/types/quick-reply';
|
||||||
import { CaptureVar } from '@/chat/validation-rules/is-valid-capture';
|
import { CaptureVar } from '@/chat/validation-rules/is-valid-capture';
|
||||||
|
|
||||||
import { modelInstance } from './misc';
|
import { modelInstance } from './misc';
|
||||||
|
@ -151,7 +151,7 @@ const PatternInput: FC<PatternInputProps> = ({
|
|||||||
onChange={(payload) => {
|
onChange={(payload) => {
|
||||||
payload && setPattern(payload);
|
payload && setPattern(payload);
|
||||||
}}
|
}}
|
||||||
value={pattern ? (pattern as PayloadPattern).value : null}
|
defaultValue={pattern as PayloadPattern}
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
{typeof value === "string" && patternType === "regex" ? (
|
{typeof value === "string" && patternType === "regex" ? (
|
||||||
|
@ -6,10 +6,17 @@
|
|||||||
* 2. All derivative works must include clear attribution to the original creator and software, Hexastack and Hexabot, in a prominent location (e.g., in the software's "About" section, documentation, and README file).
|
* 2. All derivative works must include clear attribution to the original creator and software, Hexastack and Hexabot, in a prominent location (e.g., in the software's "About" section, documentation, and README file).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Box, Skeleton, Typography } from "@mui/material";
|
import {
|
||||||
import { useMemo } from "react";
|
Autocomplete,
|
||||||
|
Box,
|
||||||
|
CircularProgress,
|
||||||
|
InputAdornment,
|
||||||
|
Skeleton,
|
||||||
|
Typography,
|
||||||
|
} from "@mui/material";
|
||||||
|
import { useMemo, useState } from "react";
|
||||||
|
|
||||||
import AutoCompleteSelect from "@/app-components/inputs/AutoCompleteSelect";
|
import { Input } from "@/app-components/inputs/Input";
|
||||||
import { useFind } from "@/hooks/crud/useFind";
|
import { useFind } from "@/hooks/crud/useFind";
|
||||||
import { useGetFromCache } from "@/hooks/crud/useGet";
|
import { useGetFromCache } from "@/hooks/crud/useGet";
|
||||||
import { useTranslate } from "@/hooks/useTranslate";
|
import { useTranslate } from "@/hooks/useTranslate";
|
||||||
@ -26,25 +33,31 @@ import {
|
|||||||
|
|
||||||
import { useBlock } from "../../BlockFormProvider";
|
import { useBlock } from "../../BlockFormProvider";
|
||||||
|
|
||||||
type PayloadOption = {
|
type PayloadOption = PayloadPattern & {
|
||||||
id: string;
|
group: string;
|
||||||
label: string;
|
};
|
||||||
group?: string;
|
|
||||||
|
const isSamePostback = <T extends PayloadPattern>(a: T, b: T) => {
|
||||||
|
return a.label === b.label && a.value === b.value;
|
||||||
};
|
};
|
||||||
|
|
||||||
type PostbackInputProps = {
|
type PostbackInputProps = {
|
||||||
value?: string | null;
|
defaultValue?: PayloadPattern;
|
||||||
onChange: (pattern: PayloadPattern) => void;
|
onChange: (pattern: PayloadPattern | null) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const PostbackInput = ({ value, onChange }: PostbackInputProps) => {
|
export const PostbackInput = ({
|
||||||
|
defaultValue,
|
||||||
|
onChange,
|
||||||
|
}: PostbackInputProps) => {
|
||||||
const block = useBlock();
|
const block = useBlock();
|
||||||
|
const [selectedValue, setSelectedValue] = useState(defaultValue || null);
|
||||||
const getBlockFromCache = useGetFromCache(EntityType.BLOCK);
|
const getBlockFromCache = useGetFromCache(EntityType.BLOCK);
|
||||||
const { data: menu } = useFind(
|
const { data: menu, isLoading: isLoadingMenu } = useFind(
|
||||||
{ entity: EntityType.MENU, format: Format.FULL },
|
{ entity: EntityType.MENU, format: Format.FULL },
|
||||||
{ hasCount: false },
|
{ hasCount: false },
|
||||||
);
|
);
|
||||||
const { data: contents } = useFind(
|
const { data: contents, isLoading: isLoadingContent } = useFind(
|
||||||
{ entity: EntityType.CONTENT, format: Format.FULL },
|
{ entity: EntityType.CONTENT, format: Format.FULL },
|
||||||
{
|
{
|
||||||
hasCount: false,
|
hasCount: false,
|
||||||
@ -54,20 +67,21 @@ export const PostbackInput = ({ value, onChange }: PostbackInputProps) => {
|
|||||||
// General options
|
// General options
|
||||||
const generalOptions = [
|
const generalOptions = [
|
||||||
{
|
{
|
||||||
id: "GET_STARTED",
|
|
||||||
label: t("label.get_started"),
|
label: t("label.get_started"),
|
||||||
group: t("label.general"),
|
value: "GET_STARTED",
|
||||||
|
group: "general",
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
id: "VIEW_MORE",
|
|
||||||
label: t("label.view_more"),
|
label: t("label.view_more"),
|
||||||
group: t("label.general"),
|
value: "VIEW_MORE",
|
||||||
|
group: "general",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "LOCATION",
|
|
||||||
label: t("label.location"),
|
label: t("label.location"),
|
||||||
group: t("label.general"),
|
value: "LOCATION",
|
||||||
|
type: PayloadType.location,
|
||||||
|
group: "general",
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
// Gather previous blocks buttons
|
// Gather previous blocks buttons
|
||||||
@ -92,8 +106,8 @@ export const PostbackInput = ({ value, onChange }: PostbackInputProps) => {
|
|||||||
}, [] as (PostBackButton & { group: string })[])
|
}, [] as (PostBackButton & { group: string })[])
|
||||||
.map((btn) => {
|
.map((btn) => {
|
||||||
return {
|
return {
|
||||||
id: btn.payload,
|
|
||||||
label: btn.title,
|
label: btn.title,
|
||||||
|
value: btn.payload,
|
||||||
group: btn.group,
|
group: btn.group,
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
@ -125,6 +139,8 @@ export const PostbackInput = ({ value, onChange }: PostbackInputProps) => {
|
|||||||
return {
|
return {
|
||||||
id: btn.payload as string,
|
id: btn.payload as string,
|
||||||
label: btn.title as string,
|
label: btn.title as string,
|
||||||
|
value: btn.payload as string,
|
||||||
|
type: PayloadType.menu,
|
||||||
group: btn.group,
|
group: btn.group,
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
@ -132,9 +148,11 @@ export const PostbackInput = ({ value, onChange }: PostbackInputProps) => {
|
|||||||
);
|
);
|
||||||
const menuOptions = menu
|
const menuOptions = menu
|
||||||
.filter(({ payload }) => payload)
|
.filter(({ payload }) => payload)
|
||||||
.map(({ title }) => ({
|
.map(({ title, payload }) => ({
|
||||||
id: title,
|
id: title,
|
||||||
label: title,
|
label: title,
|
||||||
|
value: payload as string,
|
||||||
|
type: PayloadType.menu,
|
||||||
group: "menu",
|
group: "menu",
|
||||||
}));
|
}));
|
||||||
const contentOptions = useMemo(
|
const contentOptions = useMemo(
|
||||||
@ -158,15 +176,17 @@ export const PostbackInput = ({ value, onChange }: PostbackInputProps) => {
|
|||||||
return (b.options?.content?.buttons || []).reduce((payloads, btn) => {
|
return (b.options?.content?.buttons || []).reduce((payloads, btn) => {
|
||||||
// Return a payload for each node/button combination
|
// Return a payload for each node/button combination
|
||||||
payloads.push({
|
payloads.push({
|
||||||
id: btn.title,
|
|
||||||
label: btn.title,
|
label: btn.title,
|
||||||
|
value: btn.title,
|
||||||
|
type: PayloadType.content,
|
||||||
group: "content",
|
group: "content",
|
||||||
});
|
});
|
||||||
|
|
||||||
return availableContents.reduce((acc, n) => {
|
return availableContents.reduce((acc, n) => {
|
||||||
acc.push({
|
acc.push({
|
||||||
id: n.title,
|
|
||||||
label: n.title,
|
label: n.title,
|
||||||
|
value: n.title,
|
||||||
|
type: PayloadType.content,
|
||||||
group: "content",
|
group: "content",
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -178,52 +198,76 @@ export const PostbackInput = ({ value, onChange }: PostbackInputProps) => {
|
|||||||
[block?.previousBlocks, contents, getBlockFromCache],
|
[block?.previousBlocks, contents, getBlockFromCache],
|
||||||
);
|
);
|
||||||
// Concat all previous blocks
|
// Concat all previous blocks
|
||||||
const options = [
|
const options: PayloadOption[] = [
|
||||||
...generalOptions,
|
...generalOptions,
|
||||||
...btnOptions,
|
...btnOptions,
|
||||||
...qrOptions,
|
...qrOptions,
|
||||||
...menuOptions,
|
...menuOptions,
|
||||||
...contentOptions,
|
...contentOptions,
|
||||||
];
|
];
|
||||||
const isOptionsReady = !value || options.find((e) => e.id === value);
|
const isOptionsReady =
|
||||||
|
!defaultValue || options.find((o) => isSamePostback(o, defaultValue));
|
||||||
|
|
||||||
if (!isOptionsReady) {
|
if (!isOptionsReady) {
|
||||||
return (
|
return (
|
||||||
<Skeleton animation="wave" variant="rounded" width="100%" height={40} />
|
<Skeleton animation="wave" variant="rounded" width="100%" height={40} />
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
const selected = defaultValue
|
||||||
|
? options.find((o) => {
|
||||||
|
return isSamePostback(o, defaultValue);
|
||||||
|
})
|
||||||
|
: undefined;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<Autocomplete<PayloadOption>
|
||||||
<AutoCompleteSelect<PayloadOption, "label", false>
|
size="small"
|
||||||
value={value}
|
defaultValue={selected}
|
||||||
options={options}
|
options={options}
|
||||||
labelKey="label"
|
// label={t("label.postback")}
|
||||||
label={t("label.postback")}
|
|
||||||
multiple={false}
|
multiple={false}
|
||||||
onChange={(_e, content) => {
|
onChange={(_e, value) => {
|
||||||
content &&
|
setSelectedValue(value);
|
||||||
onChange({
|
if (value) {
|
||||||
label: content.label,
|
const { group: _g, ...payloadPattern } = value;
|
||||||
value: content.id,
|
|
||||||
type: ["content", "menu"].includes(content.group || "")
|
onChange(payloadPattern);
|
||||||
? PayloadType[content?.group || ""]
|
} else {
|
||||||
: undefined,
|
onChange(null);
|
||||||
});
|
}
|
||||||
}}
|
}}
|
||||||
groupBy={(option) => {
|
groupBy={(option) => {
|
||||||
return option.group ?? t("label.other");
|
return option.group ?? t("label.other");
|
||||||
}}
|
}}
|
||||||
getOptionLabel={({ group, label }) => `${group}:${label}`}
|
getOptionLabel={({ label }) => label}
|
||||||
renderGroup={(params) => (
|
renderGroup={(params) => (
|
||||||
<li key={params.key}>
|
<li key={params.key}>
|
||||||
<Typography component="h4" p={2} fontWeight={700} color="primary">
|
<Typography component="h4" p={2} fontWeight={700} color="primary">
|
||||||
{params.group}
|
{t(`label.${params.group}`)}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Box>{params.children}</Box>
|
<Box>{params.children}</Box>
|
||||||
</li>
|
</li>
|
||||||
)}
|
)}
|
||||||
|
renderInput={(props) => {
|
||||||
|
return (
|
||||||
|
<Input
|
||||||
|
{...props}
|
||||||
|
label={t("label.postback")}
|
||||||
|
InputProps={{
|
||||||
|
...props.InputProps,
|
||||||
|
startAdornment: (
|
||||||
|
<InputAdornment position="start">
|
||||||
|
{selectedValue?.type || t("label.postback")}
|
||||||
|
</InputAdornment>
|
||||||
|
),
|
||||||
|
endAdornment:
|
||||||
|
isLoadingMenu || isLoadingContent ? (
|
||||||
|
<CircularProgress color="inherit" size={20} />
|
||||||
|
) : null,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -66,6 +66,8 @@ export interface PayloadPattern {
|
|||||||
label: string;
|
label: string;
|
||||||
value: string;
|
value: string;
|
||||||
// @todo : rename 'attachment' to 'attachments'
|
// @todo : rename 'attachment' to 'attachments'
|
||||||
|
// @todo: If undefined, that means the payload could be either quick_reply or button
|
||||||
|
// We will move soon so that it will be a required attribute
|
||||||
type?: PayloadType;
|
type?: PayloadType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,6 +28,8 @@ export enum PayloadType {
|
|||||||
attachments = "attachments",
|
attachments = "attachments",
|
||||||
menu = "menu",
|
menu = "menu",
|
||||||
content = "content",
|
content = "content",
|
||||||
|
quick_reply = "quick_reply",
|
||||||
|
button = "button",
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum FileType {
|
export enum FileType {
|
||||||
|
Loading…
Reference in New Issue
Block a user