Получил изображенную ошибку при попытке настроить обработчик события onChange для функции FormRow. В конечном итоге необходимо сохранить пользовательские данные из времени сброса очереди, порога уровня обслуживания и порога короткого отказа. Queuecontainer — это основной класс, который использует редактор для создания форм-контейнеров.
QuesContainer.js
import React from 'react';
import Editor from './Editor';
import LoginForm from '../LoginForm';
import axios from 'axios';
export default class QueuesContainer extends React.Component {
constructor(props) {
super(props);
this.state = {
workspaceSID: '',
apiKey: '',
apiSecret: '',
queues: [],
name: '',
}
this.listQueues = this.listQueues.bind(this);
this.setCredentials = this.setCredentials.bind(this);
this.getCredentials = this.getCredentials.bind(this);
this.setQueues = this.setQueues.bind(this);
this.handleChangeEvent = this.handleChangeEvent.bind(this);
}
/*
handleChangeEvent(target) {
this.setState({ [target.id]: target.value });
}
*/
//Added by JR for Save Function
handleChangeEvent(event){
console.info("From handle change", event);
this.setState({ name: event.target.value })
}
/*
handleSubmit(event) {
event.preventDefault();
this.props.login(this.state.workspaceSID, this.state.apiKey, this.state.apiSecret);
}
*/
handleSubmit(event) {
event.preventDefault();
var text = this.state.text;
console.info("form testing value output:");
}
setCredentials(workspaceSID, apiKey, apiSecret) {
this.setState({ workspaceSID: workspaceSID });
this.setState({ apiKey: apiKey });
this.setState({ apiSecret: apiSecret });
}
getCredentials() {
return this.state;
}
setQueues(queues) {
this.setState({ queues: queues });
}
getConfig(apiKey, apiSecret) {
return axios.get(`https://flex-api.twilio.com/v1/Configuration`, {
auth: {
username: apiKey,
password: apiSecret
},
});
}
//Added by JR used to post configuration
postConfig(apiKey, apiSecret, params) {
return axios.post(`https://flex-api.twilio.com/v1/Configuration`, {
auth: {
username: apiKey,
password: apiSecret
},
});
}
listQueues(workspaceSID, apiKey, apiSecret) {
this.setCredentials(workspaceSID, apiKey, apiSecret);
const queuesPromise = axios.get(`https://taskrouter.twilio.com/v1/Workspaces/${workspaceSID}/TaskQueues?PageSize=1000&Page=0`, {
auth: {
username: apiKey,
password: apiSecret
},
});
const channelsPromise = axios.get(`https://taskrouter.twilio.com/v1/Workspaces/${workspaceSID}/TaskChannels?PageSize=1000&Page=0`, {
auth: {
username: apiKey,
password: apiSecret
},
});
const configPromise = this.getConfig(apiKey, apiSecret);
Promise.all([queuesPromise, channelsPromise, configPromise])
.then((values) => {
console.info(values);
const twilioQueues = values[0].data.task_queues;
const twilioChannels = values[1].data.channels;
// const config = values[2].data.queue_stats_configuration;
const voice = twilioChannels.find(channel => {
console.info(channel)
return channel.unique_name === 'voice'
});
const chat = twilioChannels.find(channel => {
console.info(channel)
return channel.unique_name === 'chat'
});
const email = twilioChannels.find(channel => {
console.info(channel)
return channel.unique_name === 'email'
});
const channels = [voice, chat, email];
const queues = twilioQueues.map(q => {
const queue = {
queue_sid: q.sid,
friendly_name: q.friendly_name,
channels
}
return queue;
});
this.setQueues(queues);
});
}
//onChange = {this.handleInputChange.bind(this)}
render() {
const { name } = this.state
return (
<div>
<p> Test Value is : {name} </p>
<LoginForm login = {this.listQueues} buttonText='Load Queues' />
<Editor onSubmit = {this.handleSubmit} onChange = {this.handleChangeEvent} data = {this.state.queues} credentials = {this.getCredentials} setData = {this.setQueues} />
</div>
);
}
}
Editor.js
import React from 'react';
import MaterialTable from 'material-table'
import Button from '@material-ui/core/Button';
import TextField from '@material-ui/core/TextField';
import Grid from '@material-ui/core/Grid';
import axios from 'axios';
import { waitForDomChange } from '@testing-library/react';
export default class Editor extends React.Component {
constructor(props) {
super(props);
this.state = {
open: false,
queue: {},
columns: [
{ title: 'Queue Name', field: 'friendly_name', editable: 'never' },
{ title: 'Channel', field: 'channel_friendly_name', editable: 'never' },
{ title: 'Reset Timezone', field: 'channel_reset_timezone' },
{ title: 'Reset Time', field: 'channel_reset_time' },
{ title: 'Service Level Threshold', field: 'channel_service_level_threshold', type: 'numeric' },
{ title: 'Short Abandoned Threshold', field: 'channel_service_level_threshold', type: 'numeric' },
]
}
this.handleClose = this.handleClose.bind(this);
// this.handleSave = this.handleSave.bind(this);
}
handleClose(xxx) {
console.info('this happening');
console.info(xxx);
this.setState({ open: true });
}
/*
handleSave(event) {
console.info('Saving user input data');
console.info(event);
this.setState({ value: event.target.value});
}
*/
render() {
console.info('hey ho');
console.group(this.props.data);
const queues = this.props.data.map(q => {
const channel = q.channels.find(c => c.unique_name === 'voice');
q.channel_friendly_name = channel.friendly_name;
q.channel_reset_time = channel.reset_time;
q.channel_reset_timezone = channel.reset_timezone;
q.channel_service_level_threshold = channel.service_level_threshold;
q.channel_service_level_threshold = channel.service_level_threshold;
return q;
})
return (
<div>
<MaterialTable
title='Queue SLA'
columns = {this.state.columns}
data = {queues}
options = {{
pageSize: 25,
pageSizeOptions: [25, 100, 500, 1000]
}}
detailPanel = {rowData => {
//Modified by JR for Save Function
return FormContainer(rowData, this.props.credentials().apiKey,
this.props.credentials().apiSecret, this.handleChangeEvent);
}}
/>
</div>
);
}
}
function FormRow(data, handleChangeEvent) {
const queue = data.data;
const channels = queue.channels;
return (
channels.map((channel, index) => (
<Grid container item sm = {12} spacing = {3}>
<Grid item sm = {2}>
<TextField
autoFocus
margin = "dense"
id = "channel_name"
label = "Channel"
type = "text"
value = {channel.friendly_name}
fullWidth
disabled
/>
</Grid>
<Grid item sm = {2}>
<TextField
autoFocus
margin = "dense"
id = "reset_timezone"
label = "Reset Timezone"
type = "text"
value = "GMT"
fullWidth
disabled
/>
</Grid>
<Grid item sm = {2}>
<TextField
autoFocus
margin = "dense"
id = "service_level_threshold"
label = "Service Level Threshold"
value = {channel.service_level_threshold}
onChange = {handleChangeEvent}
type = "text"
fullWidth
/>
</Grid>
<Grid item sm = {2}>
<TextField
autoFocus
margin = "dense"
id = "short_abandoned_threshold"
label = "Short Abandoned Threshold"
value = {channel.short_abandoned_threshold}
onChange = {handleChangeEvent}
type = "text"
fullWidth
/>
</Grid>
</Grid>
))
);
}
//Modified by JR for Save Function
function FormContainer(data, apiKey, apiSecret, props, handleChangeEvent) {
console.info('what');
console.info(data);
console.info('JSON what');
console.info(JSON.stringify(data));
const queue = data;
// const queue = data.data;
const channels = queue.channels;
const cancel = () => {
console.info('cancel');
}
const save = () => {
//Modified by JR for Save Function
console.info('save');
console.info(data);
console.info(JSON.stringify(data));
console.info('SaveButtonClicked');
waitForDomChange();
console.info(data);
console.info(JSON.stringify(data));
savebuttonclicked(queue, apiKey, apiSecret);
console.info('Props Information');
console.info(props);
console.info('Save Sucessful');
}
return (
<div>
<Grid container>
<Grid item sm = {1}></Grid>
<Grid container item sm = {11} spacing = {3}>
<FormRow data = {queue}
formOnChange = {handleChangeEvent}/>
</Grid>
<Grid
container
direction = "row"
justify = "flex-end"
alignItems = "center"
>
<Grid item sm = {1}></Grid>
<Grid item sm = {11} spacing = {3} justify = "flex-end"
alignItems = "center">
<Grid item sm = {2}>
<TextField
autoFocus
margin = "dense"
id = "reset_time"
label = "Queue Reset Time"
type = "text"
value = {channels.reset_time}
onChange = {handleChangeEvent}
fullWidth
/>
</Grid>
<Button variant = "outlined" onClick = {cancel} color = "secondary">Cancel</Button>
<Button variant = "outlined" onClick = {save} color = "primary">Save</Button>
</Grid>
</Grid>
</Grid>
</div>
);
}
//Add by JR for Save Function
function savebuttonclicked(data, apiKey, apiSecret) {
const workspace = workspaces[0];
console.info('Test');
alert(JSON.stringify(data));
console.info(JSON.stringify(data));
var params = [];
for (const [index, value] of data.channels.entries()) {
params.push({
'url': data.channels[index].url,
'unique_name': data.channels[index].unique_name,
'account_sid': data.channels[index].account_sid,
'channel_reset_time': data.channels[index].channel_reset_time,
'channel_reset_timezone': data.channels[index].channel_reset_timezone,
'channel_service_level_threshold': data.channels[index].channel_service_level_threshold
})
}
alert(JSON.stringify(params));
console.info('Parms for API post:');
console.info(JSON.stringify(params));
/*
* Loop for API call for each URL in created JSON
*
for (const [index, value] of params.entries())
{
axios.post(params[index].url, params[index], {
auth: {
username: apiKey,
password: apiSecret,
}
})
}
*/
axios.get(workspace.apiURL, {
auth: {
username: apiKey,
password: apiSecret,
},
})
.then(function (response) {
alert('Save Sucessful.')
alert(JSON.stringify(response))
console.info('success');
console.info(response.headers);
})
.catch(function (error) {
alert('Error Occured.')
alert(error)
console.info('Error');
console.info(error);
});
}
С примененным исправлением это новая ошибка:
TypeError: не удается прочитать свойства «каналов» неопределенного FormRow C:/Users/drago/Source/Repos/twilio-flex-editor/src/queues/Editor.js:99 96 | 97 | function FormRow({data, handleChangeEvent}) { 98 | постоянная очередь = данные.данные; > 99 | константные каналы = очередь.каналы; 100 | 101 | 102 | Просмотр скомпилированных ▶ 18 кадров стека были свернуты.
Вы определили FormRow
для использования обратного вызова handleChangeEvent
, а также неправильно определили свойства. Они должны быть деструктурированы из одного объекта реквизита.
function FormRow(data, handleChangeEvent) {...
но передали обратный вызов formOnChange
prop
<FormRow data = {queue} formOnChange = {handleChangeEvent} />
Вы также передаете this.handleChangeEvent
в Editor
, но никогда не потребляете его
<Editor
onSubmit = {this.handleSubmit}
onChange = {this.handleChangeEvent}
data = {this.state.queues}
credentials = {this.getCredentials}
setData = {this.setQueues}
/>
и (возможно, по совпадению) передать неопределенную this.handleChangeEvent
функцию FormContainer
, которая передается FormRow
компоненту.
Исправьте определение компонента FormRow
function FormRow({ data, handleChangeEvent }) {...
Передайте handleChangeEvent
на FormRow
как handleChangeEvent
.
<FormRow data = {queue} handleChangeEvent = {handleChangeEvent} />
Либо определите this.handleChangeEvent
в Editor
для передачи, либо передайте this.props.onChange
дальше.
return FormContainer(
rowData,
this.props.credentials().apiKey,
this.props.credentials().apiSecret,
this.props.onChange,
);
@ Hun73r3006 Hun73r3006 В вашем предыдущем коде data
обрабатывался как ваш объект «реквизит», а handleChangeEvent
был неопределенным, поэтому data.data
работал. Это было синонимом props.data
. С моим вышеуказанным исправлением data
уже деструктурирован из props
, поэтому вы можете просто деструктурировать queue
из data
, const { queue } = data;
, теперь data.queue.channels
или queue.channels
будут работать.
Отлично, это сработало, я все еще обращался к нему через Data.data. Спасибо. С точки зрения сохранения данных обратно в данные и передачи новых входных данных в функцию SaveButtonClicked, создайте контейнер в очереди и передайте их? Я тестировал что-то подобное, и данные не обновляются.
@ Hun73r3006 Hun73r3006 Этот дополнительный вопрос может быть немного не по теме этого сообщения SO, вам следует задать новый вопрос с подробностями. Похоже, ваша функция save
просто вызывает savebuttonclicked
и передает любое текущее значение реквизита/аргумента data
/queue
. ТБХ, я не совсем понимаю, о чем вы спрашиваете.
Это изображение ошибки, которую я получил: введите здесь описание изображения
Спасибо, я внес изменения, рекомендованные выше, но теперь получил следующую ошибку: TypeError: Cannot read property 'channels' undefined FormRow C:/Users/drago/Source/Repos/twilio-flex-editor/src/queues/Ed itor.js:99 96 | 97 | function FormRow({data, handleChangeEvent}) { 98 | постоянная очередь = данные.данные; > 99 | константные каналы = очередь.каналы; 100 | 101 | 102 | Просмотр скомпилированных ▶ 18 кадров стека были свернуты.