diff --git a/src/components/DialogsContainer.js b/src/components/DialogsContainer.js index 6f42dff69..db9f883c2 100644 --- a/src/components/DialogsContainer.js +++ b/src/components/DialogsContainer.js @@ -50,10 +50,12 @@ export default function DialogsContainer() { + + diff --git a/src/components/SMSPreview/index.js b/src/components/SMSPreview/index.js new file mode 100644 index 000000000..907d8274b --- /dev/null +++ b/src/components/SMSPreview/index.js @@ -0,0 +1,46 @@ +import React from 'react'; +import styled from 'styled-components'; + +import { Icon } from 'components'; + +/** + * SMS Message preview. + */ +export function SMSMessagePreview({ + message, + iconWidth = '265px', + iconHeight = '287px', + iconColor = '#adadad', +}) { + return ( + + + {message} + + ); +} + +const SMSMessageText = styled.div` + position: absolute; + top: 61px; + padding: 12px; + color: #fff; + border-radius: 12px; + margin-left: 12px; + margin-right: 12px; + overflow-wrap: break-word; + background: #2fa2e4; + font-size: 13px; + line-height: 1.6; +`; + +const SMSMessagePreviewBase = styled.div` + position: relative; + width: 265px; + margin: 0 auto; +`; diff --git a/src/components/index.js b/src/components/index.js index 8d38aefcf..ee698b70c 100644 --- a/src/components/index.js +++ b/src/components/index.js @@ -87,6 +87,7 @@ export * from './IntersectionObserver'; export * from './Datatable/CellForceWidth'; export * from './Button'; export * from './IntersectionObserver'; +export * from './SMSPreview'; const Hint = FieldHint; diff --git a/src/containers/Dialogs/NotifyEstimateViaSMSDialog/NotifyEstimateViaSMSForm.js b/src/containers/Dialogs/NotifyEstimateViaSMSDialog/NotifyEstimateViaSMSForm.js index e4eb9fea4..acbef5440 100644 --- a/src/containers/Dialogs/NotifyEstimateViaSMSDialog/NotifyEstimateViaSMSForm.js +++ b/src/containers/Dialogs/NotifyEstimateViaSMSDialog/NotifyEstimateViaSMSForm.js @@ -24,6 +24,8 @@ function NotifyEstimateViaSMSForm({ // Handles the form submit. const handleFormSubmit = (values, { setSubmitting, setErrors }) => { + setSubmitting(true); + // Handle request response success. const onSuccess = (response) => { AppToaster.show({ @@ -31,8 +33,8 @@ function NotifyEstimateViaSMSForm({ intent: Intent.SUCCESS, }); closeDialog(dialogName); + setSubmitting(false); }; - // Handle request response errors. const onError = ({ response: { @@ -40,6 +42,7 @@ function NotifyEstimateViaSMSForm({ }, }) => { transformErrors(errors); + setSubmitting(false); }; createNotifyEstimateBySMSMutate([estimateId, values]) .then(onSuccess) diff --git a/src/containers/Dialogs/NotifyInvoiceViaSMSDialog/NotifyInvoiceViaSMSForm.js b/src/containers/Dialogs/NotifyInvoiceViaSMSDialog/NotifyInvoiceViaSMSForm.js index f3de4151f..ba1649ed4 100644 --- a/src/containers/Dialogs/NotifyInvoiceViaSMSDialog/NotifyInvoiceViaSMSForm.js +++ b/src/containers/Dialogs/NotifyInvoiceViaSMSDialog/NotifyInvoiceViaSMSForm.js @@ -11,6 +11,12 @@ import { transformErrors } from '../../../containers/NotifyViaSMS/utils'; import withDialogActions from 'containers/Dialog/withDialogActions'; import { compose } from 'utils'; +const transformFormValuesToRequest = (values) => { + return { + notification_type: values.notification_key, + }; +}; + /** * Notify Invoice Via SMS Form. */ @@ -23,16 +29,21 @@ function NotifyInvoiceViaSMSForm({ invoiceId, invoiceSMSDetail, dialogName, + notificationType, + setNotificationType, } = useNotifyInvoiceViaSMSContext(); // Handles the form submit. const handleFormSubmit = (values, { setSubmitting, setErrors }) => { + setSubmitting(true); + // Handle request response success. const onSuccess = (response) => { AppToaster.show({ message: intl.get('notify_via_sms.dialog.success_message'), intent: Intent.SUCCESS, }); + setSubmitting(false); closeDialog(dialogName); }; @@ -43,17 +54,37 @@ function NotifyInvoiceViaSMSForm({ }, }) => { transformErrors(errors); + setSubmitting(false); }; - createNotifyInvoiceBySMSMutate([invoiceId, values]) + // Transformes the form values to request. + const requestValues = transformFormValuesToRequest(values); + + createNotifyInvoiceBySMSMutate([invoiceId, requestValues]) .then(onSuccess) .catch(onError); }; + // Handle the form cancel. + const handleFormCancel = React.useCallback(() => { + closeDialog(dialogName); + }, [closeDialog, dialogName]); + + const initialValues = { + notification_key: notificationType, + ...invoiceSMSDetail, + }; + + const handleValuesChange = (values) => { + if (values.notification_key !== notificationType) { + setNotificationType(values.notification_key); + } + }; return ( ); } diff --git a/src/containers/Dialogs/NotifyInvoiceViaSMSDialog/NotifyInvoiceViaSMSFormProvider.js b/src/containers/Dialogs/NotifyInvoiceViaSMSDialog/NotifyInvoiceViaSMSFormProvider.js index 26faac775..c052dc274 100644 --- a/src/containers/Dialogs/NotifyInvoiceViaSMSDialog/NotifyInvoiceViaSMSFormProvider.js +++ b/src/containers/Dialogs/NotifyInvoiceViaSMSDialog/NotifyInvoiceViaSMSFormProvider.js @@ -5,11 +5,19 @@ import { useCreateNotifyInvoiceBySMS, useInvoiceSMSDetail } from 'hooks/query'; const NotifyInvoiceViaSMSContext = React.createContext(); function NotifyInvoiceViaSMSFormProvider({ invoiceId, dialogName, ...props }) { - const { data: invoiceSMSDetail, isLoading: isInvoiceSMSDetailLoading } = - useInvoiceSMSDetail(invoiceId, { - enabled: !!invoiceId, - }); + const [notificationType, setNotificationType] = React.useState('details'); + // Retrieve the invoice sms notification message details. + const { data: invoiceSMSDetail, isLoading: isInvoiceSMSDetailLoading } = + useInvoiceSMSDetail( + invoiceId, + { + notification_type: notificationType, + }, + { + enabled: !!invoiceId, + }, + ); // Create notfiy invoice by sms mutations. const { mutateAsync: createNotifyInvoiceBySMSMutate } = useCreateNotifyInvoiceBySMS(); @@ -20,6 +28,9 @@ function NotifyInvoiceViaSMSFormProvider({ invoiceId, dialogName, ...props }) { invoiceSMSDetail, dialogName, createNotifyInvoiceBySMSMutate, + + notificationType, + setNotificationType, }; return ( diff --git a/src/containers/Dialogs/NotifyInvoiceViaSMSDialog/index.js b/src/containers/Dialogs/NotifyInvoiceViaSMSDialog/index.js index 19ae087b8..8951788cf 100644 --- a/src/containers/Dialogs/NotifyInvoiceViaSMSDialog/index.js +++ b/src/containers/Dialogs/NotifyInvoiceViaSMSDialog/index.js @@ -32,4 +32,5 @@ function NotifyInvoiceViaSMSDialog({ ); } + export default compose(withDialogRedux())(NotifyInvoiceViaSMSDialog); diff --git a/src/containers/Dialogs/SMSMessageDialog/SMSMessageForm.js b/src/containers/Dialogs/SMSMessageDialog/SMSMessageForm.js index 3a98f36a6..2fdac2b75 100644 --- a/src/containers/Dialogs/SMSMessageDialog/SMSMessageForm.js +++ b/src/containers/Dialogs/SMSMessageDialog/SMSMessageForm.js @@ -44,7 +44,6 @@ function SMSMessageForm({ ...omit(values, ['is_notification_enabled', 'sms_message']), notification_key: smsNotification.key, }; - // Handle request response success. const onSuccess = (response) => { AppToaster.show({ @@ -53,7 +52,6 @@ function SMSMessageForm({ }); closeDialog(dialogName); }; - // Handle request response errors. const onError = ({ response: { @@ -62,7 +60,7 @@ function SMSMessageForm({ }) => { setSubmitting(false); }; - + debugger; editSMSNotificationMutate(form).then(onSuccess).catch(onError); }; diff --git a/src/containers/Dialogs/SMSMessageDialog/SMSMessageFormContent.js b/src/containers/Dialogs/SMSMessageDialog/SMSMessageFormContent.js index 52c417b24..2d1890208 100644 --- a/src/containers/Dialogs/SMSMessageDialog/SMSMessageFormContent.js +++ b/src/containers/Dialogs/SMSMessageDialog/SMSMessageFormContent.js @@ -1,17 +1,103 @@ import React from 'react'; -import { Form } from 'formik'; +import { Form, useFormikContext } from 'formik'; +import styled from 'styled-components'; +import { Classes } from '@blueprintjs/core'; import SMSMessageFormFields from './SMSMessageFormFields'; import SMSMessageFormFloatingActions from './SMSMessageFormFloatingActions'; +import { SMSMessagePreview } from 'components'; +import { getSMSUnits } from '../../NotifyViaSMS/utils'; + +const messageVariables = [ + { + variable: '{CompanyName}', + description: 'References to the current company name.', + }, +]; + /** * SMS message form content. */ export default function SMSMessageFormContent() { return (
- +
+ + + + + + {messageVariables.map(({ variable, description }) => ( + + {variable} {description} + + ))} + + + + + + + +
); } + +/** + * SMS Message preview section. + * @returns {JSX} + */ +function SMSMessagePreviewSection() { + const { + values: { message_text: message }, + } = useFormikContext(); + + const messagesUnits = getSMSUnits(message); + + return ( + + + + + Note: Note: One SMS unit can contain a maximum of 160 + characters. {messagesUnits} SMS units will be used to + send this SMS notification. + + + ); +} + +const SMSPreviewSectionRoot = styled.div``; + +const SMSPreviewSectionNote = styled.div` + font-size: 12px; + opacity: 0.7; +`; + +const SMSMessageVariables = styled.div` + list-style: none; + font-size: 12px; + opacity: 0.9; +`; + +const MessageVariable = styled.div` + margin-bottom: 8px; +`; + +const FormContent = styled.div` + display: flex; +`; +const FormFields = styled.div` + width: 55%; +`; +const FormPreview = styled.div` + display: flex; + flex-direction: column; + width: 45%; + padding-left: 25px; + margin-left: 25px; + border-left: 1px solid #dcdcdd; +`; diff --git a/src/containers/Dialogs/SMSMessageDialog/SMSMessageFormFields.js b/src/containers/Dialogs/SMSMessageDialog/SMSMessageFormFields.js index fd4c54c0c..6fd2e79b5 100644 --- a/src/containers/Dialogs/SMSMessageDialog/SMSMessageFormFields.js +++ b/src/containers/Dialogs/SMSMessageDialog/SMSMessageFormFields.js @@ -7,7 +7,7 @@ import { inputIntent } from 'utils'; export default function SMSMessageFormFields() { return ( -
+
{/* ----------- Message Text ----------- */} {({ field, meta: { error, touched } }) => ( diff --git a/src/containers/Dialogs/SMSMessageDialog/SMSMessageFormFloatingActions.js b/src/containers/Dialogs/SMSMessageDialog/SMSMessageFormFloatingActions.js index efa1a090a..d7eabc30e 100644 --- a/src/containers/Dialogs/SMSMessageDialog/SMSMessageFormFloatingActions.js +++ b/src/containers/Dialogs/SMSMessageDialog/SMSMessageFormFloatingActions.js @@ -1,6 +1,8 @@ import React from 'react'; import { Intent, Button, Classes } from '@blueprintjs/core'; import { useFormikContext } from 'formik'; +import styled from 'styled-components'; + import { FormattedMessage as T } from 'components'; import { useSMSMessageDialogContext } from './SMSMessageDialogProvider'; @@ -27,7 +29,7 @@ function SMSMessageFormFloatingActions({ return (
-
+ @@ -37,11 +39,15 @@ function SMSMessageFormFloatingActions({ style={{ minWidth: '75px' }} type="submit" > - {} + Save SMS Message -
+
); } export default compose(withDialogActions)(SMSMessageFormFloatingActions); + +const FooterActions = styled.div` + justify-content: flex-start; +`; diff --git a/src/containers/NotifyViaSMS/NotifyViaSMSForm.js b/src/containers/NotifyViaSMS/NotifyViaSMSForm.js index 93eb57375..a6f60ad1f 100644 --- a/src/containers/NotifyViaSMS/NotifyViaSMSForm.js +++ b/src/containers/NotifyViaSMS/NotifyViaSMSForm.js @@ -1,28 +1,62 @@ import React from 'react'; -import { Formik, Form } from 'formik'; +import { Formik, Form, useFormikContext } from 'formik'; +import styled from 'styled-components'; +import { Classes } from '@blueprintjs/core'; import 'style/pages/NotifyConactViaSMS/NotifyConactViaSMSDialog.scss'; import { CreateNotifyViaSMSFormSchema } from './NotifyViaSMSForm.schema'; import NotifyViaSMSFormFields from './NotifyViaSMSFormFields'; import NotifyViaSMSFormFloatingActions from './NotifyViaSMSFormFloatingActions'; +import { FormObserver, SMSMessagePreview } from 'components'; -import { transformToForm, saveInvoke } from 'utils'; +import { transformToForm, safeInvoke } from 'utils'; +import { getSMSUnits } from './utils'; const defaultInitialValues = { + notification_key: '', customer_name: '', customer_phone_number: '', sms_message: '', }; +/** + * Notify via sms - SMS message preview section. + */ +function SMSMessagePreviewSection() { + const { + values: { sms_message }, + } = useFormikContext(); + + // Calculates the SMS units of message. + const messagesUnits = getSMSUnits(sms_message); + + return ( + + + + + Note: Note: One SMS unit can contain a maximum of 160 + characters. {messagesUnits} SMS units will be used to + send this SMS notification. + + + ); +} + /** * Notify Via SMS Form. */ -function NotifyViaSMSForm({ onSubmit, NotificationDetail, NotificationName }) { +function NotifyViaSMSForm({ + initialValues: initialValuesComponent, + onSubmit, + onCancel, + onValuesChange, +}) { // Initial form values const initialValues = { ...defaultInitialValues, - ...transformToForm(NotificationDetail, defaultInitialValues), + ...transformToForm(initialValuesComponent, defaultInitialValues), }; return ( @@ -32,11 +66,56 @@ function NotifyViaSMSForm({ onSubmit, NotificationDetail, NotificationName }) { onSubmit={onSubmit} >
- - +
+ + + + + + +
+ + + ); } +/** + * Observes the values change of notify form. + */ +function NotifyObserveValuesChange({ onChange }) { + const { values } = useFormikContext(); + + // Handle the form change observe. + const handleChange = () => { + safeInvoke(onChange, values); + }; + return ; +} + export default NotifyViaSMSForm; + +const NotifyContent = styled.div` + display: flex; +`; + +const NotifyFieldsSection = styled.div` + flex: 1; + width: 65%; +`; + +const SMSPreviewSectionRoot = styled.div` + display: flex; + flex-direction: column; + width: 45%; + padding-left: 25px; + margin-left: 25px; + border-left: 1px solid #dcdcdd; +`; + +const SMSPreviewSectionNote = styled.div` + font-size: 12px; + opacity: 0.7; +`; diff --git a/src/containers/NotifyViaSMS/NotifyViaSMSFormFields.js b/src/containers/NotifyViaSMS/NotifyViaSMSFormFields.js index 37c88c1e7..65b2058d2 100644 --- a/src/containers/NotifyViaSMS/NotifyViaSMSFormFields.js +++ b/src/containers/NotifyViaSMS/NotifyViaSMSFormFields.js @@ -1,16 +1,47 @@ import React from 'react'; import { FastField, ErrorMessage } from 'formik'; -import { FormattedMessage as T } from 'components'; - -import { Classes, FormGroup, TextArea, InputGroup } from '@blueprintjs/core'; +import { FormGroup, InputGroup } from '@blueprintjs/core'; import classNames from 'classnames'; + +import { + ListSelect, + FieldRequiredHint, + FormattedMessage as T, +} from 'components'; import { CLASSES } from 'common/classes'; import { inputIntent } from 'utils'; -import { FieldRequiredHint } from 'components'; -function NotifyViaSMSFormFields() { +const notificationTypes = [ + { key: 'details', label: 'Invoice details' }, + { key: 'reminder', label: 'Invoice reminder' }, +]; + +export default function NotifyViaSMSFormFields() { return ( -
+
+ + {({ form, meta: { error, touched } }) => ( + } + > + { + form.setFieldValue('notification_key', notification.key); + }} + /> + + )} + + {/* ----------- Send Notification to ----------- */} {({ form, field, meta: { error, touched } }) => ( @@ -51,29 +82,6 @@ function NotifyViaSMSFormFields() { )} - - {/* ----------- Message Text ----------- */} - - {({ field, meta: { error, touched } }) => ( - } - labelInfo={} - className={'form-group--sms_message'} - intent={inputIntent({ error, touched })} - helperText={} - > -