Maybe the Key to Better Code?
Tech Lead @ Healthie
@findniya
Tech Lead, Frontend Platform
www.findniya.com
Tech Lead, Frontend Platform
Working in React with Typescript.
Serious coffee addict
"Dry" stands for "Don't Repeat Yourself," which is a principle in software development that encourages the elimination of redundant or duplicated code. Writing "dry code" means creating code that avoids unnecessary repetition and promotes code reusability, readability, and maintainability.
const LandingPage = () => {
return (
<div>
<h1>Sample layout with repeating components</h1>
<section>
<h2>Sed ut perspiciatis</h2>
<p>Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit
aut fugit, sed quia consequuntur magni dolores eos qui ratione
voluptatem sequi nesciunt. Neque porro quisquam est.</p>
<button onClick={onClickFunction}>Click here</button>
</section>
<section>
<h2>Nemo enim ipsam</h2>
<p>Consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt.
Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet,
consectetur, adipisci velit, sed quia non numquam.</p>
<button onClick={onClickFunctionTwo}>Learn More</button>
</section>
<section>
<h2>Lorem ipsum dolor</h2>
<p>Amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt
ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis
nostrud exercitation ullamco laboris nisi.</p>
<button onClick={onClickFunctionThree}>Learn More</button>
</section>
<section>
<h2>Lorem ipsum dolor</h2>
<p>Amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut
labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud
exercitation ullamco laboris nisi.</p>
<button onClick={onClickFunctionThree}>Learn More</button>
</section>
</div>
)
}
const Section = ({title, para, onClick, buttonText}) => (
<section>
<h2>{title}</h2>
<p>{para}</p>
<button onClick={onClick}>{buttonText}</button>
</section>
)
const LandingPage = () => {
return (
<div>
<h1>Sample layout with repeating components</h1>
{sectionData.map((section, i)=><Section
key={i}
title={section.title}
para={section.para}
onClick={section.onClickFunctionOne}
buttonText={section.btnText}
/>)}
...etc
</div>
)
}
The quality of using more words than needed; wordiness.
Giving a lot of information clearly and in a few words.
Brief but comprehensive.
<Form onSubmit={onSubmit} render={({ handleSubmit, submitting, pristine }) =>
<form onSubmit={handleSubmit}>
<Field name='clientId' component='select'>
{clients.map(client => <option value={client.id}>{client.name}</option>)}
</Field>
<Field name={'date'}>
{props => <DatePicker {...props} selected={new Date()} onChange={e => props.input.onChange(e)}/>}
</Field>
<Field name='startTime'>
{props => <DatePicker {...props}
selected={new Date()}
showTimeSelect
showTimeSelectOnly
timeIntervals={15}
dateFormat="h:mm aa"
onChange={e => props.input.onChange(e)}/>}
</Field>
<Field name='endTime'>
{props => <DatePicker {...props}
selected={new Date()}
showTimeSelect
showTimeSelectOnly
timeIntervals={15}
dateFormat="h:mm aa"
onChange={e => props.input.onChange(e)}/>}
</Field>
<Field name='meetingTypeId' component='select'>
{meetingTypes.map(type => <option value={type.id}>{type.name}</option>)}
</Field>
<Field name='meetingFormatId' component='select'>
{meetingFormats.map(format => <option value={format.id}>{format.name}</option>)}
</Field>
<Field name={'notes'} component='textarea' placeholder="Notes"/>
<button type='submit' disabled={submitting || pristine}>Submit</button>
</form>
}
/>
const onSubmit = async (values) => {
try {
const response = await axios.post('/api/accountant/createMeeting', values)
return response.data
} catch (e) {
console.error('Error creating meeting', e)
throw e
}
}
import React from 'react'
import { Field, Form } from 'react-final-form'
import DatePicker from 'react-datepicker'
import axios from 'axios'
const MeetingForm = ({ clients, meetingTypes, meetingFormats }) => {
const onSubmit = async (values) => {
try {
const response = await axios.post('/api/accountant/createMeeting', values)
return response.data
} catch (e) {
console.error('Error creating meeting', e)
throw e
}
}
return (
<Form onSubmit={onSubmit} render={({ handleSubmit, submitting, pristine }) =>
<form onSubmit={handleSubmit}>
<Field name='email' type='text'>
{props => <input type='email' {...props.input}/>}
</Field>
<Field name='clients' component='select'>
{clients.map(client => <option value={client.id}>{client.name}</option>)}
</Field>
<Field name={'date'}>
{props => <DatePicker {...props} selected={new Date()} onChange={e => props.input.onChange(e)}/>}
</Field>
<Field name='startTime'>
{props => <DatePicker {...props}
selected={new Date()} showTimeSelect showTimeSelectOnly timeIntervals={15} dateFormat="h:mm aa" onChange={e => props.input.onChange(e)}/>}
</Field>
<Field name='endTime'>
{props => <DatePicker {...props}
selected={new Date()} showTimeSelect showTimeSelectOnly timeIntervals={15} dateFormat="h:mm aa" onChange={e => props.input.onChange(e)}/>}
</Field>
<Field name='meetingType' component='select'>
{meetingTypes.map(type => <option value={type.id}>{type.name}</option>)}
</Field>
<Field name='meetingFormat' component='select'>
{meetingFormats.map(format => <option value={format.id}>{format.name}</option>)}
</Field>
<Field name={'notes'} component='textarea' placeholder="Notes"/>
<button type='submit' disabled={submitting || pristine}>Submit</button>
</form>
}
/>
)
}
export default MeetingForm
import React from 'react'
import { Field, Form } from 'react-final-form'
import DatePicker from 'react-datepicker'
import axios from 'axios'
const MeetingForm = ({ clients, meetingTypes, meetingFormats }) => {
const onSubmit = async (values) => {
try {
const response = await axios.post('/api/accountant/createMeeting')
return response.data
} catch (e) {
console.error('Error creating meeting', e)
throw e
}
}
return (
<Form onSubmit={onSubmit} render={({ handleSubmit, submitting, pristine }) =>
<form onSubmit={handleSubmit}>
<Field name='email' type='text'>
{props => <input type='email' {...props.input}/>}
</Field>
<Field name='clients' component='select'>
{clients.map(client => <option value={client.id}>{client.name}</option>)}
</Field>
<Field name={'date'}>
{props => <DatePicker {...props} selected={new Date()} onChange={e => props.input.onChange(e)}/>}
</Field>
<Field name='startTime'>
{props => <DatePicker {...props}
selected={new Date()} showTimeSelect showTimeSelectOnly timeIntervals={15} dateFormat="h:mm aa" onChange={e => props.input.onChange(e)}/>}
</Field>
<Field name='endTime'>
{props => <DatePicker {...props}
selected={new Date()} showTimeSelect showTimeSelectOnly timeIntervals={15} dateFormat="h:mm aa" onChange={e => props.input.onChange(e)}/>}
</Field>
<Field name='meetingType' component='select'>
{meetingTypes.map(type => <option value={type.id}>{type.name}</option>)}
</Field>
<Field name='meetingFormat' component='select'>
{meetingFormats.map(format => <option value={format.id}>{format.name}</option>)}
</Field>
<Field name={'notes'} component='textarea' placeholder="Notes"/>
<button type='submit' disabled={submitting || pristine}>Submit</button>
</form>
}
/>
)
}
export default MeetingForm
const clients = {
id: ID
name: string
...otherClientInformation
}[]
const meetingTypes = {
id: ID
label: string
...otherMeetingTypesInformation
}[]
const meetingFormats = {
id:ID
name: string
...otherMeetingFormatsInformation
}[]
User Client List View
Client Calendar View
Client Dashboard View
Select clients
Select accountants
User Meeting Form
Client Meeting Form
User Calendar
User Client List
Client Dashboard
Client Calendar
const MeetingForm: React.FC = ({ clients, meetingTypes, meetingFormats, initialValues, currentUser }) => {
const onSubmit = async (values) => {
try {
const updatedValues = {...values, accountantId:currentUser.id}
const response = await axios.post('/api/accountant/createMeeting', meetingData: updatedValues)
return response.data
} catch (e) {
console.error('Error creating meeting', e)
throw e
}
}
return (
<Form onSubmit={onSubmit} initialValues={initialValues} render={({ handleSubmit, submitting, pristine }) =>
<form onSubmit={handleSubmit}>
...the rest of the form fields
</form>
}
/>
)
}
const initialValues = {
date: Date
startTime: Date
endTime: Date
clientId: null
meetingType: null
meetingFormat: null
notes: null
}
<Field name={'date'}>
{props => <DatePicker {...props}
selected={initialValues?.date ?? new Date()}
onChange={e => props.input.onChange(e)}/>
}
</Field>
<Field name='startTime'>
{props => <DatePicker {...props}
selected={initialValues?.date ?? new Date()}
showTimeSelect
showTimeSelectOnly
timeIntervals={15}
dateFormat="h:mm aa"
onChange={e => props.input.onChange(e)}/>
}
</Field>
<Field name='endTime'>
{props => <DatePicker {...props}
selected={initialValues?.date ?? new Date()}
showTimeSelect
showTimeSelectOnly
timeIntervals={15}
dateFormat="h:mm aa"
onChange={e => props.input.onChange(e)}/>
}
</Field>
const MeetingForm: React.FC = ({ clients, meetingTypes, meetingFormats, initialValues, currentUser }) => {
const onSubmit = async (values) => {
try {
const updatedValues = {...values, accountantId:currentUser.id}
const response = await axios.post('/api/createMeeing', meetingData: updatedValues)
return response.data
} catch (e) {
console.error('Error creating meeting', e)
throw e
}
}
return (
<Form onSubmit={onSubmit} initialValues={initialValues} render={({ handleSubmit, submitting, pristine }) =>
<form onSubmit={handleSubmit}>
...the rest of the form fields
</form>
}
/>
)
}
const initialValues = {
date: null
startTime: null
endTime: null
clientId: ID
meetingType: null
notes: null
}
const MeetingForm: React.FC = ({
clients,
meetingTypes,
meetingFormats,
initialValues,
currentUser,
accountants,
isClientView
}) => {
const onSubmit = async (values) => {
try {
const updatedValues = isClientView
? {...values, clientId: currentUser.id}
: {...values, accountantId: currentUser.id}
const response = await axios.post('/api/createMeeing', meetingData: updatedValues)
return response.data
} catch (e) {
console.error('Error creating meeting', e)
throw e
}
}
return (
<Form onSubmit={onSubmit} initialValues={initialValues} render={({ handleSubmit, submitting, pristine }) =>
<form onSubmit={handleSubmit}>
{isClientView
? <Field name='accountantId' component='select'>
{accountants.map(accountant => <option value={accountant.id}>{accountant.name}</option>)}
</Field>
:<Field name='clientId' component='select'>
{clients.map(client => <option value={client.id}>{client.name}</option>)}
</Field>
}
... the rest of the fields
</form>
}
/>
)
}
const MeetingForm: React.FC = ({
clients,
meetingTypes,
meetingFormats,
initialValues,
currentUser,
accountants,
isClientView
}) => {
return (
<Form onSubmit={onSubmit} initialValues={initialValues}
render={({ handleSubmit, submitting, pristine }) =>
<form onSubmit={handleSubmit}>
{isClientView
? <Field name='accountantId' component='select'>
{accountants.map(accountant => <option value={accountant.id}>{accountant.name}</option>)}
</Field>
:<Field name='clientId' component='select'>
{clients.map(client => <option value={client.id}>{client.name}</option>)}
</Field>
}
... the rest of the fields
</form>
}
/>
)
}
const initialValues = {
date: null
startTime: null
endTime: null
accountantId: null
meetingType: null
meetingFormat: null
notes: null
}
const onSubmit = async (values) => {
try {
const path = isClientView
? '/api/accountant/createMeeting'
: '/api/client/createMeeting'
const updatedValues = isClientView
? {...values, clientId: currentUser.id}
: {...values, accountantId: currentUser.id}
const response = await axios.post(path, meetingData: updatedValues)
return response.data
} catch (e) {
console.error('Error creating meeting', e)
throw e
}
}
const MeetingForm: React.FC = ({
clients,
meetingTypes,
meetingFormats,
initialValues,
currentUser,
accountants,
isClientView
}) => {
const onSubmit = async (values) => {
try {
const path = isClientView
? '/api/accountant/createMeeting'
: '/api/client/createMeeting'
const updatedValues = isClientView
? {...values, clientId: currentUser.id}
: {...values, accountantId: currentUser.id}
const response = await axios.post(path, meetingData: updatedValues)
return response.data
} catch (e) {
console.error('Error creating meeting', e)
throw e
}
}
return (
<Form onSubmit={onSubmit} initialValues={initialValues} render={({ handleSubmit, submitting, pristine }) =>
<form onSubmit={handleSubmit}>
{isClientView
? <Field name='accountantId' component='select'>
{accountants.map(accountant => <option value={accountant.id}>{accountant.name}</option>)}
</Field>
:<Field name='clientId' component='select'>
{clients.map(client => <option value={client.id}>{client.name}</option>)}
</Field>
}
... the rest of the fields
</form>
}
/>
)
}
const initialValues = {
date: Date
startTime: Date
endTime: Date
accountantId: null
meetingType: null
meetingFormat: null
notes: null
}
import React from 'react'
import { Field, Form } from 'react-final-form'
import DatePicker from 'react-datepicker'
import axios from 'axios'
const MeetingForm: React.FC = ({
clients,
meetingTypes,
meetingFormats,
initialValues,
currentUser,
accountants,
isClientView,
}) => {
const onSubmit = async (values) => {
try {
const path = isClientView
? '/api/accountant/createMeeting'
: '/api/client/createMeeting'
const updatedValues = isClientView
? {...values, clientId: currentUser.id}
: {...values, accountantId: currentUser.id}
const response = await axios.post(path, meetingData: updatedValues)
return response.data
} catch (e) {
console.error('Error creating meeting', e)
throw e
}
}
return (
...Form
)
}
export default MeetingForm
<Form onSubmit={onSubmit}
initialValues={initialValues}
render={({ handleSubmit, submitting, pristine }) =>
<form onSubmit={handleSubmit}>
{isClientView
? <Field name='accountantId' component='select'>
{accountants.map(accountant => <option value={accountant.id}>{accountant.name}</option>)}
</Field>
:<Field name='clientId' component='select'>
{clients.map(client => <option value={client.id}>{client.name}</option>)}
</Field>
}
<Field name={'date'}>
{props => <DatePicker {...props}
selected={initialValues?.date ?? new Date()} onChange={e => props.input.onChange(e)}/>}
</Field>
<Field name='startTime'>
{props => <DatePicker {...props}
selected={initialValues?.startTime ?? new Date()} showTimeSelect showTimeSelectOnly timeIntervals={15} onChange={e => props.input.onChange(e)}/>}
</Field>
<Field name='endTime'>
{props => <DatePicker {...props}
selected={initialValues?.endTime ?? new Date()} showTimeSelect showTimeSelectOnly timeIntervals={15} onChange={e => props.input.onChange(e)}/>}
</Field>
<Field name='meetingType' component='select'>
{meetingTypes.map(type => <option value={type.id}>{type.name}</option>)}
</Field>
<Field name='meetingFormat' component='select'>
{meetingFormats.map(format => <option value={format.id}>{format.name}</option>)}
</Field>
<Field name={'notes'} component='textarea' placeholder="Notes"/>
<button type='submit' disabled={submitting || pristine}>Submit</button>
</form>
}
/>
User Calendar
Client Dashboard
Client Calendar
const creatMeeting = async (values) =>{
try {
const path = isClientView
? '/api/accountant/createMeeting'
: '/api/client/createMeeting'
const updatedValues = isClientView
? {...values, clientId: currentUser.id}
: {...values, accountantId: currentUser.id}
const response = await axios.post(path, meetingData: updatedValues)
return response.data
} catch (e) {
console.error('Error creating meeting', e)
throw e
}
}
const editMeeting = async (values) =>{
try {
const path = isClientView
? '/api/accountant/editMeeting'
: '/api/client/editMeeting'
const updatedValues = isClientView
? {...values, clientId: currentUser.id, id: meetingId}
: {...values, accountantId: currentUser.id, id:meetingId}
const response = await axios.post(path, meetingData: updatedValues)
return response.data
} catch (e) {
console.error('Error creating meeting', e)
throw e
}
}
const creatMeeting = async (values) =>{
try {
const path = isClientView
? '/api/accountant/createMeeting'
: '/api/client/createMeeting'
const updatedValues = isClientView
? {...values, clientId: currentUser.id}
: {...values, accountantId: currentUser.id}
const response = await axios.post(path, meetingData: updatedValues)
return response.data
} catch (e) {
console.error('Error creating meeting', e)
throw e
}
}
const editMeeting = async (values) =>{
try {
const path = isClientView
? '/api/accountant/editMeeting'
: '/api/client/editMeeting'
const updatedValues = isClientView
? {...values, clientId: currentUser.id, id: meetingId}
: {...values, accountantId: currentUser.id, id:meetingId}
const response = await axios.post(path, meetingData: updatedValues)
return response.data
} catch (e) {
console.error('Error creating meeting', e)
throw e
}
}
const onSubmit = async (values) => {
try {
const response = meetingId === null
? await creatMeeting(values)
: await editMeeting(values)
return response.data
} catch (e) {
console.error('Error creating meeting', e)
throw e
}
}
import React from 'react'
import { Field, Form } from 'react-final-form'
import DatePicker from 'react-datepicker'
import axios from 'axios'
const MeetingForm: React.FC = ({
clients,
meetingTypes,
meetingFormats,
initialValues,
currentUser,
accountants,
isClientView,
meetingId
}) => {
const creatMeeting = async (values) =>{
try {
const path = isClientView
? '/api/accountant/createMeeting'
: '/api/client/createMeeting'
const updatedValues = isClientView
? {...values, clientId: currentUser.id}
: {...values, accountantId: currentUser.id}
const response = await axios.post(path, meetingData: updatedValues)
return response.data
} catch (e) {
console.error('Error creating meeting', e)
throw e
}
}
const editMeeting = async (values) =>{
try {
const path = isClientView
? '/api/accountant/editMeeting'
: '/api/client/editMeeting'
const updatedValues = isClientView
? {...values, clientId: currentUser.id, id: meetingId}
: {...values, accountantId: currentUser.id, id:meetingId}
const response = await axios.post(path, meetingData: updatedValues)
return response.data
} catch (e) {
console.error('Error creating meeting', e)
throw e
}
}
const onSubmit = async (values) => {
try {
const response = meetingId === null
? await creatMeeting(values)
: await editMeeting(values)
return response.data
} catch (e) {
console.error('Error creating meeting', e)
throw e
}
}
return (
<Form onSubmit={onSubmit} initialValues={initialValues} render={({ handleSubmit, submitting, pristine }) =>
<form onSubmit={handleSubmit}>
{isClientView
? <Field name='accountantId' component='select'>
{accountants.map(accountant => <option value={accountant.id}>{accountant.name}</option>)}
</Field>
:<Field name='clientId' component='select'>
{clients.map(client => <option value={client.id}>{client.name}</option>)}
</Field>
}
<Field name={'date'}>
{props => <DatePicker {...props} selected={initialValues?.date ?? new Date()} onChange={e => props.input.onChange(e)}/>}
</Field>
<Field name='startTime'>
{props => <DatePicker {...props} selected={initialValues?.startTime ?? new Date()} showTimeSelect showTimeSelectOnly timeIntervals={15} onChange={e => props.input.onChange(e)}/>}
</Field>
<Field name='endTime'>
{props => <DatePicker {...props} selected={initialValues?.endTime ?? new Date()} showTimeSelect showTimeSelectOnly timeIntervals={15} onChange={e => props.input.onChange(e)}/>}
</Field>
<Field name='meetingType' component='select'>
{meetingTypes.map(type => <option value={type.id}>{type.name}</option>)}
</Field>
<Field name='meetingFormat' component='select'>
{meetingFormats.map(format => <option value={format.id}>{format.name}</option>)}
</Field>
<Field name={'notes'} component='textarea' placeholder="Notes"/>
<button type='submit' disabled={submitting || pristine}>Submit</button>
</form>
}
/>
)
}
export default MeetingForm
return (
<Form onSubmit={onSubmit} initialValues={initialValues} render={({ handleSubmit, submitting, pristine }) =>
<form onSubmit={handleSubmit}>
{isClientView
? <Field name='accountantId' component='select'>
{accountants.map(accountant => <option value={accountant.id}>{accountant.name}</option>)}
</Field>
:<Field name='clientId' component='select'>
{clients.map(client => <option value={client.id}>{client.name}</option>)}
</Field>
}
<Field name={'date'}>
{props => <DatePicker {...props}
selected={initialValues?.date ?? new Date()} onChange={e => props.input.onChange(e)}/>}
</Field>
<Field name='startTime'>
{props => <DatePicker {...props}
selected={initialValues?.startTime ?? new Date()}
showTimeSelect showTimeSelectOnly timeIntervals={15} onChange={e => props.input.onChange(e)}/>}
</Field>
<Field name='endTime'>
{props => <DatePicker {...props}
selected={initialValues?.endTime ?? new Date()}
showTimeSelect showTimeSelectOnly timeIntervals={15} onChange={e => props.input.onChange(e)}/>}
</Field>
<Field name='meetingType' component='select'>
{meetingTypes.map(type => <option value={type.id}>{type.name}</option>)}
</Field>
<Field name='meetingFormat' component='select'>
{meetingFormats.map(format => <option value={format.id}>{format.name}</option>)}
</Field>
<Field name={'notes'} component='textarea' placeholder="Notes"/>
<button type='submit' disabled={submitting || pristine}>Submit</button>
</form>
}
/>
)
}
export default MeetingForm
As the business grows there can be more and more feature-specific requirements.
For Example: On List view disable date and times where the accountant already has meetings.
Complexity
The complexity of the component increases with each new product requirement.
Debugging
Increased complexity, leads hard to read code, which makes debugging even harder.
Product Locked
Each of the different product areas are now locked together. A change in one means a bug or change in the other.
Developer productivity suffers and it becomes increasingly harder to make changes to the component.
Focuses on the rules and workflows for a user, specific to a particular business.
Is the technical decisions and coding practices employed by developers to implement the business logic.
User Calendar
User Client List
Client Dashboard
Client Calendar
User Calendar
User Client List
Client Dashboard
Client Calendar
User Calendar
User Client List
1.
User clicks on Calendar day/ time slot
2.
Modal with Meeting Form appears with day/time pre-filled
3.
User inputs blank fields and submits form
4.
Meeting is booked and appears on the calendar.
1.
User clicks on Book Meeting button for a specific client.
2.
Modal with Meeting Form appears with client data pre-filled
3.
User inputs blank fields and submits form
4.
Meeting is booked.
Client Calendar
Client Dashboard
1.
Client clicks on Calendar day/ time slot
2.
Modal with Meeting Form appears with day/time pre-filled
3.
Client inputs blank fields and submits form
4.
Meeting is booked and appears on the calendar
1.
Client clicks on Book Meeting button
2.
Modal with Meeting Form appears
3.
Client inputs blank fields and submits form
4.
Meeting is booked and appears on the dashboard
By making the Meeting Form Component the same for each unique feature area, the developer has made the Business Decision to make the features dependent on each other.
const AccountantCalendarMeeting = () => {
const creatMeeting = async (values) =>{
...post call for creating meeting
}
}
const editMeeting = async (values) =>{
try {
...poset call for editing
}
}
const onSubmit = async (values) => {
try {
const response = meetingId === null
? await creatMeeting(values)
: await editMeeting(values)
return response.data
} catch (e) {
console.error('Error creating meeting', e)
throw e
}
}
// fetch and format data for form dependencies.
// handle the opening and closing of the modal
return (
<MeetingForm
onSubmit={onSubmit}
initialValues={initialValues}
clients={clients}
userId={currentUser.id}
meetingTypes={meetingTypes}
meetingFormats={meetingFormats}
meetingId={meetingId ?? null}
/>
)
}
const ClientCalendarMeeting = () => {
const creatMeeting = async (values) =>{
...post call for creating meeting
}
}
const editMeeting = async (values) =>{
try {
...poset call for editing
}
}
const onSubmit = async (values) => {
try {
const response = meetingId === null
? await creatMeeting(values)
: await editMeeting(values)
return response.data
} catch (e) {
console.error('Error creating meeting', e)
throw e
}
}
// fetch and format data for form dependencies.
// handle the opening and closing of the modal
return (
<ClientMeetingForm
onSubmit={onSubmit}
initialValues={initialValues}
accountants={accoutants}
userId={currentUser.id}
meetingTypes={meetingTypes}
meetingFormats={meetingFormats}
meetingId={meetingId ?? null}
/>
)
}
Meeting Form Component, just for the Accountants.
Accountant Meeting Form Component
<Form onSubmit={onSubmit}
initialValues={initialValues}
render={({ handleSubmit, submitting, pristine }) =>
<form onSubmit={handleSubmit}>
<Field name='accountantId' component='select'>
{accountants.map(accountant =>
<option value={accountant.id}>{accountant.name}</option>)}
</Field>
<Field name={'date'}>
{props => <DatePicker {...props}
selected={initialValues?.date ?? new Date()} onChange={e => props.input.onChange(e)}/>}
</Field>
<Field name='startTime'>
{props => <DatePicker {...props}
selected={initialValues?.startTime ?? new Date()}
showTimeSelect showTimeSelectOnly timeIntervals={15}
onChange={e => props.input.onChange(e)}/>}
</Field>
<Field name='endTime'>
{props => <DatePicker {...props}
selected={initialValues?.endTime ?? new Date()}
showTimeSelect showTimeSelectOnly timeIntervals={15}
onChange={e => props.input.onChange(e)}/>}
</Field>
<Field name='meetingType' component='select'>
{meetingTypes.map(type => <option value={type.id}>{type.name}</option>)}
</Field>
<Field name='meetingFormat' component='select'>
{meetingFormats.map(format => <option value={format.id}>{format.name}</option>)}
</Field>
<Field name={'notes'} component='textarea' placeholder="Notes"/>
<button type='submit' disabled={submitting || pristine}>Submit</button>
</form>
}
/>
Use Storybook or something like it for your component documentation
Image from: https://design-system.atoka.io/?path=/story/forms-form--full-form