diff --git a/src/common/classes.js b/src/common/classes.js
index 1bbcf9873..c00f489f3 100644
--- a/src/common/classes.js
+++ b/src/common/classes.js
@@ -71,6 +71,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 f52002200..ed46913da 100644
--- a/src/components/DialogsContainer.js
+++ b/src/components/DialogsContainer.js
@@ -35,6 +35,7 @@ import UnlockingPartialTransactionsDialog from '../containers/Dialogs/UnlockingP
import CreditNotePdfPreviewDialog from '../containers/Dialogs/CreditNotePdfPreviewDialog';
import PaymentReceivePdfPreviewDialog from '../containers/Dialogs/PaymentReceivePdfPreviewDialog';
import WarehouseFormDialog from '../containers/Dialogs/WarehouseFormDialog';
+import BranchFormDialog from '../containers/Dialogs/BranchFormDialog';
/**
* Dialogs container.
@@ -80,6 +81,7 @@ export default function DialogsContainer() {
+
);
}
diff --git a/src/components/Preferences/PreferencesTopbar.js b/src/components/Preferences/PreferencesTopbar.js
index 7b27a83e8..dfc687d4d 100644
--- a/src/components/Preferences/PreferencesTopbar.js
+++ b/src/components/Preferences/PreferencesTopbar.js
@@ -6,7 +6,8 @@ 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 WarehousesActions from '../../containers/Preferences/Warehouses/WarehousesActions'
+import WarehousesActions from '../../containers/Preferences/Warehouses/WarehousesActions';
+import BranchesActions from '../../containers/Preferences/Branches/BranchesActions';
import withDashboard from 'containers/Dashboard/withDashboard';
import { compose } from 'utils';
@@ -41,6 +42,7 @@ function PreferencesTopbar({ preferencesPageTitle }) {
path={'/preferences/warehouses'}
component={WarehousesActions}
/>
+
diff --git a/src/config/preferencesMenu.js b/src/config/preferencesMenu.js
index f01ca6e12..48b5d0952 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: ,
href: '/preferences/warehouses',
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 037112e8d..904427d0a 100644
--- a/src/lang/en/index.json
+++ b/src/lang/en/index.json
@@ -1768,9 +1768,6 @@
"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",
-
"warehouses.label": "Warehouses",
"warehouses.label.new_warehouse": "New Warehouse",
"warehouse.dialog.label.new_warehouse": "New Warehouse",
@@ -1824,5 +1821,25 @@
"select_warehouse_transfer":"Select Warehouse Transfer",
"warehouse_transfer.alert.delete_message":"The warehouse transfer transaction has been deleted successfully",
"warehouse_transfer.once_delete_this_warehouse_transfer":"Once you delete this warehouse transfer, you won't be able to restore it later. Are you sure you want to delete this warehouse transfer?",
- "warehouse_transfer.error.could_not_transfer_item_from_source_to_destination":"Could not transfer item from source to destination on the same warehouse"
+ "warehouse_transfer.error.could_not_transfer_item_from_source_to_destination":"Could not transfer item from source to destination on the same warehouse",
+
+ "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 b4200758e..53c8b5e38 100644
--- a/src/routes/preferences.js
+++ b/src/routes/preferences.js
@@ -2,12 +2,12 @@ import General from 'containers/Preferences/General/General';
import Users from '../containers/Preferences/Users/Users';
import Roles from '../containers/Preferences/Users/Roles/RolesForm/RolesFormPage';
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 SMSIntegration from '../containers/Preferences/SMSIntegration';
import DefaultRoute from '../containers/Preferences/DefaultRoute';
import Warehouses from '../containers/Preferences/Warehouses';
+import Branches from '../containers/Preferences/Branches';
const BASE_URL = '/preferences';
@@ -40,6 +40,10 @@ export default [
{
path: `${BASE_URL}/warehouses`,
component: Warehouses,
+ },
+ {
+ path: `${BASE_URL}/branches`,
+ component: Branches,
exact: true,
},
{
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;
+ }
+}