Skip to content

Commit

Permalink
#375 Make country renderer and region renderer as custom field render…
Browse files Browse the repository at this point in the history
…er components
  • Loading branch information
rajeev-k-tomy committed Oct 20, 2024
1 parent a397e63 commit 8768af1
Show file tree
Hide file tree
Showing 9 changed files with 113 additions and 56 deletions.
49 changes: 49 additions & 0 deletions src/reactapp/src/fieldRenderers/FieldRenderer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import {
ConfigMultiline,
ConfigTextInput,
ConfigSelectInput,
} from '../components/common/Form';
import { _emptyFunc } from '../utils';
import { FieldType } from '../utils/field';

export class FieldRenderer {
rendererList = [];

constructor() {
this.#registerDefaultRenderers();
}

register(renderer, sortOrder = 100, conditionCallback = _emptyFunc()) {
const newRenderer = {
renderer,
sortOrder,
canRenderField: conditionCallback,
};
this.rendererList = [...this.rendererList, newRenderer].sort(
(renderer1, renderer2) => renderer1.sortOrder - renderer2.sortOrder
);
}

getRendererForField(field) {
// eslint-disable-next-line no-restricted-syntax
for (const renderer of this.rendererList) {
if (renderer.canRenderField(field)) {
return renderer.renderer;
}
}

return false;
}

#registerDefaultRenderers() {
this.register(ConfigTextInput, 350, (field) =>
FieldType.isText(field.type)
);
this.register(ConfigSelectInput, 400, (field) =>
FieldType.isSelect(field.type)
);
this.register(ConfigMultiline, 300, (field) =>
FieldType.isMultiline(field.type)
);
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import React from 'react';

import { ConfigSelectInput } from '../../common/Form';
import { prepareCountryOptions } from '../utility';
import { ConfigSelectInput } from '../../../components/common/Form';
import useAppContext from '../../../hook/useAppContext';
import { prepareCountryOptions } from '../../../components/address/utility';
import { fieldConfigShape, formikDataShape } from '../../../utils/propTypes';

function CountryRenderer({ formikData, config }) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default function countryRendererCondition(field) {
return field.code === 'country_id';
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import CountryRenderer from './CountryRenderer';

export default CountryRenderer;
export { default as countryRendererCondition } from './condition';
31 changes: 31 additions & 0 deletions src/reactapp/src/fieldRenderers/customRenderers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import CountryRenderer, {
countryRendererCondition,
} from './components/countryRenderer';
import RegionRenderer, { regionRendererCondition } from './regionRenderer';

/**
* Holds custom renderers.
*
* renderer: React component that will be used to render the field.
*
* sortOrder: This defines the priority of the renderer component. All registered
* components have a sort order associated with it. When a field looks for
* a renderer, it loops through all the registered renderers and find a
* suitable renderer that can render the field based on the "condition".
* Lower the sort order, higher the chance to use the renderer.
*
* condition: This is a callback which determines whether the renderer can be
* used to render the field.
*/
export default [
{
renderer: CountryRenderer,
sortOrder: 100,
condition: countryRendererCondition,
},
{
renderer: RegionRenderer,
sortOrder: 200,
condition: regionRendererCondition,
},
];
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import React from 'react';

import { ConfigSelectInput, ConfigTextInput } from '../../common/Form';
import useCountryState from '../hooks/useCountryState';
import { fieldConfigShape, formikDataShape } from '../../../utils/propTypes';
import {
ConfigTextInput,
ConfigSelectInput,
} from '../../components/common/Form';
import { fieldConfigShape, formikDataShape } from '../../utils/propTypes';
import useCountryState from '../../components/address/hooks/useCountryState';

function RegionRenderer({ formikData, config }) {
const { stateOptions, hasStateOptions } = useCountryState({
Expand Down
3 changes: 3 additions & 0 deletions src/reactapp/src/fieldRenderers/regionRenderer/condition.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default function regionRendererCondition(field) {
return field.code === 'region';
}
5 changes: 5 additions & 0 deletions src/reactapp/src/fieldRenderers/regionRenderer/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import RegionRenderer from './RegionRenderer';

export default RegionRenderer;

export { default as regionRendererCondition } from './condition';
61 changes: 10 additions & 51 deletions src/reactapp/src/fieldRenderers/renderers.js
Original file line number Diff line number Diff line change
@@ -1,53 +1,12 @@
import {
ConfigMultiline,
ConfigTextInput,
ConfigSelectInput,
} from '../components/common/Form';
import { _emptyFunc } from '../utils';
import { FieldType } from '../utils/field';
import RegionRenderer from '../components/address/components/RegionRenderer';
import CountryRenderer from '../components/address/components/CountryRenderer';

class FieldRenderer {
rendererList = [];

constructor() {
this.#registerDefaultRenderers();
}

register(renderer, sortOrder = 100, conditionCallback = _emptyFunc()) {
const newRenderer = {
renderer,
sortOrder,
canRenderField: conditionCallback,
};
this.rendererList = [...this.rendererList, newRenderer].sort(
(renderer1, renderer2) => renderer1.sortOrder - renderer2.sortOrder
);
}

getRendererForField(field) {
// eslint-disable-next-line no-restricted-syntax
for (const renderer of this.rendererList) {
if (renderer.canRenderField(field)) {
return renderer.renderer;
}
}

return false;
}

#registerDefaultRenderers() {
this.register(CountryRenderer, 10, (field) => field.code === 'country_id');
this.register(RegionRenderer, 20, (field) => field.code === 'region');
this.register(ConfigTextInput, 30, (field) => FieldType.isText(field.type));
this.register(ConfigSelectInput, 10, (field) =>
FieldType.isSelect(field.type)
);
this.register(ConfigMultiline, 10, (field) =>
FieldType.isMultiline(field.type)
);
}
}
import customRenderers from './customRenderers';
import { FieldRenderer } from './FieldRenderer';

export const addressFieldRenderer = new FieldRenderer();

/**
* Here adds custom field renderers for address form.
*/
customRenderers.forEach((customrenderer) => {
const { renderer, sortOrder, condition } = customrenderer;
addressFieldRenderer.register(renderer, sortOrder, condition);
});

0 comments on commit 8768af1

Please sign in to comment.