Settings form

Page recipe

Use this page when people edit the configuration of a whole workspace, account or integration and save it in one go, such as a workspace's name, timezone and default sender. It names the screen and its scope in the header and keeps the fields in a narrow column, with Cancel and Save changes at the end of the form. Add a panel per group of related settings as the page grows.


Preview

Workspace settings

Set how this workspace identifies itself and the defaults its messages start from.

General

These settings apply to everyone who works in this workspace.

Source

import {
	Button,
	Checkbox,
	Form,
	FormLayout,
	FormLayoutGroup,
	Page,
	PageBody,
	PageHeader,
	PageHeaderDescription,
	PageHeaderTitle,
	Panel,
	PanelActions,
	PanelDescription,
	PanelFooter,
	PanelHeader,
	PanelSection,
	PanelTitle,
	Select,
	TextField,
} from '@customerio/pluma-components/react';

const timezoneOptions = [
	{ value: 'America/New_York', label: 'Eastern Time (US & Canada)' },
	{ value: 'America/Chicago', label: 'Central Time (US & Canada)' },
	{ value: 'America/Denver', label: 'Mountain Time (US & Canada)' },
	{ value: 'America/Los_Angeles', label: 'Pacific Time (US & Canada)' },
	{ value: 'Etc/UTC', label: 'Coordinated Universal Time (UTC)' },
	{ value: 'Europe/London', label: 'London' },
	{ value: 'Europe/Paris', label: 'Paris' },
	{ value: 'Europe/Berlin', label: 'Berlin' },
	{ value: 'Asia/Singapore', label: 'Singapore' },
	{ value: 'Asia/Tokyo', label: 'Tokyo' },
	{ value: 'Australia/Sydney', label: 'Sydney' },
];

const languageOptions = [
	{ value: 'en', label: 'English' },
	{ value: 'es', label: 'Spanish' },
	{ value: 'fr', label: 'French' },
	{ value: 'de', label: 'German' },
	{ value: 'pt-BR', label: 'Portuguese (Brazil)' },
	{ value: 'ja', label: 'Japanese' },
];

export interface SettingsFormValues {
	workspaceName: string;
	/** An IANA timezone name, such as `America/New_York`. */
	timezone: string;
	/** A language code, such as `en`. */
	language: string;
	senderEmail: string;
	sendWeeklySummary: boolean;
}

export interface SettingsFormProps {
	/** The current value of every field. */
	settings: SettingsFormValues;
	/** Called on every keystroke in the workspace name field. */
	onWorkspaceNameInput: (event: Event & { target: HTMLInputElement }) => void;
	/** Called with the timezone the user picks. */
	onTimezoneChange: (timezone: string | null) => void;
	/** Called with the language the user picks. */
	onLanguageChange: (language: string | null) => void;
	/** Called on every keystroke in the sender email field. */
	onSenderEmailInput: (event: Event & { target: HTMLInputElement }) => void;
	/** Called when the weekly summary checkbox is toggled. */
	onSendWeeklySummaryChange: (isChecked: boolean) => void;
	/** Called when the form is submitted. Return a promise to lock the fields until it settles. */
	onSave: () => void | Promise<void>;
	/** Called when the user discards their changes. */
	onCancel: () => void;
}

export function SettingsForm({
	settings,
	onWorkspaceNameInput,
	onTimezoneChange,
	onLanguageChange,
	onSenderEmailInput,
	onSendWeeklySummaryChange,
	onSave,
	onCancel,
}: SettingsFormProps) {
	return (
		<Page isFullScreen bodyContentWidth="narrow">
			<PageHeader>
				<PageHeaderTitle>Workspace settings</PageHeaderTitle>
				<PageHeaderDescription>
					Set how this workspace identifies itself and the defaults its messages start from.
				</PageHeaderDescription>
			</PageHeader>
			<PageBody>
				<Form onSubmit={onSave}>
					<Panel>
						<PanelHeader>
							<PanelTitle>General</PanelTitle>
							<PanelDescription>These settings apply to everyone who works in this workspace.</PanelDescription>
						</PanelHeader>
						<PanelSection>
							<FormLayout>
								<TextField
									label="Workspace name"
									description="Appears in the workspace switcher and in notifications sent to your team."
									value={settings.workspaceName}
									onInput={onWorkspaceNameInput}
								/>
								<FormLayoutGroup>
									<Select
										label="Timezone"
										description="Schedules and reports use this timezone."
										placeholder="Select a timezone"
										searchPlaceholder="Search timezones"
										isSearchable
										options={timezoneOptions}
										value={settings.timezone}
										onChange={onTimezoneChange}
									/>
									<Select
										label="Default language"
										description="Messages without a translation fall back to this language."
										placeholder="Select a language"
										options={languageOptions}
										value={settings.language}
										onChange={onLanguageChange}
									/>
								</FormLayoutGroup>
								<TextField
									label="Default sender email"
									description="New campaigns and broadcasts send from this address until you change it."
									type="email"
									value={settings.senderEmail}
									onInput={onSenderEmailInput}
								/>
								<Checkbox
									label="Send a weekly delivery summary to admins"
									description="Sent on Mondays with deliveries, opens, and bounces from the past week"
									isChecked={settings.sendWeeklySummary}
									onCheckedChange={onSendWeeklySummaryChange}
								/>
							</FormLayout>
						</PanelSection>
						<PanelFooter>
							<PanelActions>
								<Button variant="tertiary" size="sm" onClick={onCancel}>
									Cancel
								</Button>
								<Button variant="primary" size="sm" type="submit">
									Save changes
								</Button>
							</PanelActions>
						</PanelFooter>
					</Panel>
				</Form>
			</PageBody>
		</Page>
	);
}

Scaffold

Copy this recipe into your app with the Pluma CLI. Replace <dest-dir> with the folder the file goes in, and add --name <Name> to rename the component and its file.

pluma-cli scaffold settings-form <dest-dir> --framework react

Components

This recipe uses these components. Each one's docs page lists its props.

On this page