Sana Assistant (online)
Table of Contents

Template field editors

The templateFields object is a supported web store named export that Sana expects an add-on to provide from its entry JavaScript module.

It's an object with the signature described below, whose property names are the template field editor names and property values are objects with instances of the React components, responsible for rendering of the corresponding editors for template fields.

templateFields?: Record<string,
    | {
      editor: TemplateFieldEditor;
    }
    | {
      display: ReadOnlyTemplateFieldEditor;
    }>;

Example:

import type { AddonExports } from 'sana/types';
import DeliveryDateEditor from 'components/DeliveryDateEditor';
import DeliveryDateDisplay from 'components/DeliveryDateDisplay';

const addonExports: AddonExports = {
  templateFields: {
    MyDeliveryDateEditor: {
      editor: DeliveryDateEditor,
    },
    MyDeliveryDateEditorReadOnly: {
      display: DeliveryDateDisplay,
    },
  },
};

export default addonExports;

TemplateFieldEditor component

The TemplateFieldEditor is react component to manage template field value. It expects the properties of TemplateFieldEditorProps<S = any> type where S is the type of editor settings.

The TemplateFieldEditorProps<S = any> type contains the following properties:

Property Type Description
fieldName string The field form name.
fieldTitle string The field title.
description string | null The field description.
settings S = any The editor settings.
initialValue any The initial field value.
disabled boolean The value indicating whether the field is disabled.
required boolean The value indicating whether the field value is required.
validation Validation Object with field value validation rules.

The Validation type contains the following properties:

Property Type Description
required (optional) boolean Enables validation that field is mandatory.
custom (optional) (value: any) => string | null | undefined Custom validation function which returns undefined in case validation succeeded, nullable error message otherwise.

Example:

import type { TemplateFieldEditor } from 'sana/templateFields';
import { useMemo, useCallback } from 'react';
import { FormGroup, FieldLabel, DatePickerField } from 'sana/forms';
import { useSimpleTexts } from 'sana/texts';

type Settings = {
  availabilityInDays: number;
  notAvailableDates: string[] | null;
};

const DeliveryDateEditor: TemplateFieldEditor<Settings> = ({
  fieldName,
  fieldTitle,
  description,
  settings,
  initialValue,
  disabled,
  required,
  validation,
}) => {
  const { texts: [validationDateIsNotAvailableMessage] } = useSimpleTexts(['ValidationDateIsNotAvailable']);
  const minDate = useMemo(() => {
    const date = new Date();
    date.setHours(0, 0, 0, 0);
    date.setDate(date.getDate() + settings.availabilityInDays);

    return date;
  }, [settings.availabilityInDays]);

  const deliveryDateValidation = useMemo(() => {
    if (!validationDateIsNotAvailableMessage || !settings.notAvailableDates?.length)
      return validation;

    const notAvailableDates = settings.notAvailableDates.map(s => getDateHash(new Date(s)));

    return {
      ...validation,
      custom(value: any) {
        if (validation.custom) {
          const validationResult = validation.custom(value);
          if (validationResult !== undefined)
            return validationResult;
        }

        if (!value)
          return;

        const hash = getDateHash(new Date(value));
        return notAvailableDates.includes(hash) ? validationDateIsNotAvailableMessage : undefined;
      },
    };
  }, [validation, validationDateIsNotAvailableMessage, settings.notAvailableDates]);

  const isDateAvailable = useCallback((date: Date) => deliveryDateValidation.custom!(date) === undefined, [deliveryDateValidation]);

  const label = (
    <FieldLabel
      fieldName={fieldName}
      required={required}
      focusToFieldOnClick
    >
      {fieldTitle}
    </FieldLabel>
  );
  const field = (
    <DatePickerField
      fieldName={fieldName}
      fieldTitle={fieldTitle}
      initialValue={initialValue}
      required={required}
      disabled={disabled}
      minDate={minDate}
      validation={deliveryDateValidation}
      isDateAvailable={isDateAvailable}
    />
  );

  return (
    <FormGroup
      label={label}
      field={field}
      description={description}
    />
  );
};

export default DeliveryDateEditor;

function getDateHash(date: Date) {
  const year = date.getFullYear();
  const month = date.getMonth() + 1;
  const day = date.getDate();

  return `${year}-${month}-${day}`;
}

ReadOnlyTemplateFieldEditor component

The ReadOnlyTemplateFieldEditor is react component to display template field read only value. It expects the properties of ReadOnlyTemplateFieldEditorProps<S = any> type where S is the type of editor settings.

The ReadOnlyTemplateFieldEditorProps<S = any> type contains the following properties:

Property Type Description
fieldName string The field form name.
fieldTitle string The field title.
description string | null The field description.
settings S = any The editor settings.
value any The field value.
displayValue string | null The formatted field value.

Example:

import type { ReadOnlyTemplateFieldEditor } from 'sana/templateFields';
import { ReadOnlyFormGroup, FieldLabel } from 'sana/forms';
import { DateDisplay } from 'sana/elements';

type Settings = {
  longFormat: boolean;
};

const DeliveryDateDisplay: ReadOnlyTemplateFieldEditor<Settings> = ({
  fieldName,
  fieldTitle,
  description,
  settings,
  value,
}) => {
  const field = <DateDisplay value={value} longFormat={settings.longFormat} />;
  const label = <FieldLabel fieldName={fieldName}>{fieldTitle}</FieldLabel>;

  return (
    <ReadOnlyFormGroup
      label={label}
      field={field}
      description={description}
    />
  );
};

export default DeliveryDateDisplay;

See also