5.4 Settings & Configurations

Now that we have created our plugin that adds the Tasks functionality to our app, let's see if we can make it configurable.

There are "configurable", we mean 2 things:

  1. A developer that is using this plugin, can configure it via the configs prop.

  2. An end-user can configure the feature through the "Settings" UI.

We will attempt to do both these things in this chapter. For this example, we will make the number of items our Task List loads per page.

Step 1.1: Consume a Variable from the Config

Let's go back to our TaskList component from Chapter 4.2.

Change Line 32 from:

const itemsPerPage = 10;

To:

const [itemsPerPage] = useConfig('tasks.itemsPerPage');

Basically, rather than having a hardcoded number in the code, we extract it from config with key 'tasks.itemsPerPage'. We utilize the useConfig hook for this purpose, that is imported from the @bluebase/core package.

Note that the useConfig hook has the same API as the useState hook in the react library.

This should be your final code now:

src/components/TaskList/TaskList.tsx
import { QueryResult } from '@apollo/client';
import { Divider } from '@bluebase/components';
import { getComponent, useConfig } from '@bluebase/core';
import { GraphqlConnection, GraphqlListProps } from '@bluebase/plugin-json-graphql-components';
import React from 'react';
import { ListRenderItemInfo } from 'react-native';

import { Tasks, TasksCollectionQueryQuery, TasksCollectionQueryQueryVariables } from '../../graphql-types';
import TaskListEmptyState from '../TaskListEmptyState';
import { TaskListItem, TaskListItemProps } from '../TaskListItem';
import { TasksCollectionQuery, TasksCollectionQueryUpdateQueryFn } from './TasksCollectionQuery.graphql';

const GraphqlList = getComponent<GraphqlListProps<TaskListItemProps, TasksCollectionQueryQuery>>('GraphqlList');

function mapQueryResultToConnection(result: QueryResult<TasksCollectionQueryQuery>) {
	return result.data?.tasksCollection as GraphqlConnection<Tasks>;
}

function renderItem({ item }: ListRenderItemInfo<TaskListItemProps>) {
	return <TaskListItem {...item} />;
}

const renderDivider = () => <Divider inset />;

export interface TaskListProps {
	completed: boolean;
}

export const TaskList = (props: TaskListProps) => {
	const { completed } = props;
	const [itemsPerPage] = useConfig('tasks.itemsPerPage');

	const variables: TasksCollectionQueryQueryVariables = {
		filter: {
			completed: { 'eq': completed }
		}
	};

	return (
		<GraphqlList
			key="task-list"
			pagination="infinite"
			itemsPerPage={itemsPerPage}
			query={TasksCollectionQuery}
			updateQueryInfinitePagination={TasksCollectionQueryUpdateQueryFn}
			mapQueryResultToConnection={mapQueryResultToConnection}
			renderItem={renderItem}
			ItemSeparatorComponent={renderDivider}
			ListEmptyComponent={TaskListEmptyState}
			queryOptions={{
				variables
			}}
		/>
	);
};

TaskList.displayName = 'TaskList';

Step 1.2 Add Default Configs

Now that we are using the config, we also need to define its default value. Add the defaultConfigs object to your plugin as shown in the code below:

src/index.ts
import { createPlugin } from '@bluebase/core';

export default createPlugin({
	key: 'tasks',
	name: 'Tasks',
	description: 'A todo app made with BlueBase framework.',

	defaultConfigs: {
		'tasks.itemsPerPage': 10,
	}
	
	// ... other properties
});

Now run your app and inspect. You will observe that BlueBase has successfully loaded the default config, which has been passed onto the GraphqlList component.

Step 1.3: Override Config Value

Now comes the fun part. Let's override this value from our app's configs:

configs.ts
export const configs = {

	'tasks.itemsPerPage': 5,

	// ... other configs
};

Run your app again. You will observe that the value in the configs was loaded and preferred over the defaultConfigs.

Now, let's see how we can allow the end-user to customize the value too.

Step 2.1: Create a Form

