rbrown12
(Rhenne Brown)
July 11, 2021, 6:06pm
1
Good afternoon, Plone community!
I have a question regarding refacti\oring items in Volto. I have been refactoring my code in Volto using the example for TalkList in the Plone 6 training. However, the view doesn't display in a neat fashion. I am currently using a custom version of this code for my project.
A screenshot of the page has been included in this posting as a reference:
Also, here is the code for the view I am currently using which renders this example:
const ApplicationForm = ({ content }) => {
const results = useSelector(
(state) => state.search.subrequests.applicationform?.items,
);
const dispatch = useDispatch();
useEffect(() => {
dispatch(
searchContent(
'/',
{
// portal_type: ['applicationform'],
fullobjects: true,
},
'applicationform',
),
);
}, [dispatch]);
My question is how do I go about making the display neater without using bbb_getContentFetchesFullobjects in the config.js file? The reason I am trying to refactor this code is to prevent performance issues in rendering content in Volto.
I thank you kindly in advance for your help.
Sincerely,
rbrown12
I don't really understand the intention of the code, so perhaps you can add some more details. For example, I see the component name as "ApplicationForm", so I presume it's a view for ApplicationForm content types? But then you're searching for applicationform inside that view, so probably you couldn't get it to work for the real applicationforms?
rbrown12
(Rhenne Brown)
July 11, 2021, 8:12pm
3
@tiberiuichim ,
Thank you for your reply. The rest of the code is below:
import moment from 'moment';
import { Container, Modal, Table } from 'semantic-ui-react';
import React, { useEffect } from 'react';
import PDFViews from '../../PDFViews/PDFViews';
import ContentStatusHistory from '../ListingViews/ContentStatusHistory';
import { Link } from 'react-router-dom';
import Voting from '../../../Voting/Voting';
import { useDispatch, useSelector } from 'react-redux';
import { searchContent } from '../../../../../../../../omelette/src/actions/search/search';
const SchoolWidget = ({ school }) => {
return (
__CLIENT__ && (
<div>
<Table celled className="igibschool_list">
<Table.Header>
<Table.Row>
<Table.HeaderCell>School</Table.HeaderCell>
<Table.HeaderCell>Location</Table.HeaderCell>
<Table.HeaderCell>Year of Graduation</Table.HeaderCell>
<Table.HeaderCell>GPA</Table.HeaderCell>
<Table.HeaderCell>Major</Table.HeaderCell>
</Table.Row>
</Table.Header>
<Table.Body>
{school?.items?.map((item) => (
<Table.Row key={item.school}>
<Table.Cell>{item.school}</Table.Cell>
<Table.Cell>{item.location}</Table.Cell>
<Table.Cell>{item.year}</Table.Cell>
<Table.Cell>{item.gpa}</Table.Cell>
<Table.Cell>{item.major}</Table.Cell>
</Table.Row>
))}
</Table.Body>
</Table>
</div>
)
);
};
const EmployerWidget = ({ employer }) => {
return (
__CLIENT__ && (
<div>
<Table celled className="igibemployer_list">
<Table.Header>
<Table.Row>
<Table.HeaderCell>Employer Name</Table.HeaderCell>
<Table.HeaderCell>Employer Phone</Table.HeaderCell>
<Table.HeaderCell>Street</Table.HeaderCell>
<Table.HeaderCell>City</Table.HeaderCell>
<Table.HeaderCell>State</Table.HeaderCell>
<Table.HeaderCell>Postal Code</Table.HeaderCell>
</Table.Row>
</Table.Header>
<Table.Body>
{employer?.items?.map((item) => (
<Table.Row key={item.employer}>
<Table.Cell>{item.employer}</Table.Cell>
<Table.Cell>{item.employerPhone}</Table.Cell>
<Table.Cell>{item.street}</Table.Cell>
<Table.Cell>{item.city}</Table.Cell>
<Table.Cell>{item.state}</Table.Cell>
<Table.Cell>{item.zip}</Table.Cell>
</Table.Row>
))}
</Table.Body>
</Table>
</div>
)
);
};
const ReferencesWidget = ({ references }) => {
return (
__CLIENT__ && (
<div>
<Table celled className="igibreferences_list">
<Table.Header>
<Table.Row>
<Table.HeaderCell>
Name <em>Recommender</em>
</Table.HeaderCell>
<Table.HeaderCell>Email</Table.HeaderCell>
<Table.HeaderCell>
Institution/Organization/Company
</Table.HeaderCell>
<Table.HeaderCell>Address</Table.HeaderCell>
<Table.HeaderCell>Telephone Number</Table.HeaderCell>
<Table.HeaderCell>Relationship to You</Table.HeaderCell>
</Table.Row>
</Table.Header>
<Table.Body>
{references?.items?.map((item) => (
<Table.Row key={item.name}>
<Table.Cell>{item.name}</Table.Cell>
<Table.Cell>{item.email}</Table.Cell>
<Table.Cell>{item.ioc}</Table.Cell>
<Table.Cell>{item.address}</Table.Cell>
<Table.Cell>{item.phoneNumber}</Table.Cell>
<Table.Cell>{item.relationship}</Table.Cell>
</Table.Row>
))}
</Table.Body>
</Table>
</div>
)
);
};
const ApplicationForm = ({ content }) => {
const results = useSelector(
(state) => state.search.subrequests.applicationform?.items,
);
const dispatch = useDispatch();
useEffect(() => {
dispatch(
searchContent(
'/',
{
// portal_type: ['applicationform'],
fullobjects: true,
},
'applicationform',
),
);
}, [dispatch]);
return (
<Container className="view-wrapper">
<h1 className="documentFirstHeading">
{content.last_name}, {content.first_name}{' '}
{content.employeeID && -content.employeeID}
</h1>
<span className="contentStatusHistory">
<Modal closeIcon trigger={<Link>Change State</Link>} scrolling>
<Modal.Content>
<div>
<ContentStatusHistory {...content} />
</div>
</Modal.Content>
<br />
</Modal>
</span>
{results && <h2>Current Recommendations</h2>}
{results && (
<Table celled striped sortable fixed>
<Table.Header>
<Table.Row>
<Table.HeaderCell>Recommender</Table.HeaderCell>
<Table.HeaderCell>Recommend Applicant?</Table.HeaderCell>
</Table.Row>
</Table.Header>
<Table.Body>
{results &&
results.map((item) => (
<Table.Row key={item.id}>
<Table.Cell>
<Modal
trigger={<Link>{item.refereeName}</Link>}
scrolling
closeIcon
>
<Modal.Content>
<h1 className="documentFirstHeading">
{item.refereeName}
</h1>
<Voting />
{item.candidateName && (
<div>
<h3>
<strong>Applicant Name</strong>
</h3>
<h4>{item.candidateName}</h4>
</div>
)}
<br />
{item.refereeName && (
<div>
<h3>
<strong>Referee Name</strong>
</h3>
<h4>{item.refereeName}</h4>
</div>
)}
<br />
{item.email && (
<div>
<h3>
<strong>Email</strong>
</h3>
<h4>{item.email}</h4>
</div>
)}
<br />
{item.phone && (
<div>
<h3>
<strong>Telephone</strong>
</h3>
<h4>{item.phone}</h4>
</div>
)}
<br />
{item.address && (
<div>
<h3>
<strong>Mailing Address</strong>
</h3>
<h4>{item.address}</h4>
</div>
)}
<br />
{item.capacity && (
<div>
<h3>
<strong>Knowledge of Applicant</strong>
</h3>
<h3>
<strong>
What capacity have you known the Applicant?
</strong>
</h3>
<h4>{item.capacity}</h4>
</div>
)}
<br />
{item.howLong && (
<div>
<h3>
<strong>
How long have you known the Applicant?
</strong>
</h3>
<p>
<em>(years/months)</em>
</p>
<h4>{item.howLong}</h4>
</div>
)}
<br />
{item.knowledge && (
<div>
<h3>
<strong>Other</strong>
</h3>
<h4>{item.knowledge}</h4>
</div>
)}
<br />
{item.adapt && (
<div>
<h3>
<strong>Ability to adapt and change</strong>
</h3>
<h4>{item.adapt.token.toString()}</h4>
</div>
)}
<br />
{item.awareness && (
<div>
<h3>
<strong>Awareness of self and others</strong>
</h3>
<h4>{item.awareness.token.toString()}</h4>
</div>
)}
<br />
{item.maturity && (
<div>
<h3>
<strong>Maturity</strong>
</h3>
<h4>{item.maturity.token.toString()}</h4>
</div>
)}
<br />
{item.openness && (
<div>
<h3>
<strong>
Openness to feedback and constructive criticism{' '}
</strong>
</h3>
<h4>{item.openness.token.toString()}</h4>
</div>
)}
<br />
{item.interpersonal && (
<div>
<h3>
<strong>
Interpersonal skills (with superiors/executives){' '}
</strong>
</h3>
<h4>{item.interpersonal.token.toString()}</h4>
</div>
)}
<br />
{item.confidence && (
<div>
<h3>
<strong>Confidence</strong>
</h3>
<h4>{item.confidence.token.toString()}</h4>
</div>
)}
<br />
{item.initiative && (
<div>
<h3>
<strong>Initiative/Self-Motivation</strong>
</h3>
<h4>{item.initiative.token.toString()}</h4>
</div>
)}
<br />
{item.collaboration && (
<div>
<h3>
<strong>Collaboration/Teamwork</strong>
</h3>
<h4>{item.collaboration.token.toString()}</h4>
</div>
)}
<br />
{item.thinking && (
<div>
<h3>
<strong>Critical Thinking Skills </strong>
</h3>
<h4>{item.thinking.token.toString()}</h4>
</div>
)}
<br />
{item.curiosity && (
<div>
<h3>
<strong>Intellectual Curiosity</strong>
</h3>
<h4>{item.curiosity.token.toString()}</h4>
</div>
)}
<br />
{item.problemSolvingSkills && (
<div>
<h3>
<strong>Problem Solving Skills</strong>
</h3>
<h4>
{item.problemSolvingSkills.token.toString()}
</h4>
</div>
)}
<br />
{item.comments && (
<div>
<h3>
<strong>Additional comments</strong>
</h3>
<h4>{item.comments}</h4>
</div>
)}
<br />
{item.letter_recommendation && (
<div>
<h3>
<strong>Formal letter of recommendation</strong>
</h3>
<PDFViews
file={item.letter_recommendation.download}
/>
</div>
)}
<br />
{item.acceptanceAR && (
<div>
<h3>
<strong>For Academic Referees Only</strong>
</h3>
<h4>{item.acceptanceAR.token}</h4>
</div>
)}
<br />
{item.acceptanceNR && (
<div>
<h3>
<strong>For Non-Academic Referees Only</strong>
</h3>
<h4>{item.acceptanceNR.token}</h4>
</div>
)}
<br />
<h3>
<em>
<span> last modified </span>
<span> {moment(item.modified).fromNow('ll')}</span>
<span> ago </span>{' '}
</em>
</h3>
</Modal.Content>
</Modal>
</Table.Cell>
<Table.Cell>
{(item.acceptanceAR && item.acceptanceAR.token) ||
(item.acceptanceNR && item.acceptanceNR.token)}
</Table.Cell>
</Table.Row>
))}
</Table.Body>
</Table>
)}
<h3>
<strong>Reviewer's Comments</strong>
</h3>
{content.comments && <h4>{content.comments}</h4>}
{content.semester && (
<h3>
<strong>Semester</strong>
</h3>
)}
<h4>{content.semester && content.semester.token.toString()}</h4>
{content.program && (
<h3>
<strong>Program</strong>
</h3>
)}
<h4>{content.program && content.program.token.toString()}</h4>
{content.first_name && (
<h3>
<strong>First Name</strong>
</h3>
)}
<h4>{content.first_name && content.first_name}</h4>
{content.last_name && (
<h3>
<strong>Last Name</strong>
</h3>
)}
<h4>{content.last_name && content.last_name}</h4>
{content.street2 && (
<h3>
<strong>Street</strong>
</h3>
)}
<h4>{content.street2 && content.street2}</h4>
{content.city2 && (
<h3>
<strong>City</strong>
</h3>
)}
<h4>{content.city2 && content.city2}</h4>
{content.state2 && (
<h3>
<strong>State</strong>
</h3>
)}
<h4>{content.state2 && content.state2}</h4>
{content.zip2 && (
<h3>
<strong>Zip</strong>
</h3>
)}
<h4>{content.zip2 && content.zip2}</h4>
{content.phoneNumber && (
<h3>
<strong>Phone Number</strong>
</h3>
)}
<h4>{content.phoneNumber && content.phoneNumber}</h4>
{content.appl_email && (
<h3>
<strong>Email Address</strong>
</h3>
)}
<h4>{content.appl_email && content.appl_email}</h4>
{content.birthDate && (
<h3>
<strong>Date of Birth</strong>
</h3>
)}
<h4>{content.birthDate && moment(content.birthDate).format('ll')}</h4>
{content.gender && (
<h3>
<strong>Gender Identity</strong>
</h3>
)}
<h4>{content.gender && content.gender.token.toString()}</h4>
{content.veteran && (
<h3>
<strong>Are you a Veteran?</strong>
</h3>
)}
<h4>{content.veteran && content.veteran.token.toString()}</h4>
{content.f1student && (
<h3>
<strong>Are you a F1 student?</strong>
</h3>
)}
<h4>{content.f1student && content.f1student.token.toString()}</h4>
{content.citizen && (
<h3>
<strong>Are you a U.S. Citizen?</strong>
</h3>
)}
<h4>{content.citizen && content.citizen.token.toString()}</h4>
{content.birthCountry && (
<h3>
<strong>Country of Birth</strong>
</h3>
)}
<h4>{content.birthCountry && content.birthCountry.token.toString()}</h4>
<h3>
<strong>Country of Citizenship</strong>
</h3>
{content.citizenshipCountry && (
<h4>{content.citizenshipCountry.token.toString()}</h4>
)}
{content.permanent && (
<div>
<h2>Additional Citizenship Information:</h2>
<h2>U.S. Permanent Resident:</h2>
<h3>
<strong>Alien (A) Number</strong>
</h3>
</div>
)}
<h4>{content.permanent && content.permanent}</h4>
{content.permanent2 && (
<h3>
<strong>Date Obtained MM/YY</strong>
</h3>
)}
<h4>{content.permanent2 && moment(content.permanent2).format('ll')}</h4>
{content.temporary && <h2>Temporary Visa:</h2>}
{content.temporary && (
<h3>
<strong>Type of Visa</strong>
</h3>
)}
<h4>{content.temporary && content.temporary}</h4>
{content.temporary2 && (
<h3>
<strong>Date Obtained MM/YY</strong>
</h3>
)}
<h4>{content.temporary2 && moment(content.temporary2).format('ll')}</h4>
{content.temporary3 && (
<h3>
<strong>Date Expired MM/YY</strong>
</h3>
)}
<h4>{content.temporary3 && moment(content.temporary3).format('ll')}</h4>
{content.other && (
<h3>
<strong>Other: Explain</strong>
</h3>
)}
<h4>{content.other && content.other}</h4>
<h3>
<strong>Current Resume</strong>
</h3>
{content.resume && <PDFViews file={content.resume.download} />}
{content.statement && (
<div>
<h3>
<strong>Personal Statement</strong>
</h3>
<span></span>
</div>
)}
{content.statement && <PDFViews file={content.statement.download} />}
{content.toefl && (
<div>
<h3>
<strong>TOEFL or IELTS score</strong>
</h3>
</div>
)}
{content.toefl && <h4>{content.toefl}</h4>}
{content.score && (
<div>
<h3>
<strong>Unofficial copy of TOEFL or IELTS score</strong>
</h3>
</div>
)}
{content.score && <PDFViews file={content.score.download} />}
{content.date && (
<h3>
<strong>Date TOEFL/IELTS taken:</strong>
</h3>
)}
{content.date && <h4>{moment(content.date).format('ll')}</h4>}
{content.native && (
<h3>
<strong>Native Language</strong>
</h3>
)}
{content.native && <h4>{content.native}</h4>}
<h3>School Information</h3>
<SchoolWidget school={content.school} />
{content.occupation && (
<h3>
<strong>Present Occupation</strong>
</h3>
)}
{content.occupation && <h4>{content.occupation}</h4>}
<h3>Employer Information</h3>
<EmployerWidget employer={content.employerAddress} />
<h3>References Information</h3>
<ReferencesWidget references={content.references} />
{content.rconsent && (
<h3>
<strong>Letters of Recommendation</strong>
</h3>
)}
{content.rconsent && <h4>{content.rconsent.token.toString()}</h4>}
<br />
<p>
{content.statementConsent && content.statementConsent.token.toString()}
</p>
<br />
{content.transcript && (
<div>
<h3>
<strong>Official Transcript</strong>
</h3>
<p>
<em>Internal Use</em>
</p>
</div>
)}
<br />
{content.transcript && <PDFViews file={content.transcript.download} />}
<br />
{content.transcript1 && (
<div>
<h3>
<strong>Official Transcript</strong>
</h3>
<p>
<span>
<em>Internal Use</em>
</span>
</p>
</div>
)}
<br />
{content.transcript1 && <PDFViews file={content.transcript1.download} />}
<br />
{content.transcript2 && (
<div>
<h3>
<strong>Official Transcript</strong>
</h3>
<p>
<span>
<em>Internal Use</em>
</span>
</p>
</div>
)}
<br />
{content.transcript2 && <PDFViews file={content.transcript2.download} />}
<br />
{content.transcript3 && (
<div>
<h3>
<strong>Official Transcript</strong>
</h3>
<p>
<span>
<em>Internal Use</em>
</span>
</p>
</div>
)}
<br />
{content.transcript3 && <PDFViews file={content.transcript3.download} />}
<br />
{content.grade_equivalent && (
<div>
<h3>
<strong>Grade Equivalent</strong>
</h3>
<p>
<span>
<em>Internal Use</em>
</span>
</p>
</div>
)}
<br />
{content.grade_equivalent && (
<PDFViews file={content.grade_equivalent.download} />
)}
<br />
{content.english_translation && (
<div>
<h3>
<strong>English Translation</strong>
</h3>
<p>
<span>
<em>Internal Use</em>
</span>
</p>
</div>
)}
<br />
{content.english_translation && (
<PDFViews file={content.english_translation.download} />
)}
<br />
<h3>
<em>
<span> last modified </span>
<span> {moment(content.modified).fromNow('ll')}</span>
<span> ago </span>{' '}
</em>
</h3>
</Container>
);
};
export default ApplicationForm;
Yes, the view is for the ApplicationForm content types. It was working before when using bbb_getContentFetchesFullobjects in the config.js file and I would like to have it work without using this.
I thank you kindly.
Sincerely,
rbrown12
As far as I understand, your issue is the fact that you need to do an extra @search
endpoint call, instead of relying on the items list brought by the regular getContent call.
I don't think that's really an issue. It forces you to be aware of the batching problem: assuming you set the bbb_getContentFetchesFullobjects
to true, your users will see only a partial set of results, which is dangerous for the application.
Now, some extra tips based on your code:
you can rewrite import { searchContent } from '../../../../../../../../omelette/src/actions/search/search';
as import { searchContent } from '@plone/volto/actions'
.
you can rewrite import Voting from '../../../Voting/Voting';
as import Voting from '@package/Voting/Voting';
or import Voting from '~/Voting/Voting'
(note, your path might be different, the important point is that the <root>/src
of your project is aliased as @package
and ~
.
the use of __CLIENT__
is a smell.
Otherwise, looks good. Nice to see you advancing on your Volto app!