/*! * Copyright (c) 2024 PLANKA Software GmbH * Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md */ import { dequal } from 'dequal'; import omit from 'lodash/omit'; import React, { useCallback, useMemo, useRef } from 'react'; import classNames from 'classnames'; import { useDispatch, useSelector } from 'react-redux'; import { useTranslation } from 'react-i18next'; import TextareaAutosize from 'react-textarea-autosize'; import { Button, Checkbox, Divider, Form, Header, Tab, TextArea } from 'semantic-ui-react'; import { Input } from '../../../lib/custom-ui'; import selectors from '../../../selectors'; import entryActions from '../../../entry-actions'; import { useForm, useNestedRef } from '../../../hooks'; import styles from './SmtpPane.module.scss'; const SmtpPane = React.memo(() => { const config = useSelector(selectors.selectConfig); const smtpTestState = useSelector(selectors.selectSmtpTestState); const dispatch = useDispatch(); const [t] = useTranslation(); const [passwordFieldRef, handlePasswordFieldRef] = useNestedRef('inputRef'); const isPasswordTouchedRef = useRef(false); const defaultData = useMemo( () => ({ smtpHost: config.smtpHost, smtpPort: config.smtpPort, smtpName: config.smtpName, smtpSecure: config.smtpSecure, smtpTlsRejectUnauthorized: config.smtpTlsRejectUnauthorized, smtpUser: config.smtpUser, smtpPassword: config.smtpPassword, smtpFrom: config.smtpFrom, }), [config], ); const [data, handleFieldChange] = useForm(() => ({ ...defaultData, smtpHost: defaultData.smtpHost || '', smtpPort: defaultData.smtpPort === null ? '' : `${defaultData.smtpPort}`, smtpName: defaultData.smtpName || '', smtpSecure: defaultData.smtpSecure, smtpTlsRejectUnauthorized: defaultData.smtpTlsRejectUnauthorized, smtpUser: defaultData.smtpUser || '', smtpPassword: defaultData.smtpPassword || '', smtpFrom: defaultData.smtpFrom || '', })); const isPasswordSet = defaultData.smtpPassword === undefined; const cleanData = useMemo( () => ({ ...data, smtpHost: data.smtpHost.trim() || null, smtpPort: parseInt(data.smtpPort, 10) || null, smtpName: data.smtpName.trim() || null, smtpUser: data.smtpUser.trim() || null, smtpPassword: data.smtpPassword || (isPasswordSet ? undefined : null), smtpFrom: data.smtpFrom.trim() || null, }), [data, isPasswordSet], ); const isModified = useMemo(() => { const cleanDataToCheck = omit(cleanData, 'smtpPassword'); const defaultDataToCheck = omit(defaultData, 'smtpPassword'); return !dequal(cleanDataToCheck, defaultDataToCheck) || isPasswordTouchedRef.current; }, [defaultData, cleanData]); const handleSubmit = useCallback(() => { isPasswordTouchedRef.current = false; dispatch(entryActions.updateConfig(cleanData)); }, [dispatch, cleanData]); const handlePasswordClear = useCallback(() => { dispatch( entryActions.updateConfig({ smtpPassword: null, }), ); passwordFieldRef.current.focus(); }, [dispatch, passwordFieldRef]); const handleTestClick = useCallback(() => { dispatch(entryActions.testSmtpConfig()); }, [dispatch]); const handlePasswordChange = useCallback( (event, { value, ...props }) => { isPasswordTouchedRef.current = value !== ''; handleFieldChange(event, { value, ...props }); }, [handleFieldChange], ); return (
{t('common.host')}
{t('common.port')}
{t('common.clientHostnameInEhlo')} ( {t('common.optional', { context: 'inline', })} )
{t('common.username')} ( {t('common.optional', { context: 'inline', })} )
{t('common.password')} ( {t('common.optional', { context: 'inline', })} )
{t('common.defaultFrom')} ( {t('common.optional', { context: 'inline', })} )
{smtpTestState.logs && ( <>
{t('common.testLog', { context: 'title', })}