Introduction
The Chevron Employees Multipurpose Cooperative Society (CEMCS), as its name denotes, is a 55-year old cooperative society that serves the interests of the employees, retirees and expatriates of Chevron Nigeria Limited. I joined the company—as one member of its two-man IT team—to modernise it's digital products and web presence. As my teammate's skillset is heavily backend-focused, all product design and frontend development activities in the company have been my responsibility.
Purpose and Goal
A few of the applications delivered as part of this project are summarised below.
- Loans and deposits application: Loans and deposits (fixed deposits etc.) form the bulk of CEMCS's products.
- Approvals application: An approval pipeline is the heart of the company's operations—all member applications (for loans etc.) must be endorsed by authorised approvers.
- Mobile application: I handled only the design of this part of the project. Essentially, the products built in item 1 (above) were redesigned into a mobile application.
- Public Website A modern rebuild of the CEMCS website.
The company's old application was a somewhat archaic Visual Basic shop that used HTML tables for layouts and was compatible with only Internet Explorer. Also, as it was locked for use within the Chevron network, retiree members could not access it. Therefore, our main goal was to build a modern application (or suite of applications) that any member anywhere could use.
Preliminary Planning and Design
One main requirement I was given by my (non-technical managers) was that all the applications I designed were to look 'Chevrony'. In other words, the company's colors must be very prominent in all apps. This is particularly exemplified by the design of the new company website (in comparison to the old site).


In addition to the more vibrant use of color, the original long navigation was segmented and reduced. Also, actual indexable HTML elements were used to replace the photos found all over the old site.
Forms made up the bulk of the applications built in this project. A glimpse of how the forms were redesigned is provided below.


The first design change was to remove all multi-column form layouts for improved usability. Also, to reduce distraction and form clutter, prefilled view-only inputs (greyed out in the image above) were removed and only shown to the user in a confirmation screen. Finally, all input elements were revamped using modern tools available in the React ecosystem. Some of these, such as the amount input are shown in the images above.
Spotlight Feature: Form Pages CMS
When we started working on the forms for the project, we quickly realised that there was a lot or repeated content in each form. As a result, my colleague suggested that we build a system by which all form pages will be generated strictly from data. Despite being somewhat unconvinced about the practicality of his idea, I did try it out with the following approach:
-
Generate a dummy json data to form a skeleton of how pages will be rendered.
With the use of JSON Server, I prototyped the data needed for each page with the structure provided in the snippet below.
"formPages": [ { "id": 0, "name": "Any Random Form Page", "url": "/any-random-form-page", "data": { "confirmationMessage": "I, Any Person, consent to the sum I have entered above being withdrawn as cash from my deposit account, in the month of September 2021.", "explanationMessage": "All the fields in this form are required. Please fill them all before attempting to submit.", "fixedData": [ { "id": 5, "property": "Location", "value": "A location" }, // Any other fixed data (prefilled data in the old form) ], "inputGroups": [ { "id": 2, "inputs": [ { "id": 1, "detail": "", "fieldName": "methodOfCollection", "labelName": "Method of collection", "title": "Method of collection", "placeholder": "", "options": [ { "label": "Personal Cheque", "value": "Personal Cheque", "id": 3 }, { "label": "Credit my account/CEMCS", "value": "Credit my account/CEMCS", "id": 2 } ], "type": "radio" }, // Any other input components ], "name": "Select a method of collection" }, // Any other input groups ] } }, ]The data is made up of three key nested arrays: formPages, inputGroups and inputs. These were used to generate bits of the UI as illustrated in the image below.

Form UI data segments -
Use the data structure to generate form pages and UI components.
The application's form routes were constructed using React Router v5 in the following manner:
const formPages = formPagesData?.map(({ url, name, data, id, target }) => { return ( <Route path={url} key={id}> <SingleFormPage name={name} data={data} target={target} /> </Route> ); });An abridged version of the code for generating the input groups and components is also shown below:
const allInputComponents = inputGroups.map( ({ name, inputs, id, message }) => { return ( <fieldset key={id}> <legend>{name}</legend> {inputs.map(i => ( <React.Fragment key={id}>{renderRelevantInput(i)}</React.Fragment> ))} </fieldset> ); }, );The
renderRelevantInputmethod essentially contains a switch statement that loops over each input's type and returns relevant components for every case.
A minimal GUI was eventually created to automate this entire process even further. Despite its drawbacks, the output of this approach was a CMS of sorts that helped us move really quickly in this part of the project. To handle form state and frontend validation, React Hook Form and Yup were respectively used.
Lessons Learned
Despite it seeming like an ingenious solution to the woes of repetitive code, our homemade form management system was built on huge switch statements and some other really complex code. Therefore, the key lesson I learned from this project was the importance of adequately weighing tradeoffs before implementing an abstraction.