diff --git a/src/common/classes.js b/src/common/classes.js
index 6b0872396..d58ecc6f5 100644
--- a/src/common/classes.js
+++ b/src/common/classes.js
@@ -70,6 +70,7 @@ const CLASSES = {
PREFERENCES_PAGE_INSIDE_CONTENT_ACCOUNTANT: 'preferences-page__inside-content--accountant',
PREFERENCES_PAGE_INSIDE_CONTENT_SMS_INTEGRATION: 'preferences-page__inside-content--sms-integration',
PREFERENCES_PAGE_INSIDE_CONTENT_ROLES_FORM: 'preferences-page__inside-content--roles-form',
+ PREFERENCES_PAGE_INSIDE_CONTENT_BRANCHES: 'preferences-page__inside-content--branches',
FINANCIAL_REPORT_INSIDER: 'dashboard__insider--financial-report',
diff --git a/src/components/DialogsContainer.js b/src/components/DialogsContainer.js
index cd8eb745e..204b40264 100644
--- a/src/components/DialogsContainer.js
+++ b/src/components/DialogsContainer.js
@@ -34,6 +34,7 @@ import UnlockingTransactionsDialog from '../containers/Dialogs/UnlockingTransact
import UnlockingPartialTransactionsDialog from '../containers/Dialogs/UnlockingPartialTransactionsDialog';
import CreditNotePdfPreviewDialog from '../containers/Dialogs/CreditNotePdfPreviewDialog';
import PaymentReceivePdfPreviewDialog from '../containers/Dialogs/PaymentReceivePdfPreviewDialog';
+import BranchFormDialog from '../containers/Dialogs/BranchFormDialog';
/**
* Dialogs container.
@@ -78,6 +79,7 @@ export default function DialogsContainer() {
/>
+
);
}
diff --git a/src/components/Preferences/PreferencesTopbar.js b/src/components/Preferences/PreferencesTopbar.js
index 1633ecc8f..41ed14894 100644
--- a/src/components/Preferences/PreferencesTopbar.js
+++ b/src/components/Preferences/PreferencesTopbar.js
@@ -6,6 +6,7 @@ import { CLASSES } from 'common/classes';
import DashboardTopbarUser from 'components/Dashboard/TopbarUser';
import UsersActions from 'containers/Preferences/Users/UsersActions';
import CurrenciesActions from 'containers/Preferences/Currencies/CurrenciesActions';
+import BranchesActions from '../../containers/Preferences/Branches/BranchesActions';
import withDashboard from 'containers/Dashboard/withDashboard';
import { compose } from 'utils';
@@ -35,6 +36,11 @@ function PreferencesTopbar({ preferencesPageTitle }) {
path={'/preferences/currencies'}
component={CurrenciesActions}
/>
+
diff --git a/src/config/preferencesMenu.js b/src/config/preferencesMenu.js
index 031dfe0e1..b42ce876a 100644
--- a/src/config/preferencesMenu.js
+++ b/src/config/preferencesMenu.js
@@ -13,9 +13,12 @@ export default [
},
{
text: ,
-
href: '/preferences/currencies',
},
+ {
+ text: ,
+ href: '/preferences/branches',
+ },
{
text: ,
disabled: false,
diff --git a/src/containers/Dialogs/BranchFormDialog/BranchForm.js b/src/containers/Dialogs/BranchFormDialog/BranchForm.js
new file mode 100644
index 000000000..99f41f76e
--- /dev/null
+++ b/src/containers/Dialogs/BranchFormDialog/BranchForm.js
@@ -0,0 +1,45 @@
+import React from 'react';
+import { Formik } from 'formik';
+
+import { AppToaster } from 'components';
+import { CreateBranchFormSchema } from './BranchForm.schema';
+
+import BranchFormContent from './BranchFormContent';
+import { useBranchFormContext } from './BranchFormProvider';
+
+import withDialogActions from 'containers/Dialog/withDialogActions';
+import { compose } from 'utils';
+
+const defaultInitialValues = {
+ branch_name: '',
+ branch_address_1: '',
+ branch_address_2: '',
+ phone_number: '',
+ email: '',
+ website: '',
+ branch_address_city: '',
+ branch_address_country: '',
+};
+
+function BranchForm({
+ // #withDialogActions
+ closeDialog,
+}) {
+ // Initial form values.
+ const initialValues = {
+ ...defaultInitialValues,
+ };
+
+ // Handles the form submit.
+ const handleFormSubmit = (values, { setSubmitting, setErrors }) => {};
+
+ return (
+
+ );
+}
+export default compose(withDialogActions)(BranchForm);
diff --git a/src/containers/Dialogs/BranchFormDialog/BranchForm.schema.js b/src/containers/Dialogs/BranchFormDialog/BranchForm.schema.js
new file mode 100644
index 000000000..2fe48f301
--- /dev/null
+++ b/src/containers/Dialogs/BranchFormDialog/BranchForm.schema.js
@@ -0,0 +1,15 @@
+import * as Yup from 'yup';
+import intl from 'react-intl-universal';
+
+const Schema = Yup.object().shape({
+ branch_name: Yup.string().required().label(intl.get('branch_name')),
+ branch_address_1: Yup.string().trim(),
+ branch_address_2: Yup.string().trim(),
+ branch_address_city: Yup.string().trim(),
+ branch_address_country: Yup.string().trim(),
+ website: Yup.string().url().nullable(),
+ phone_number: Yup.number(),
+ email: Yup.string().email().nullable(),
+});
+
+export const CreateBranchFormSchema = Schema;
diff --git a/src/containers/Dialogs/BranchFormDialog/BranchFormContent.js b/src/containers/Dialogs/BranchFormDialog/BranchFormContent.js
new file mode 100644
index 000000000..e47e5706e
--- /dev/null
+++ b/src/containers/Dialogs/BranchFormDialog/BranchFormContent.js
@@ -0,0 +1,17 @@
+import React from 'react';
+import { Form } from 'formik';
+
+import BranchFormFields from './BranchFormFields';
+import BranchFormFloatingActions from './BranchFormFloatingActions';
+
+/**
+ * Branch form content.
+ */
+export default function BranchFormContent() {
+ return (
+
+ );
+}
diff --git a/src/containers/Dialogs/BranchFormDialog/BranchFormDialogContent.js b/src/containers/Dialogs/BranchFormDialog/BranchFormDialogContent.js
new file mode 100644
index 000000000..b073f6f6e
--- /dev/null
+++ b/src/containers/Dialogs/BranchFormDialog/BranchFormDialogContent.js
@@ -0,0 +1,20 @@
+import React from 'react';
+
+import '../../../style/pages/Branches/BranchFormDialog.scss';
+
+import { BranchFormProvider } from './BranchFormProvider';
+import BranchForm from './BranchForm';
+
+/**
+ * Branch form dialog content.
+ */
+export default function BranchFormDialogContent({
+ // #ownProps
+ dialogName,
+}) {
+ return (
+
+
+
+ );
+}
diff --git a/src/containers/Dialogs/BranchFormDialog/BranchFormFields.js b/src/containers/Dialogs/BranchFormDialog/BranchFormFields.js
new file mode 100644
index 000000000..90eae49f9
--- /dev/null
+++ b/src/containers/Dialogs/BranchFormDialog/BranchFormFields.js
@@ -0,0 +1,157 @@
+import React from 'react';
+import intl from 'react-intl-universal';
+import { FastField, ErrorMessage, Field } from 'formik';
+import styled from 'styled-components';
+import {
+ Classes,
+ FormGroup,
+ InputGroup,
+ ControlGroup,
+ Position,
+} from '@blueprintjs/core';
+import { inputIntent } from 'utils';
+import { FieldRequiredHint, Col, Row, FormattedMessage as T } from 'components';
+import { useBranchFormContext } from './BranchFormProvider';
+
+/**
+ * Branch form dialog fields.
+ */
+function BranchFormFields() {
+ return (
+
+ {/*------------ Branch Name -----------*/}
+
+ {({ form, field, meta: { error, touched } }) => (
+ }
+ labelInfo={}
+ intent={inputIntent({ error, touched })}
+ inline={true}
+ helperText={}
+ className={'form-group--branch_name'}
+ >
+
+
+ )}
+
+
+ {/*------------ Branch Address 1 -----------*/}
+
+ {({ form, field, meta: { error, touched } }) => (
+ }
+ className={'form-group--branch_address_1'}
+ >
+
+
+ )}
+
+
+ {/*------------ Branch Address 2 -----------*/}
+
+ {({ form, field, meta: { error, touched } }) => (
+ }
+ className={'form-group--branch_address_2'}
+ >
+
+
+ )}
+
+
+ {/*------------ Branch Address City & Country-----------*/}
+ }
+ >
+
+
+ {({ field, meta: { error, touched } }) => (
+
+ )}
+
+
+
+ {({ field, meta: { error, touched } }) => (
+
+ )}
+
+
+
+
+
+ {/*------------ Phone Number -----------*/}
+
+ {({ form, field, meta: { error, touched } }) => (
+ }
+ className={'form-group--phone_number'}
+ >
+
+
+ )}
+
+
+ {/*------------ Email -----------*/}
+
+ {({ form, field, meta: { error, touched } }) => (
+ }
+ className={'form-group--email'}
+ >
+
+
+ )}
+
+
+ {/*------------ Website -----------*/}
+
+ {({ form, field, meta: { error, touched } }) => (
+ }
+ className={'form-group--website'}
+ >
+
+
+ )}
+
+
+ );
+}
+
+export default BranchFormFields;
+
+const BranchAddressWrap = styled.div`
+ margin-left: 160px;
+`;
diff --git a/src/containers/Dialogs/BranchFormDialog/BranchFormFloatingActions.js b/src/containers/Dialogs/BranchFormDialog/BranchFormFloatingActions.js
new file mode 100644
index 000000000..8b2c558bc
--- /dev/null
+++ b/src/containers/Dialogs/BranchFormDialog/BranchFormFloatingActions.js
@@ -0,0 +1,46 @@
+import React from 'react';
+
+import { Intent, Button, Classes } from '@blueprintjs/core';
+import { useFormikContext } from 'formik';
+import { FormattedMessage as T } from 'components';
+
+import { useBranchFormContext } from './BranchFormProvider';
+import withDialogActions from 'containers/Dialog/withDialogActions';
+import { compose } from 'utils';
+
+/**
+ * Branch form floating actions.
+ */
+function BranchFormFloatingActions({
+ // #withDialogActions
+ closeDialog,
+}) {
+ // Formik context.
+ const { isSubmitting } = useFormikContext();
+
+ const { dialogName } = useBranchFormContext();
+
+ // Handle close button click.
+ const handleCancelBtnClick = () => {
+ closeDialog(dialogName);
+ };
+
+ return (
+
+ );
+}
+export default compose(withDialogActions)(BranchFormFloatingActions);
diff --git a/src/containers/Dialogs/BranchFormDialog/BranchFormProvider.js b/src/containers/Dialogs/BranchFormDialog/BranchFormProvider.js
new file mode 100644
index 000000000..18e97bc92
--- /dev/null
+++ b/src/containers/Dialogs/BranchFormDialog/BranchFormProvider.js
@@ -0,0 +1,25 @@
+import React from 'react';
+import { DialogContent } from 'components';
+// import {} from 'hooks/query';
+
+const BranchFormContext = React.createContext();
+
+/**
+ * Branch form dialog provider.
+ */
+function BranchFormProvider({ dialogName, ...props }) {
+ // State provider.
+ const provider = {
+ dialogName,
+ };
+ return (
+
+
+
+ );
+}
+const useBranchFormContext = () => React.useContext(BranchFormContext);
+
+export { BranchFormProvider, useBranchFormContext };
diff --git a/src/containers/Dialogs/BranchFormDialog/index.js b/src/containers/Dialogs/BranchFormDialog/index.js
new file mode 100644
index 000000000..fca572330
--- /dev/null
+++ b/src/containers/Dialogs/BranchFormDialog/index.js
@@ -0,0 +1,31 @@
+import React from 'react';
+import { FormattedMessage as T } from 'components';
+import { Dialog, DialogSuspense } from 'components';
+import withDialogRedux from 'components/DialogReduxConnect';
+
+import { compose } from 'utils';
+
+const BranchFormDialogContent = React.lazy(() =>
+ import('./BranchFormDialogContent'),
+);
+
+/**
+ * Branch form form dialog.
+ */
+function BranchFormDialog({ dialogName, payload = {}, isOpen }) {
+ return (
+ }
+ isOpen={isOpen}
+ canEscapeJeyClose={true}
+ autoFocus={true}
+ className={'dialog--branch-form'}
+ >
+
+
+
+
+ );
+}
+export default compose(withDialogRedux())(BranchFormDialog);
diff --git a/src/containers/Preferences/Branches/Branches.js b/src/containers/Preferences/Branches/Branches.js
new file mode 100644
index 000000000..af93b014c
--- /dev/null
+++ b/src/containers/Preferences/Branches/Branches.js
@@ -0,0 +1,21 @@
+import React from 'react';
+import intl from 'react-intl-universal';
+import classNames from 'classnames';
+import { CLASSES } from 'common/classes';
+
+import BranchesDataTable from './BranchesDataTable';
+import withDashboardActions from 'containers/Dashboard/withDashboardActions';
+
+import { compose } from 'utils';
+
+function Branches({
+ // #withDashboardActions
+ changePreferencesPageTitle,
+}) {
+ React.useEffect(() => {
+ changePreferencesPageTitle(intl.get('branches.label'));
+ }, [changePreferencesPageTitle]);
+
+ return ;
+}
+export default compose(withDashboardActions)(Branches);
diff --git a/src/containers/Preferences/Branches/BranchesActions.js b/src/containers/Preferences/Branches/BranchesActions.js
new file mode 100644
index 000000000..a73c4bb93
--- /dev/null
+++ b/src/containers/Preferences/Branches/BranchesActions.js
@@ -0,0 +1,29 @@
+import React from 'react';
+import { Button, Intent } from '@blueprintjs/core';
+
+import { FormattedMessage as T, Icon } from 'components';
+import withDialogActions from 'containers/Dialog/withDialogActions';
+import { compose } from 'utils';
+
+function BranchesActions({
+ //#ownProps
+ openDialog,
+}) {
+ const handleClickNewBranche = () => {
+ openDialog('branch-form');
+ };
+
+ return (
+
+ }
+ onClick={handleClickNewBranche}
+ intent={Intent.PRIMARY}
+ >
+
+
+
+ );
+}
+
+export default compose(withDialogActions)(BranchesActions);
diff --git a/src/containers/Preferences/Branches/BranchesDataTable.js b/src/containers/Preferences/Branches/BranchesDataTable.js
new file mode 100644
index 000000000..91e992a10
--- /dev/null
+++ b/src/containers/Preferences/Branches/BranchesDataTable.js
@@ -0,0 +1,36 @@
+import React from 'react';
+import styled from 'styled-components';
+
+import { DataTable } from 'components';
+import TableSkeletonRows from 'components/Datatable/TableSkeletonRows';
+import { useBranchesTableColumns, ActionsMenu } from './components';
+
+import withDialogActions from 'containers/Dialog/withDialogActions';
+import { compose } from 'utils';
+
+/**
+ * Branches data table.
+ */
+function BranchesDataTable({
+ // #withDialogAction
+ openDialog,
+}) {
+ // Table columns.
+ const columns = useBranchesTableColumns();
+
+ return (
+
+ );
+}
+
+export default compose(withDialogActions)(BranchesDataTable);
+
+const BranchesTable = styled(DataTable)``;
diff --git a/src/containers/Preferences/Branches/BranchesProvider.js b/src/containers/Preferences/Branches/BranchesProvider.js
new file mode 100644
index 000000000..a8fdea708
--- /dev/null
+++ b/src/containers/Preferences/Branches/BranchesProvider.js
@@ -0,0 +1,35 @@
+import React from 'react';
+import styled from 'styled-components';
+import classNames from 'classnames';
+import { CLASSES } from 'common/classes';
+import { Card } from 'components';
+
+const BranchesContext = React.createContext();
+
+/**
+ * Branches data provider.
+ */
+function BranchesProvider({ ...props }) {
+ // Provider state.
+ const provider = {};
+
+ return (
+
+
+
+
+
+ );
+}
+
+const useBranchesContext = () => React.useContext(BranchesContext);
+export { BranchesProvider, useBranchesContext };
+
+const BrachesPreferencesCard = styled(Card)`
+ padding: 0;
+`;
diff --git a/src/containers/Preferences/Branches/components.js b/src/containers/Preferences/Branches/components.js
new file mode 100644
index 000000000..00239bf23
--- /dev/null
+++ b/src/containers/Preferences/Branches/components.js
@@ -0,0 +1,76 @@
+import React from 'react';
+import intl from 'react-intl-universal';
+import {
+ Intent,
+ Button,
+ Popover,
+ Menu,
+ MenuDivider,
+ Tag,
+ MenuItem,
+ Position,
+} from '@blueprintjs/core';
+
+import { safeCallback } from 'utils';
+import { Icon } from 'components';
+
+/**
+ * Context menu of Branches.
+ */
+export function ActionsMenu({
+ payload: { onEdit, onDelete },
+ row: { original },
+}) {
+ return (
+
+ );
+}
+
+/**
+ * Retrieve branches table columns
+ * @returns
+ */
+export function useBranchesTableColumns() {
+ return React.useMemo(
+ () => [
+ {
+ id: 'branch_name',
+ Header: intl.get('branches.column.branch_name'),
+ accessor: 'branch_name',
+ className: 'branch_name',
+ width: '120',
+ disableSortBy: true,
+ textOverview: true,
+ },
+ {
+ Header: intl.get('branches.column.address'),
+ accessor: 'address',
+ className: 'address',
+ width: '180',
+ disableSortBy: true,
+ textOverview: true,
+ },
+ {
+ Header: intl.get('branches.column.phone_number'),
+ accessor: 'phone_number',
+ className: 'phone_number',
+ width: '120',
+ disableSortBy: true,
+ },
+ ],
+ [],
+ );
+}
diff --git a/src/containers/Preferences/Branches/index.js b/src/containers/Preferences/Branches/index.js
new file mode 100644
index 000000000..9bd083d91
--- /dev/null
+++ b/src/containers/Preferences/Branches/index.js
@@ -0,0 +1,15 @@
+import React from 'react';
+
+import { BranchesProvider } from './BranchesProvider';
+import Branches from './Branches';
+
+/**
+ * Branches .
+ */
+export default function BranchesPreferences() {
+ return (
+
+
+
+ );
+}
diff --git a/src/lang/en/index.json b/src/lang/en/index.json
index 4147975a2..eb7b674b3 100644
--- a/src/lang/en/index.json
+++ b/src/lang/en/index.json
@@ -1738,19 +1738,32 @@
"global_error.you_dont_have_permissions": "You do not have permissions to access this page.",
"global_error.transactions_locked": "Transactions before {lockedToDate} has been locked. Hence action cannot be performed.",
"global_error.authorized_user_inactive": "The authorized user is inactive.",
-
"the_vendor_has_been_inactivated_successfully": "The contact has been inactivated successfully.",
-
"vendor.alert.activated_message": "The vendor has been activated successfully.",
- "vendor.alert.are_you_sure_want_to_inactivate_this_vendor":"Are you sure want to inactivate this vendor? You will to able to activate it later.",
+ "vendor.alert.are_you_sure_want_to_inactivate_this_vendor": "Are you sure want to inactivate this vendor? You will to able to activate it later.",
"vendor.alert.inactivated_message": "The vendor has been inactivated successfully.",
"vendor.alert.are_you_sure_want_to_activate_this_vendor": "Are you sure want to activate this vendor? You will to able to inactivate it later.",
-
- "customer.alert.activated_message":"The customer has been activated successfully.",
+ "customer.alert.activated_message": "The customer has been activated successfully.",
"customer.alert.are_you_sure_want_to_activate_this_customer": "Are you sure want to activate this customer? You will to able to inactivate it later.",
"customer.alert.inactivated_message": "The customer has been inactivated successfully.",
- "customer.alert.are_you_sure_want_to_inactivate_this_customer":"Are you sure want to inactivate this customer? You will to able to activate it later.",
-
- "credit_note_preview.dialog.title":"Credit Note PDF Preview",
- "payment_receive_preview.dialog.title":"Payment Receive PDF Preview"
+ "customer.alert.are_you_sure_want_to_inactivate_this_customer": "Are you sure want to inactivate this customer? You will to able to activate it later.",
+ "credit_note_preview.dialog.title": "Credit Note PDF Preview",
+ "payment_receive_preview.dialog.title": "Payment Receive PDF Preview",
+ "branches.label": "Branches",
+ "branches.label.new_branche": "New Branch",
+ "branches.action.edit_branch": "Edit Branch",
+ "branches.action.delete_branch": "Edit Branch",
+ "branches.column.branch_name": "Branch name",
+ "branches.column.address": "Address",
+ "branches.column.phone_number": "Phone number",
+ "branch.dialog.label": "New Branch",
+ "branch.dialog.label.branch_name": "Branch Name",
+ "branch.dialog.label.branch_address": "Branch Address",
+ "branch.dialog.label.address_1": "Address 1",
+ "branch.dialog.label.address_2": "Address 2",
+ "branch.dialog.label.city": "City",
+ "branch.dialog.label.country": "Country",
+ "branch.dialog.label.phone_number": "Phone Number",
+ "branch.dialog.label.email": "Email",
+ "branch.dialog.label.website": "Website"
}
\ No newline at end of file
diff --git a/src/routes/preferences.js b/src/routes/preferences.js
index 9fc454ddd..c8962e8b6 100644
--- a/src/routes/preferences.js
+++ b/src/routes/preferences.js
@@ -7,6 +7,7 @@ import Currencies from 'containers/Preferences/Currencies/Currencies';
import Item from 'containers/Preferences/Item';
import SMSIntegration from '../containers/Preferences/SMSIntegration';
import DefaultRoute from '../containers/Preferences/DefaultRoute';
+import Branches from '../containers/Preferences/Branches'
const BASE_URL = '/preferences';
@@ -36,6 +37,11 @@ export default [
component: Currencies,
exact: true,
},
+ {
+ path: `${BASE_URL}/branches`,
+ component: Branches,
+ exact: true,
+ },
{
path: `${BASE_URL}/accountant`,
component: Accountant,
diff --git a/src/style/pages/Branches/BranchFormDialog.scss b/src/style/pages/Branches/BranchFormDialog.scss
new file mode 100644
index 000000000..b10bea737
--- /dev/null
+++ b/src/style/pages/Branches/BranchFormDialog.scss
@@ -0,0 +1,39 @@
+.dialog--branch-form {
+ width: 600px;
+
+ .bp3-dialog-body {
+ .bp3-form-group {
+ margin-bottom: 15px;
+ }
+ .bp3-form-group.bp3-inline {
+ .bp3-label {
+ font-size: 13px;
+ margin-bottom: 3px;
+ min-width: 150px;
+ }
+ .bp3-form-content {
+ width: 320px;
+ }
+ }
+ .form-group {
+ &--branch_address_city {
+ .bp3-control-group > * {
+ flex-shrink: unset;
+ padding-right: 5px;
+ padding-left: 5px;
+
+ &:first-child {
+ padding-left: 0;
+ }
+ &:last-child {
+ padding-right: 0;
+ }
+ }
+ }
+ }
+ }
+
+ .bp3-dialog-footer {
+ padding-top: 10px;
+ }
+}