Let's create a form that will allow the user to input a value, and update the config when he presses the submit button.

For this purpose, we will use the JsonForm component from the @bluebase/plugin-json-schema-components.

The props of JsonForm component are very similar to the GraphqlJsonForm that we have previously usesd.

This is because the GraphqlJsonForm too uses JsonForm internally.

JsonForm component is built using the formik library.

src/components/TaskSettingsForm/TaskSettingsForm.tsx
import { getComponent, useConfig } from '@bluebase/core';
import { JsonFormProps } from '@bluebase/plugin-json-schema-components';
import { FormikHelpers } from 'formik';
import React from 'react';

interface TaskSettingsFormValues {
	itemsPerPage: number;
}

const JsonForm = getComponent<JsonFormProps<TaskSettingsFormValues>>('JsonForm');

export interface TaskSettingsFormProps {}

export const TaskSettingsForm = (props: TaskSettingsFormProps) => {
	const [itemsPerPage, setItemsPerPage] = useConfig('tasks.itemsPerPage');

	return (
		<JsonForm
			{...props}
			schema={{
				validateOnBlur: false,
				validateOnChange: false,

				fields: [
					{
						autoFocus: true,
						label: 'Items per page',
						name: 'itemsPerPage',
						required: true,
						type: 'number',
					},
					{
						schema: { component: 'Divider' },
						type: 'component',
					},
					{
						direction: 'right',
						name: 'form-actions',
						type: 'inline',

						fields: [
							{
								name: 'reset',
								type: 'reset',
							},
							{
								name: 'submit',
								title: 'Save',
								type: 'submit',
							},
						],
					},
				],

				initialValues: {
					itemsPerPage,
				},

				onSubmit: (values: TaskSettingsFormValues, helpers: FormikHelpers<TaskSettingsFormValues>) => {
					const { setSubmitting } = helpers;
					setItemsPerPage(values.itemsPerPage);

					// Wait one second and then setSubmitting to false
					setTimeout(() => setSubmitting(false), 1000);
				}
			}}
		/>
	);
};

TaskSettingsForm.displayName = 'TaskSettingsForm';

Add the index file to export the component.

src/components/TaskSettingsForm/index.ts
export * from './TaskSettingsForm';

import { TaskSettingsForm } from './TaskSettingsForm';
export default TaskSettingsForm;

Step 2.2 Add Screen in the Settings App

Now we want to create a screen for "Tasks" in the Settings app. Luckily the Settings app allows this to be done via bluebase.plugin.setting-app.pages filter.

This filter inputs an array of screens in the settings app, all we have to do is to append our own screen configs and return the array. Create a new file and copy the following code:

src/filter.ts
import { SettingsPageProps } from '@bluebase/plugin-settings-app';

import TaskSettingsForm from './components/TaskSettingsForm';

export const filters = {
	'bluebase.plugin.setting-app.pages': [
		{
			key: 'bluebase-settings-todo-page',
			priority: 20,

			value: (pages: SettingsPageProps[]) => [
				{
					name: 'TaskSettings',
					path: 'task',

					options: {
						drawerIcon: { type: 'icon', name: 'checkbox-multiple-marked' },
						title: 'Tasks',
					},

					items: [
						{
							name: 'task-settings',
							component: TaskSettingsForm,
							title: 'Task Settings',
							description: 'Configure your tasks',
						},
					],
				},
				...pages,
			],
		},
	],
};

Note that in Line 22 till 27 we define the "Task Settings" panel and use the TaskSettingsForm component that we created in the previous step.

Let's add this filter to the plugin (See Line 13):

src/index.ts
import { createPlugin } from '@bluebase/core';


import { filters } from './filters';
import { lang } from './lang';

export default createPlugin({
	key: 'tasks',
	name: 'Tasks',
	description: 'A todo app made with BlueBase framework.',

	filters: {
		...filters,
		...lang,
	},
	
	// ... Other properties
});

Run the app and go to the settings section. You will see the "Tasks" settings page is added.

When you use and submit the form, you will observe that it will update the config to achieve the desired result:

Last updated