diff --git a/src/components/DataTableCells/SwitchFieldCell.js b/src/components/DataTableCells/SwitchFieldCell.js new file mode 100644 index 000000000..0e9635439 --- /dev/null +++ b/src/components/DataTableCells/SwitchFieldCell.js @@ -0,0 +1,43 @@ +import React from 'react'; +import classNames from 'classnames'; +import { get } from 'lodash'; +import { Classes, Switch, FormGroup, Intent } from '@blueprintjs/core'; + +const SwitchEditableCell = ({ + row: { index, original }, + column: { id, switchProps }, + cell: { value: initialValue }, + payload, +}) => { + const [value, setValue] = React.useState(initialValue); + + const onChange = (e) => { + const newValue = e.target.checked; + + setValue(newValue); + payload.updateData(index, id, newValue); + }; + + React.useEffect(() => { + setValue(initialValue); + }, [initialValue]); + + const error = payload.errors?.[index]?.[id]; + + return ( + + + + ); +}; +export default SwitchEditableCell; diff --git a/src/components/DataTableCells/TextAreaCell.js b/src/components/DataTableCells/TextAreaCell.js new file mode 100644 index 000000000..c8ff97a0c --- /dev/null +++ b/src/components/DataTableCells/TextAreaCell.js @@ -0,0 +1,42 @@ +import React, { useState, useEffect } from 'react'; +import classNames from 'classnames'; +import { Classes, TextArea, FormGroup, Intent } from '@blueprintjs/core'; + +const TextAreaEditableCell = ({ + row: { index }, + column: { id }, + cell: { value: initialValue }, + payload, +}) => { + const [value, setValue] = useState(initialValue); + + const onChange = (e) => { + setValue(e.target.value); + }; + const onBlur = () => { + payload.updateData(index, id, value); + }; + useEffect(() => { + setValue(initialValue); + }, [initialValue]); + + const error = payload.errors?.[index]?.[id]; + + return ( + + + + ); +}; + +export default TextAreaEditableCell; diff --git a/src/components/DataTableCells/index.js b/src/components/DataTableCells/index.js index 2a0688ad2..fed349eed 100644 --- a/src/components/DataTableCells/index.js +++ b/src/components/DataTableCells/index.js @@ -6,7 +6,9 @@ import ItemsListCell from './ItemsListCell'; import PercentFieldCell from './PercentFieldCell'; import { DivFieldCell, EmptyDiv } from './DivFieldCell'; import NumericInputCell from './NumericInputCell'; -import CheckBoxFieldCell from './CheckBoxFieldCell' +import CheckBoxFieldCell from './CheckBoxFieldCell'; +import SwitchFieldCell from './SwitchFieldCell'; +import TextAreaCell from './TextAreaCell'; export { AccountsListFieldCell, @@ -18,5 +20,7 @@ export { DivFieldCell, EmptyDiv, NumericInputCell, - CheckBoxFieldCell + CheckBoxFieldCell, + SwitchFieldCell, + TextAreaCell, }; diff --git a/src/config/preferencesMenu.js b/src/config/preferencesMenu.js index 3e1b981dd..56066043d 100644 --- a/src/config/preferencesMenu.js +++ b/src/config/preferencesMenu.js @@ -1,29 +1,34 @@ -import React from 'react' -import { FormattedMessage as T } from 'components'; +import React from 'react'; +import { FormattedMessage as T } from 'components'; export default [ { - text: , + text: , disabled: false, href: '/preferences/general', }, { - text: , + text: , href: '/preferences/users', }, { - text: , - + text: , + href: '/preferences/currencies', }, { - text: , + text: , disabled: false, href: '/preferences/accountant', }, { - text: , + text: , disabled: false, href: '/preferences/items', }, + { + text: , + disabled: false, + href: '/preferences/sms-message', + }, ]; diff --git a/src/containers/Preferences/SMSMessageTemplates/SMSMessageTemplateFloatingAction.js b/src/containers/Preferences/SMSMessageTemplates/SMSMessageTemplateFloatingAction.js new file mode 100644 index 000000000..e989d4dfc --- /dev/null +++ b/src/containers/Preferences/SMSMessageTemplates/SMSMessageTemplateFloatingAction.js @@ -0,0 +1,28 @@ +import React from 'react'; +import { useFormikContext } from 'formik'; + +import { Intent, Button, Classes } from '@blueprintjs/core'; +import { FormattedMessage as T } from 'components'; +import { useHistory } from 'react-router-dom'; + +function SMSMessageTemplateFloatingAction() { + const history = useHistory(); + const { isSubmitting } = useFormikContext(); + + const handleCloseClick = () => { + history.go(-1); + }; + + return ( + + + + + + + + + ); +} + +export default SMSMessageTemplateFloatingAction; diff --git a/src/containers/Preferences/SMSMessageTemplates/SMSMessageTemplateForm.js b/src/containers/Preferences/SMSMessageTemplates/SMSMessageTemplateForm.js new file mode 100644 index 000000000..ead8f137c --- /dev/null +++ b/src/containers/Preferences/SMSMessageTemplates/SMSMessageTemplateForm.js @@ -0,0 +1,46 @@ +import React from 'react'; +import { Formik, Form } from 'formik'; +import { Intent } from '@blueprintjs/core'; +import intl from 'react-intl-universal'; +import classNames from 'classnames'; +import { useHistory } from 'react-router-dom'; +import { CLASSES } from 'common/classes'; + +import { CreateSMSMessageTemplateSchema } from './SMSMessageTemplateForm.schema'; + +import SMSMessageTemplateFormContent from './SMSMessageTemplateFormContent'; + +export const defaultInitialValues = { + entries: [ + { + notification: '', + service: '', + message: '', + auto: true, + switch: true, + }, + ], +}; + +export default function SMSMessageTemplateForm({}) { + // Form initial values. + const initialValues = { + ...defaultInitialValues, + }; + + // Handles form submit. + const handleSubmit = (values, { setSubmitting, setErrors, resetForm }) => {}; + + return ( + + + + ); +} diff --git a/src/containers/Preferences/SMSMessageTemplates/SMSMessageTemplateForm.schema.js b/src/containers/Preferences/SMSMessageTemplates/SMSMessageTemplateForm.schema.js new file mode 100644 index 000000000..584e342e5 --- /dev/null +++ b/src/containers/Preferences/SMSMessageTemplates/SMSMessageTemplateForm.schema.js @@ -0,0 +1,19 @@ +import * as Yup from 'yup'; +import intl from 'react-intl-universal'; +import { DATATYPES_LENGTH } from 'common/dataTypes'; +import { isBlank } from 'utils'; + +const Schema = Yup.object().shape({ + + entries: Yup.array().of( + Yup.object().shape({ + notification: Yup.string().nullable(), + service: Yup.number().nullable(), + message: Yup.string().max(DATATYPES_LENGTH.TEXT).nullable(), + auto:Yup.boolean(), + switch:Yup.boolean(), + + }), + ), +}) +export const CreateSMSMessageTemplateSchema = Schema; diff --git a/src/containers/Preferences/SMSMessageTemplates/SMSMessageTemplateFormBody.js b/src/containers/Preferences/SMSMessageTemplates/SMSMessageTemplateFormBody.js new file mode 100644 index 000000000..90067fb43 --- /dev/null +++ b/src/containers/Preferences/SMSMessageTemplates/SMSMessageTemplateFormBody.js @@ -0,0 +1,23 @@ +import React from 'react'; +import { FastField } from 'formik'; + +import SMSMessageTemplatesEntriesTable from './SMSMessageTemplatesEntriesTable'; + +export default function SMSMessageTemplateFormBody() { + return ( + + {({ + form: { values, setFieldValue }, + field: { value }, + meta: { error, touched }, + }) => ( + { + setFieldValue('entries', newEntries); + }} + /> + )} + + ); +} diff --git a/src/containers/Preferences/SMSMessageTemplates/SMSMessageTemplateFormContent.js b/src/containers/Preferences/SMSMessageTemplates/SMSMessageTemplateFormContent.js new file mode 100644 index 000000000..217361a35 --- /dev/null +++ b/src/containers/Preferences/SMSMessageTemplates/SMSMessageTemplateFormContent.js @@ -0,0 +1,16 @@ +import React from 'react'; +import { Form } from 'formik'; +import classNames from 'classnames'; +import { CLASSES } from 'common/classes'; + +import SMSMessageTemplateFormBody from './SMSMessageTemplateFormBody'; +import SMSMessageTemplateFloatingAction from './SMSMessageTemplateFloatingAction'; + +export default function SMSMessageTemplateFormContent() { + return ( + + + + + ); +} diff --git a/src/containers/Preferences/SMSMessageTemplates/SMSMessageTemplateProvider.js b/src/containers/Preferences/SMSMessageTemplates/SMSMessageTemplateProvider.js new file mode 100644 index 000000000..b90df0a4e --- /dev/null +++ b/src/containers/Preferences/SMSMessageTemplates/SMSMessageTemplateProvider.js @@ -0,0 +1,42 @@ +import React from 'react'; +import classNames from 'classnames'; +import { CLASSES } from 'common/classes'; +import { useSettings, useSaveSettings } from 'hooks/query'; + +import PreferencesPageLoader from '../PreferencesPageLoader'; + +const SMSMessageTemplateContext = React.createContext(); + +/** + * SMS message template provider. + */ +function SMSMessageTemplateProvider({ ...props }) { + + //Fetches Organization Settings. + const { isLoading: isSettingsLoading } = useSettings(); + + // Provider state. + const provider = {}; + + return ( + + + {isSettingsLoading ? ( + + ) : ( + + )} + + + ); +} + +const useSMSMessageTemplateContext = () => + React.useContext(SMSMessageTemplateContext); + +export { SMSMessageTemplateProvider, useSMSMessageTemplateContext }; diff --git a/src/containers/Preferences/SMSMessageTemplates/SMSMessageTemplatesEntriesTable.js b/src/containers/Preferences/SMSMessageTemplates/SMSMessageTemplatesEntriesTable.js new file mode 100644 index 000000000..67ed04c43 --- /dev/null +++ b/src/containers/Preferences/SMSMessageTemplates/SMSMessageTemplatesEntriesTable.js @@ -0,0 +1,68 @@ +import React from 'react'; +import intl from 'react-intl-universal'; +import { + InputGroupCell, + TextAreaCell, + SwitchFieldCell, +} from 'components/DataTableCells'; +import { DataTableEditable } from 'components'; +import { compose, updateTableCell } from 'utils'; + +export default function SMSMessageTemplatesEntriesTable({ + onUpdateData, + entries, +}) { + const columns = React.useMemo(() => [ + { + Header: intl.get('sms_message_template.label_Notification'), + accessor: 'notification', + Cell: InputGroupCell, + disableSortBy: true, + width: '150', + }, + { + Header: intl.get('service'), + accessor: 'service', + Cell: InputGroupCell, + disableSortBy: true, + width: '150', + }, + { + Header: intl.get('sms_message_template.label_mesage'), + accessor: 'message', + // Cell: TextAreaCell, + Cell: InputGroupCell, + disableSortBy: true, + width: '150', + }, + { + Header: intl.get('sms_message_template.label_auto'), + accessor: 'auto', + Cell: SwitchFieldCell, + disableSortBy: true, + disableResizing: true, + width: '120', + }, + ]); + + const handleUpdateData = React.useCallback( + (rowIndex, columnId, value) => { + const newRows = compose(updateTableCell(rowIndex, columnId, value))( + entries, + ); + onUpdateData(newRows); + }, + [onUpdateData, entries], + ); + + return ( + + ); +} diff --git a/src/containers/Preferences/SMSMessageTemplates/index.js b/src/containers/Preferences/SMSMessageTemplates/index.js new file mode 100644 index 000000000..3a086ca9b --- /dev/null +++ b/src/containers/Preferences/SMSMessageTemplates/index.js @@ -0,0 +1,14 @@ +import React from 'react'; +import { SMSMessageTemplateProvider } from './SMSMessageTemplateProvider'; +import SMSMessageTemplateForm from './SMSMessageTemplateForm'; + +/** + * SMS message template. + */ +export default function SMSMessageTemplates() { + return ( + + + + ); +} diff --git a/src/lang/en/index.json b/src/lang/en/index.json index 058cfe230..a025575bd 100644 --- a/src/lang/en/index.json +++ b/src/lang/en/index.json @@ -1407,7 +1407,6 @@ "cash_flow_money_out": "Money Out", "cash_flow_transaction.switch_item": "Transactions {value}", "cash_flow_transaction.balance_in_bigcapital": "Balance in Bigcapital", - "AR_aging_summary.filter_customers.all_customers": "All customers", "AR_aging_summary.filter_customers.all_customers.hint": "All customers, include that ones have zero-balance.", "AR_aging_summary.filter_customers.without_zero_balance": "Customers without zero balance", @@ -1425,8 +1424,15 @@ "bad_debt.dialog.bad_debt": "Bad debt", "bad_debt.dialog.cancel_bad_debt": "Cancel bad debt", "bad_debt.dialog.header_note": "The seller can charge the amount of an invoice to the bad debt expense account when it is certain that the invoice will not be paid.", - "bad_debt.dialog.success_message":"The given sale invoice has been writte-off successfully.", - "bad_debt.cancel_alert.success_message":"The given sale invoice has been canceled write-off successfully.", - "bad_debt.cancel_alert.message": "Are you sure you want to write off this invoice?" - -} + "bad_debt.dialog.success_message": "The given sale invoice has been writte-off successfully.", + "bad_debt.cancel_alert.success_message": "The given sale invoice has been canceled write-off successfully.", + "bad_debt.cancel_alert.message": "Are you sure you want to write off this invoice?", + "notify_via_sms.dialog.send_notification_to":"Send notification to", + "notify_via_sms.dialog.message_text":"Message Text", + "notify_via_sms.dialog.notify_via_sms":"Notify vis SMS", + "send": "Send", + "sms_message_template.label_mesage":"Message", + "sms_message_template.label_Notification":"Notification", + "sms_message_template.label_auto":"Auto", + "sms_message":"SMS message" +} \ No newline at end of file diff --git a/src/routes/preferences.js b/src/routes/preferences.js index cc539a664..080b747c1 100644 --- a/src/routes/preferences.js +++ b/src/routes/preferences.js @@ -4,6 +4,7 @@ import Accountant from 'containers/Preferences/Accountant/Accountant'; // import Accounts from 'containers/Preferences/Accounts/Accounts'; import Currencies from 'containers/Preferences/Currencies/Currencies'; import Item from 'containers/Preferences/Item'; +import SMSMessageTemplates from '../containers/Preferences/SMSMessageTemplates'; import DefaultRoute from '../containers/Preferences/DefaultRoute'; const BASE_URL = '/preferences'; @@ -34,6 +35,11 @@ export default [ component: Item, exact: true, }, + { + path: `${BASE_URL}/sms-message`, + component: SMSMessageTemplates, + exact: true, + }, { path: `${BASE_URL}/`, component: DefaultRoute,