3 * Copyright (C) 2009-2024 SonarSource SA
4 * mailto:info AT sonarsource DOT com
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 3 of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
27 } from '@sonarsource/echoes-react';
28 import { FormField, InputField, TextError } from 'design-system/lib';
29 import { isEmpty, isUndefined } from 'lodash';
30 import React, { useEffect } from 'react';
31 import isEmail from 'validator/lib/isEmail';
32 import { translate, translateWithParameters } from '../../../../helpers/l10n';
34 type InputType = 'email' | 'number' | 'password' | 'select' | 'text';
37 children?: (props: { onChange: (value: string) => void }) => React.ReactNode;
38 description: React.ReactNode;
42 onChange: (value: string | undefined) => void;
45 requiresRevaluation?: boolean;
47 value: string | undefined;
50 export function EmailNotificationFormField(props: Readonly<Props>) {
63 const [validationMessage, setValidationMessage] = React.useState<string>();
65 const handleCheck = (changedValue: string | undefined) => {
66 if (changedValue !== undefined && isEmpty(changedValue) && required) {
67 setValidationMessage(translate('settings.state.value_cant_be_empty_no_default'));
71 if (type === 'email' && !isEmail(changedValue ?? '')) {
72 setValidationMessage(translate('email_notification.state.value_should_be_valid_email'));
76 setValidationMessage(undefined);
80 const onChange = (newValue: string | undefined) => {
81 handleCheck(newValue);
82 props.onChange(newValue);
85 const hasValidationMessage = !isUndefined(validationMessage);
89 className="sw-grid sw-grid-cols-2 sw-gap-x-4 sw-py-6 sw-px-4"
91 label={translate(name)}
93 requiredAriaLabel={translate('field_required')}
95 <div className="sw-row-span-2 sw-grid">
100 options={options ?? []}
103 requiresRevaluation={requiresRevaluation}
108 {hasValidationMessage && (
111 text={translateWithParameters('settings.state.validation_failed', validationMessage)}
116 <div className="sw-w-abs-300">
117 {!isUndefined(description) && <div className="markdown sw-mt-1">{description}</div>}
125 hasValue: boolean | undefined;
128 onChange: (value: string | undefined) => void;
131 requiresRevaluation?: boolean;
133 value: string | undefined;
136 const { type } = props;
139 return <PasswordInput {...props} />;
141 return <SelectInput {...props} />;
143 return <BasicInput {...props} />;
149 hasValue: boolean | undefined;
152 onChange: (value: string) => void;
155 value: string | undefined;
158 const { hasValue, id, onChange, name, required, type, value } = props;
163 min={type === 'number' ? 0 : undefined}
165 onChange={(event) => onChange(event.target.value)}
167 type === 'password' && hasValue ? translate('email_notification.form.private') : undefined
171 step={type === 'number' ? 1 : undefined}
178 function PasswordInput(
180 hasValue: boolean | undefined;
183 onChange: (value: string | undefined) => void;
185 requiresRevaluation?: boolean;
186 value: string | undefined;
189 const { hasValue, id, onChange, name, required, requiresRevaluation, value } = props;
190 const [isEditing, setIsEditing] = React.useState<boolean>(requiresRevaluation === true);
193 if (!requiresRevaluation) {
194 setIsEditing(!hasValue);
196 }, [hasValue, requiresRevaluation]);
199 <div className="sw-flex">
201 disabled={!isEditing && !requiresRevaluation}
204 onChange={(event) => onChange(event.target.value)}
205 required={isEditing && required}
209 hasValue && !isEditing && !requiresRevaluation
210 ? translate('email_notification.form.private')
214 {!requiresRevaluation && (
216 ariaLabel={isEditing ? translate('reset_verb') : translate('edit')}
217 data-testid={`${name}-${isEditing ? 'reset' : 'edit'}`}
219 Icon={isEditing ? IconDelete : IconEdit}
224 setIsEditing(!isEditing);
226 variety={ButtonVariety.Default}
233 function SelectInput(
237 onChange: (value: string) => void;
240 value: string | undefined;
243 const { id, name, onChange, options, required, value } = props;
247 data={options?.map((option) => ({ label: option, value: option })) ?? []}
250 isRequired={required}
253 size={InputSize.Large}