I have created a form which has two dropdowns when I select both of them and click on Add Story Button then a chat thread is added.
The problem is when I select New Intent Name and New Action Name from dropdown then the previous Action Name also gets added I don't want like that what I want is
- Story should start with Intent Name (This is mandatory)
- One Intent Name can Have multiple Actions But not duplicate actions
- With new Intent Name selected the previous Action Name should not be added only the selected Action Name should be added (To give a basic idea just like the messenger chat threads work)
I think I am not setting or mapping the state variable properly, please guide me as of where am I going wrong
While I am able to manage the 1st point I want help with the below two


My Code
import React, { useEffect, useState } from "react";
import {
Form,
Input,
Button,
Select,
Card,
Typography,
notification,
} from "antd";
import { Layout } from "antd";
const { Header, Footer, Content } = Layout;
const { Text } = Typography;
const { Option } = Select;
const CreateStory = () => {
const [form] = Form.useForm();
const [storyValue, setStoryValue] = useState("");
const [intentName, setIntentName] = useState([]);
const [actionName, setActionName] = useState([]);
const [valueIntent, setValueIntent] = useState("");
const [valueAction, setValueAction] = useState("");
const storyInputValue = (e) => {
setStoryValue(e.target.value);
};
const onFinish = (values) => {
console.log("Success:", values);
};
const onFinishFailed = (errorInfo: any) => {
console.log("Failed:", errorInfo);
};
const SelectIntentName = (valueIntent) => {
// console.log(valueIntent)
setValueIntent(valueIntent);
};
const SelectActionName = (valueAction) => {
// console.log(valueAction)
setValueAction(valueAction);
};
// Error Notification
const openNotificationWithIcon = (type) => {
notification[type]({
message: "intent name cannot be empty",
});
};
const addStory = () => {
// Story should start with intent name
if (!valueIntent) {
openNotificationWithIcon("error")
return;
}
// Handling duplicate intent values
else if (intentName.includes(valueIntent)) {
setActionName((prev) => [...prev, valueAction])
return;
}
else {
setActionName((prev) => [...prev, valueAction])
setIntentName((prev) => [...prev, valueIntent])
}
// For every intent name create a new thread
};
// console.log(intentName)
return (
<div className="csi-create-story-component-page-0103CS">
<Card
title="Create Story"
className="csi-create-story-screen-card-0104SC"
size="small"
>
<Form
onFinish={onFinish}
onFinishFailed={onFinishFailed}
layout="vertical"
>
<Form.Item
label="Story Name"
name="Story Name"
rules={[
{ required: true, message: "Please input your story name!" },
]}
>
<Input
value={storyValue}
onChange={storyInputValue}
placeholder="Enter story name"
/>
</Form.Item>
<div className="csi-action-intent-box-grid-column-0126">
<Form.Item
label="Intent Name"
name="Intent Name"
rules={[
{ required: true, message: "Please select your intent name!" },
]}
>
<Select
placeholder="Select a option"
allowClear
showSearch
onSelect={SelectIntentName}
>
<Option value="intent_name_1">intent_name_1</Option>
<Option value="intent_name_2">intent_name_2</Option>
<Option value="intent_name_3">intent_name_3</Option>
</Select>
</Form.Item>
<Form.Item
label="Action Name"
name="Action Name"
rules={[
{ required: true, message: "Please select your action name!" },
]}
>
<Select
placeholder="Select a option"
allowClear
showSearch
onSelect={SelectActionName}
>
<Option value="action_name_1">action_name_1</Option>
<Option value="action_name_2">action_name_2</Option>
<Option value="action_name_3">action_name_3</Option>
</Select>
</Form.Item>
</div>
<Form.Item>
<Button type="primary" htmlType="submit" onClick={addStory}>
ADD STORY
</Button>
</Form.Item>
</Form>
</Card>
<div>
<Layout className="csi-created-story-list-screen-card-0105SLS">
<Header>{storyValue}</Header>
<Content className="csi-intent-action-content-layout-0353IA">
{/* Number of div depends on number of elements in the intentName array */}
<div
className="csi-created-intent-action-parent-box-0237IA"
>
{intentName.map((intentName, index) => {
return (
<>
<div className="csi-intent-name-left-box" key={index}>
<span className="csi-intent-text-com-0245I">
<span className="csi-INTENT-text">Intent</span>
<Text>{intentName}</Text>
</span>
</div>
{actionName.map((actionName, index) => {
return (
<div className="csi-action-name-right-box" key={index}>
<span className="csi-action-text-com-0246A">
<span className="csi-ACTION-text">Action</span>
<Text>{actionName}</Text>
</span>
</div>
);
})}
</>
)
})}
{/* {actionName.map((actionName, index) => {
return (
<div className="csi-action-name-right-box" key={index}>
<span className="csi-action-text-com-0246A">
<span className="csi-ACTION-text">Action</span>
<Text>{actionName}</Text>
</span>
</div>
);
})} */}
</div>
</Content>
<Footer className="csi-footer-submit-button-for-intent-action-0357">
<Button type="primary">Submit</Button>
</Footer>
</Layout>
</div>
</div>
);
};
export default CreateStory;
CodePudding user response:
It is definitely because of index in key prop. React doesn't know what you want to render there.
Don't use index as key if you're going to change order of items
CodePudding user response:
The main issue relies with your implementation. You can not handle it with two array of strings. My opinion - Use a result array which will have items as object -
{
"intent_name": "",
"actions": [] //array of string
}
whenever Add Story button is clicked give an entry to this result array. condition should be like - if intent_name already exist then -> check if object.actions already have entry -> if not then give entry.
and loop through this result array to show the intent action list.
you can also use id instead of name in terms of uniqueness.
overall if you need any clarification then please ping me.
and apologies if I miss anything. I am trying this platform new.
