Today ticket was to add an (owner name and email fields) in one of our tools.
those owners will come from Cognito-pool that exist within the backend. aside from this a default value should be used and this one comes from the already signed-in User(owner) on the front-end.
I know it sound like hHaaaa
This tool allows you to create a campaign that is used by our marketing team, where they set campaign that holds infos like expanses partners and a lot of other infos.
The campaign was built using react-admin platform
https://marmelab.com/react-admin/
Which is a great open source frontend Framework for building admin applications running in the browser, on top of REST/GraphQL APIs, using ES6, React and Material Design.
The only problem that I usually face with this platform is the BIG documentation and it's most of the times not clear to me where to start and how a specific component really works, what is the params and how it its working under the hood, but after a while I start liking this platform.
Basically the more you use it the more you will realise its fitting and has almost everything you need.
Back to the main task: so i need it to create 2 fields owner name and email and the email should be set automatically once you select the owner name and not to forget the default values incase there was no data or incase of creating new campaign.
In our case the owners was coming from the cognito-pool and not from a database
So I implemented a REST API called list-owners where this one use a lambda function on the backend that reads the cognito pool and return a list of users
As the following:
[
{
id: '123',
name: 'Ahmed Zeino',
email: 'azeino@company.com'
},
{
id: '124',
name: 'John doh',
email: 'jdoh@company.com'
}
]
Now the front end ,
React admin allows you to use a lot of viewing fields components such as
An example of the usages if AutocompleteInput is like this:-
const choices = [
{ id: 123, owner_name: 'Ahmed Zeino', email: 'azeino@company.com' },
{ id: 124, owner_name: 'John Doh', email: 'JDoh@company.com ' },
];
All of these components have some common properties like the source and reference.
The reference is the path that the api will look for and in our example its /owners as we set this in the rest api.
This will do the request and return the response that has the array of owners
[
{
id: '123',
name: 'Ahmed Zeino',
email: 'azeino@company.com'
},
{
id: '124',
name: 'John doh',
email: 'jdoh@company.com'
}
]
The react-admin component will use this as a source of data (choices in the AutocompleteInput component )
React admin will inject this data directly with component , without the need to use choices
And the component should display nicely the owners name list.
But the problem lies in the way that you need to display the email on a side field based on the selected owner name , even if there is no relation between those two.
So what to do ?
I solved this by splitting the problem into 3 parts
I need to display a list of owner names and a TextField that display the email.
I need to be able to pass the data coming from the api /owners to those two components.
I should be able to set the default values to these 2 components incase of the first load and in case there is no data yet.
so i did the following :-
I created a custom components called OwnersInput , this component will do the query of the rest api and pass the data to the sub components
and
I wrapped the with a thats allowing me to check the current form fields and allowing me to dispatch a change event that will change specific field of the form.
I'll put the component here and write more explanations on it
export const OwnersInput = ({
label,
source,
reference,
optionValue,
user = {},
formName = ''
}) => {
const {name: defaultUser} = user
const {email: defaultEmail} = user
return (<Query type={GET_LIST} resource={reference} payload={ownersPayload}>
{({data}) => {
return (data && (<div>
<AutocompleteInput
translateChoice={false}
choices={data}
allowEmpty
label={label}
optionValue={optionValue}
source={source}
validate={validateOwner}
defaultValue={defaultUser}
/>
<FormDataConsumer>
{({formData, dispatch}) => {
const email = getEmail(
formData,
data,
defaultEmail
)
if (
formData &&
formData.owner_email !== email
) {
console.log('CHANGING EMAIL')
dispatch(
change(
formName,
'owner_email',
email
)
)
}
return (
<TextInput
source="owner_email"
label="email"
defaultValue={defaultEmail}
disabled
style={layout}
/>
)
}}
</FormDataConsumer>
<div/>)
)
}}
</Query>
)
}
When creating this component i am giving it the init user name and email which is already saved in the state - on the front side (based on logged user) and thats how i am creating the default name and default email
I am also passing the reference as reference="owners"
And also the formName ,so i can do the dispatch on the right form
The component will do the query using GET_LIST
For the initial value u can pass it as defaultValue={defaultUser} inside the component
The get email function will check for the form field owner_name and it will grab the needed email after it compare it with the data , if not it will return the default email
Here is the usages inside a create page:-
<OwnersSingleInput
reference="owners"
label="owner"
optionValue="name"
source="owner_name"
formName="createForm"
user={user} // injected from the state
/>
I hope it was a clear and simple explanation ,otherwise feel free to ask me.
just run npm run myscript
Top comments (2)
Hi Ahmed, could you fix the code snippets/highlights?
Please refer to the Editor Guide.
sure ill do that , thanks for the note