validate: copyLengthValidator()

in public/src/components/channelManagement/supportLandingPage/productsEditor.tsx [118:247]


            validate: copyLengthValidator(30),
          })}
          error={!!errors.label?.copy}
          helperText={errors?.label?.copy?.message}
          label="Pill (optional)"
          name="label.copy"
          onBlur={handleSubmit(onProductChange)}
          disabled={!editMode}
          fullWidth
        />

        <div className={classes.benefitsHeading}>{buildBenefitsHeading(productKey)}</div>

        {benefits.map((benefit, index) => (
          <Grid container columns={9} spacing={1} key={benefit.id}>
            <Grid item xs={3}>
              <TextField
                label="Benefit Copy"
                required={true}
                name={`benefits[${index}].copy`}
                inputRef={register({
                  required: EMPTY_ERROR_HELPER_TEXT,
                  validate: copyLengthValidator(116),
                })}
                error={!!errors.benefits?.[index]?.copy}
                helperText={errors.benefits?.[index]?.copy?.message}
                defaultValue={benefit.copy}
                onBlur={handleSubmit(onProductChange)}
                disabled={!editMode}
                fullWidth
              />
            </Grid>
            <Grid item xs={3}>
              <TextField
                label="Tooltip (optional)"
                name={`benefits[${index}].tooltip`}
                inputRef={register()}
                error={!!errors.benefits?.[index]?.tooltip}
                defaultValue={benefit.tooltip}
                onBlur={handleSubmit(onProductChange)}
                disabled={!editMode}
                fullWidth
              />
            </Grid>
            <Grid item xs={2}>
              <TextField
                label="Pill (optional)"
                name={`benefits[${index}].label.copy`}
                inputRef={register()}
                error={!!errors.benefits?.[index]?.label?.copy}
                defaultValue={benefit.label?.copy}
                onBlur={handleSubmit(onProductChange)}
                disabled={!editMode}
                fullWidth
              />
            </Grid>
            <Grid item xs={1}>
              <Button
                className={classes.deleteButton}
                onClick={() => {
                  remove(index);
                  onProductChange({
                    ...product,
                    benefits: product.benefits.filter((_, i) => i !== index),
                  });
                }}
                disabled={!editMode}
                variant="outlined"
                size="medium"
              >
                <CloseIcon />
              </Button>
            </Grid>
          </Grid>
        ))}
        <Button
          onClick={() => append({ copy: '' })}
          disabled={!editMode || benefits.length >= 8}
          variant="outlined"
          size="medium"
        >
          <AddIcon />
        </Button>
      </AccordionDetails>
    </Accordion>
  );
};

interface ProductsEditorProps {
  products: Products;
  onProductsChange: (updatedProducts: Products) => void;
  onValidationChange: (isValid: boolean) => void;
  editMode: boolean;
}

export const ProductsEditor: React.FC<ProductsEditorProps> = ({
  products,
  onProductsChange,
  onValidationChange,
  editMode,
}) => {
  const classes = useStyles();

  // Validation for all 3 products
  const { control, setError, clearErrors, errors, reset } = useForm<Products>({
    mode: 'onChange',
    defaultValues: products,
  });

  useEffect(() => {
    const isValid = Object.keys(errors).length === 0;
    onValidationChange(isValid);
  }, [errors.Contribution, errors.SupporterPlus, errors.TierThree]);

  useEffect(() => {
    reset(products);
  }, [products, reset]);

  return (
    <div>
      <Typography className={classes.heading} variant="h5">
        Products
      </Typography>

      {productKeys.map(productKey => (
        <Controller
          key={productKey}
          control={control}
          name={productKey}
          render={field => (