Merge remote-tracking branch 'origin/feature/general'

This commit is contained in:
Ahmed Bouhuolia
2020-04-28 04:40:29 +02:00
24 changed files with 595 additions and 379 deletions

View File

@@ -70,6 +70,7 @@
"react-loadable": "^5.5.0", "react-loadable": "^5.5.0",
"react-redux": "^7.1.3", "react-redux": "^7.1.3",
"react-router-dom": "^5.1.2", "react-router-dom": "^5.1.2",
"react-scrollbars-custom": "^4.0.21",
"react-sortablejs": "^2.0.11", "react-sortablejs": "^2.0.11",
"react-table": "^7.0.0", "react-table": "^7.0.0",
"react-use": "^13.26.1", "react-use": "^13.26.1",

View File

@@ -5,25 +5,34 @@ import DialogConnect from 'connectors/Dialog.connector';
import LoadingIndicator from 'components/LoadingIndicator'; import LoadingIndicator from 'components/LoadingIndicator';
import { compose } from 'utils'; import { compose } from 'utils';
import DataTable from 'components/DataTable'; import DataTable from 'components/DataTable';
import { Button, Popover, Menu, MenuItem, Position } from '@blueprintjs/core'; import {
Button,
Popover,
Menu,
MenuItem,
Position,
Classes,
Tooltip,
} from '@blueprintjs/core';
const ItemsCategoryList = ({ const ItemsCategoryList = ({
categories, categories,
onFetchData, onFetchData,
onDeleteCategory, onDeleteCategory,
onEditCategory, onEditCategory,
openDialog openDialog,
count,
}) => { }) => {
const handelEditCategory = category => () => { const handelEditCategory = (category) => () => {
openDialog('item-form', { action: 'edit', id: category.id }); openDialog('item-form', { action: 'edit', id: category.id });
onEditCategory(category.id); onEditCategory(category.id);
}; };
const handleDeleteCategory = category => () => { const handleDeleteCategory = (category) => () => {
onDeleteCategory(category); onDeleteCategory(category);
}; };
const actionMenuList = category => ( const actionMenuList = (category) => (
<Menu> <Menu>
<MenuItem text='Edit Category' onClick={handelEditCategory(category)} /> <MenuItem text='Edit Category' onClick={handelEditCategory(category)} />
<MenuItem <MenuItem
@@ -38,17 +47,22 @@ const ItemsCategoryList = ({
{ {
id: 'name', id: 'name',
Header: 'Category Name', Header: 'Category Name',
accessor: 'name' accessor: 'name',
width: 150,
}, },
{ {
id: 'description', id: 'description',
Header: 'Description', Header: 'Description',
accessor: 'description' accessor: 'description',
className: 'description',
width: 150,
}, },
{ {
id: 'count', id: 'count',
Header: 'Count', Header: 'Count',
// accessor: '' accessor: () => <span>{count}</span>,
className: 'count',
width: 50,
}, },
{ {
id: 'actions', id: 'actions',
@@ -62,9 +76,9 @@ const ItemsCategoryList = ({
</Popover> </Popover>
), ),
className: 'actions', className: 'actions',
width: 50 width: 50,
// canResize: false // canResize: false
} },
], ],
[] []
); );
@@ -73,6 +87,7 @@ const ItemsCategoryList = ({
onFetchData && onFetchData(); onFetchData && onFetchData();
}, []); }, []);
return ( return (
<LoadingIndicator spinnerSize={30}> <LoadingIndicator spinnerSize={30}>
<DataTable <DataTable
@@ -81,6 +96,8 @@ const ItemsCategoryList = ({
onFetchData={handelFetchData} onFetchData={handelFetchData}
manualSortBy={true} manualSortBy={true}
selectionColumn={true} selectionColumn={true}
expandable={true}
treeGraph={true}
/> />
</LoadingIndicator> </LoadingIndicator>
); );

View File

@@ -2,14 +2,14 @@ import React from 'react';
import PreferencesTopbar from 'components/Preferences/PreferencesTopbar'; import PreferencesTopbar from 'components/Preferences/PreferencesTopbar';
import PreferencesContentRoute from 'components/Preferences/PreferencesContentRoute'; import PreferencesContentRoute from 'components/Preferences/PreferencesContentRoute';
export default function() { export default function () {
return ( return (
<div className="dashboard-content dashboard-content--preferences"> <div className='dashboard-content dashboard-content--preferences'>
<PreferencesTopbar pageTitle={"asdad"}/> <PreferencesTopbar pageTitle={'asdad'} />
<div class="dashboard__preferences-content"> <div className='dashboard__preferences-content'>
<PreferencesContentRoute /> <PreferencesContentRoute />
</div> </div>
</div> </div>
) );
} }

View File

@@ -1,11 +1,12 @@
import React from 'react'; import * as React from 'react';
import { Scrollbar } from 'react-scrollbars-custom';
export default function SidebarContainer(props) { export default function SidebarContainer(props) {
return ( return (
<div className="sidebar" id="sidebar"> <div className='sidebar' id='sidebar'>
<div class="sidebar__inner"> <Scrollbar noDefaultStyles={true}>
{props.children} <div className='sidebar__inner'>{props.children}</div>
</div> </Scrollbar>
</div> </div>
) );
} }

View File

@@ -32,7 +32,7 @@ export default function SidebarMenu() {
dropdownType={item.dropdownType || 'collapse'} dropdownType={item.dropdownType || 'collapse'}
caretIconSize={15} caretIconSize={15}
onClick={handleItemClick} onClick={handleItemClick}
callapseActive={!!isActive} // callapseActive={!!isActive}
className={classNames({ 'is-active': isActive })} /> className={classNames({ 'is-active': isActive })} />
); );
}); });

View File

@@ -3,31 +3,31 @@ import {
fetchItemCategories, fetchItemCategories,
submitItemCategory, submitItemCategory,
deleteItemCategory, deleteItemCategory,
editItemCategory editItemCategory,
} from 'store/itemCategories/itemsCategory.actions'; } from 'store/itemCategories/itemsCategory.actions';
import { getDialogPayload } from 'store/dashboard/dashboard.reducer'; import { getDialogPayload } from 'store/dashboard/dashboard.reducer';
import { getCategoryId } from 'store/itemCategories/itemsCategory.reducer'; import { getCategoryId } from 'store/itemCategories/itemsCategory.reducer';
export const mapStateToProps = (state, props) => { export const mapStateToProps = (state, props) => {
const dialogPayload = getDialogPayload(state, 'item-form'); const dialogPayload = getDialogPayload(state, 'item-form');
return { return {
categories: state.itemCategories.categories, categories: state.itemCategories.categories,
categoriesList: Object.values(state.itemCategories.categories), count: 1,
name: 'item-form', name: 'item-form',
payload: { action: 'new', id: null }, payload: { action: 'new', id: null },
editItemCategory: editItemCategory:
dialogPayload && dialogPayload.action === 'edit' dialogPayload && dialogPayload.action === 'edit'
? state.itemCategories.categories[dialogPayload.id] ? state.itemCategories.categories[dialogPayload.id]
: {}, : {},
getCategoryId: id => getCategoryId(state, id) getCategoryId: (id) => getCategoryId(state, id),
}; };
}; };
export const mapDispatchToProps = (dispatch) => ({
export const mapDispatchToProps = dispatch => ({ requestSubmitItemCategory: (form) => dispatch(submitItemCategory({ form })),
requestSubmitItemCategory: form => dispatch(submitItemCategory({ form })),
requestFetchItemCategories: () => dispatch(fetchItemCategories()), requestFetchItemCategories: () => dispatch(fetchItemCategories()),
requestDeleteItemCategory: id => dispatch(deleteItemCategory(id)), requestDeleteItemCategory: (id) => dispatch(deleteItemCategory(id)),
requestEditItemCategory: (id, form) => dispatch(editItemCategory(id, form)) requestEditItemCategory: (id, form) => dispatch(editItemCategory(id, form)),
}); });
export default connect(mapStateToProps, mapDispatchToProps); export default connect(mapStateToProps, mapDispatchToProps);

View File

@@ -1,4 +1,10 @@
import {connect} from 'react-redux'; import { connect } from 'react-redux';
import {
FetchOption,
FetchOptions,
submitOptions,
} from 'store/settings/settings.actions';
export const mapStateToProps = (state, props) => { export const mapStateToProps = (state, props) => {
return { return {
@@ -7,7 +13,8 @@ export const mapStateToProps = (state, props) => {
}; };
export const mapDispatchToProps = (dispatch) => ({ export const mapDispatchToProps = (dispatch) => ({
requestSubmitOptions: (form) => dispatch(submitOptions({ form })),
requestFetchOptions: () => dispatch(FetchOptions({})),
}); });
export default connect(mapStateToProps, mapDispatchToProps); export default connect(mapStateToProps, mapDispatchToProps);

View File

@@ -1,20 +1,18 @@
import {connect} from 'react-redux'; import { connect } from 'react-redux';
import { import { fetchUsers, fetchUser, deleteUser } from 'store/users/users.actions';
fetchUsers,
fetchUser,
deleteUser,
} from 'store/users/users.actions';
import t from 'store/types'; import t from 'store/types';
export const mapStateToProps = (state, props) => ({ export const mapStateToProps = (state, props) => ({
usersList: state.users.list usersList: state.users.list.results,
}); });
export const mapDispatchToProps = (dispatch) => ({ export const mapDispatchToProps = (dispatch) => ({
openDialog: (name, payload) => dispatch({ type: t.OPEN_DIALOG, name, payload }), openDialog: (name, payload) =>
closeDialog: (name, payload) => dispatch({ type: t.CLOSE_DIALOG, name, payload }), dispatch({ type: t.OPEN_DIALOG, name, payload }),
closeDialog: (name, payload) =>
dispatch({ type: t.CLOSE_DIALOG, name, payload }),
fetchUsers: () => dispatch(fetchUsers({ })), fetchUsers: () => dispatch(fetchUsers({})),
fetchUser: (id) => dispatch(fetchUser({ id })), fetchUser: (id) => dispatch(fetchUser({ id })),
deleteUser: (id) => dispatch(deleteUser({ id })), deleteUser: (id) => dispatch(deleteUser({ id })),
}); });

View File

@@ -89,7 +89,7 @@ function AccountFormDialog({
requestEditAccount({ requestEditAccount({
payload: payload.id, payload: payload.id,
form: { ...omit(values, [...exclude, 'account_type_id']) } form: { ...omit(values, [...exclude, 'account_type_id']) }
}).then(response => { }).then((response) => {
closeDialog(name); closeDialog(name);
AppToaster.show({ AppToaster.show({
message: 'the_account_has_been_edited' message: 'the_account_has_been_edited'

View File

@@ -1,6 +1,6 @@
import React from 'react'; import React, { useMemo } from 'react';
import { useIntl } from "react-intl" import { useIntl } from 'react-intl';
import {useFormik} from 'formik'; import { useFormik } from 'formik';
import * as Yup from 'yup'; import * as Yup from 'yup';
import { import {
Dialog, Dialog,
@@ -18,8 +18,12 @@ import UserFormDialogConnect from 'connectors/UserFormDialog.connector';
import DialogReduxConnect from 'components/DialogReduxConnect'; import DialogReduxConnect from 'components/DialogReduxConnect';
import AppToaster from 'components/AppToaster'; import AppToaster from 'components/AppToaster';
import useAsync from 'hooks/async'; import useAsync from 'hooks/async';
import {objectKeysTransform} from 'utils'; import { objectKeysTransform } from 'utils';
import {pick, snakeCase} from 'lodash'; import { pick, snakeCase } from 'lodash';
import ErrorMessage from 'components/ErrorMessage';
import classNames from 'classnames';
import Icon from 'components/Icon';
import { compose } from 'utils';
function UserFormDialog({ function UserFormDialog({
fetchUser, fetchUser,
@@ -34,27 +38,21 @@ function UserFormDialog({
const intl = useIntl(); const intl = useIntl();
const fetchHook = useAsync(async () => { const fetchHook = useAsync(async () => {
await Promise.all([ await Promise.all([
...(payload.action === 'edit') ? [ ...(payload.action === 'edit' ? [fetchUser(payload.user.id)] : []),
fetchUser(payload.user.id),
] : [],
]); ]);
}, false); }, false);
const validationSchema = Yup.object().shape({ const validationSchema = Yup.object().shape({
first_name: Yup.string().required(),
last_name: Yup.string().required(),
email: Yup.string().email().required(), email: Yup.string().email().required(),
phone_number: Yup.string().required(),
password: Yup.string().min(5).required(),
}); });
const initialValues = { const initialValues = {
status: 1, status: 1,
...payload.action === 'edit' && ...(payload.action === 'edit' &&
pick( pick(
objectKeysTransform(payload.user, snakeCase), objectKeysTransform(payload.user, snakeCase),
Object.keys(validationSchema.fields) Object.keys(validationSchema.fields)
), )),
password: '', password: '',
}; };
@@ -84,113 +82,76 @@ function UserFormDialog({
} }
}, },
}); });
const { values, errors, touched } = useMemo(() => formik, [formik]);
const statusOptions = [ const statusOptions = [
{value: 1, label: 'Active'}, { value: 1, label: 'Active' },
{value: 2, label: 'Inactive'}, { value: 2, label: 'Inactive' },
]; ];
const onDialogOpening = () => { fetchHook.execute(); }; const onDialogOpening = () => {
fetchHook.execute();
};
const onDialogClosed = () => { const onDialogClosed = () => {
formik.resetForm(); formik.resetForm();
}; };
const handleClose = () => { closeDialog(name); }; const handleClose = () => {
closeDialog(name);
};
return ( return (
<Dialog <Dialog
isOpen={isOpen}
name={name} name={name}
title={payload.action === 'edit' ? 'Edit User' : 'New User'} title={payload.action === 'edit' ? 'Edit invite' : 'New invite'}
className={classNames({
'dialog--loading': fetchHook.pending,
'dialog--invite-form': true,
})}
autoFocus={true}
canEscapeKeyClose={true}
isOpen={isOpen}
isLoading={fetchHook.pending} isLoading={fetchHook.pending}
onClosed={onDialogClosed} onClosed={onDialogClosed}
onOpening={onDialogOpening}> onOpening={onDialogOpening}
>
<form onSubmit={formik.handleSubmit}> <form onSubmit={formik.handleSubmit}>
<div className={Classes.DIALOG_BODY}> <div className={Classes.DIALOG_BODY}>
<FormGroup <FormGroup
label={'First Name'} label={'Email'}
className={'form-group--first-name'} className={'form-group--email'}
intent={formik.errors.first_name && Intent.DANGER} intent={errors.email && touched.email && Intent.DANGER}
helperText={formik.errors.first_name && formik.errors.first_name} helperText={<ErrorMessage name='email' {...formik} />}
inline={true}> inline={true}
>
<InputGroup <InputGroup
intent={formik.errors.first_name && Intent.DANGER} medium={true}
{...formik.getFieldProps('first_name')} /> intent={errors.email && touched.email && Intent.DANGER}
{...formik.getFieldProps('email')}
/>
</FormGroup> </FormGroup>
<FormGroup
label={'Last Name'}
className={'form-group--last-name'}
intent={formik.errors.last_name && Intent.DANGER}
helperText={formik.errors.last_name && formik.errors.last_name}
inline={true}>
<InputGroup
intent={formik.errors.last_name && Intent.DANGER}
{...formik.getFieldProps('last_name')} />
</FormGroup>
<FormGroup <FormGroup
label={'Email'} label={'Email'}
className={'form-group--email'} className={'form-group--email'}
intent={formik.errors.email && Intent.DANGER} intent={errors.email && touched.email && Intent.DANGER}
helperText={formik.errors.email && formik.errors.email} helperText={<ErrorMessage name='email' {...formik} />}
inline={true}> inline={true}
>
<InputGroup <InputGroup
intent={formik.errors.email && Intent.DANGER} medium={true}
{...formik.getFieldProps('email')} /> intent={errors.email && touched.email && Intent.DANGER}
{...formik.getFieldProps('email')}
/>
</FormGroup> </FormGroup>
</div>
<FormGroup <div className={Classes.DIALOG_FOOTER}>
label={'Phone Number'} <div className={Classes.DIALOG_FOOTER_ACTIONS}>
className={'form-group--phone-number'} <Button onClick={handleClose}>Close</Button>
intent={formik.errors.phone_number && Intent.DANGER} <Button intent={Intent.PRIMARY} type='submit'>
helperText={formik.errors.phone_number && formik.errors.phone_number} {payload.action === 'edit' ? 'Edit' : 'invite'}
inline={true}> </Button>
<InputGroup
intent={formik.errors.phone_number && Intent.DANGER}
{...formik.getFieldProps('phone_number')} />
</FormGroup>
<FormGroup
label={'Password'}
className={'form-group--password'}
intent={formik.errors.password && Intent.DANGER}
helperText={formik.errors.password && formik.errors.password}
inline={true}>
<InputGroup
intent={formik.errors.password && Intent.DANGER}
className={Classes.FILL}
{...formik.getFieldProps('password')} />
</FormGroup>
<FormGroup
label={'Status'}
className={'form-group--status'}
intent={formik.errors.status && Intent.DANGER}
helperText={formik.errors.status && formik.errors.status}
inline={true}>
<HTMLSelect
options={statusOptions}
className={Classes.FILL}
{...formik.getFieldProps(`status`)} />
</FormGroup>
<div className={Classes.DIALOG_FOOTER}>
<div className={Classes.DIALOG_FOOTER_ACTIONS}>
<Button onClick={handleClose}>Close</Button>
<Button intent={Intent.PRIMARY} type="submit">
{ payload.action === 'edit' ? 'Edit' : 'Submit' }
</Button>
</div>
</div> </div>
</div> </div>
</form> </form>
@@ -198,4 +159,7 @@ function UserFormDialog({
); );
} }
export default UserFormDialogConnect(DialogReduxConnect(UserFormDialog)); export default compose(
UserFormDialogConnect,
DialogReduxConnect
)(UserFormDialog);

View File

@@ -3,21 +3,45 @@ import {} from 'reselect';
import DashboardActionsBar from 'components/Dashboard/DashboardActionsBar'; import DashboardActionsBar from 'components/Dashboard/DashboardActionsBar';
import { compose } from 'utils'; import { compose } from 'utils';
import { NavbarGroup, Button, Classes, Intent } from '@blueprintjs/core'; import {
NavbarGroup,
Button,
Classes,
Intent,
Popover,
Position,
PopoverInteractionKind,
} from '@blueprintjs/core';
import classNames from 'classnames';
import Icon from 'components/Icon'; import Icon from 'components/Icon';
import DashboardConnect from 'connectors/Dashboard.connector'; import DashboardConnect from 'connectors/Dashboard.connector';
import ItemsCategoryConnect from 'connectors/ItemsCategory.connect'; import ItemsCategoryConnect from 'connectors/ItemsCategory.connect';
import DialogConnect from 'connectors/Dialog.connector'; import DialogConnect from 'connectors/Dialog.connector';
import FilterDropdown from 'components/FilterDropdown';
import ResourceConnect from 'connectors/Resource.connector';
const ItemsCategoryActionsBar = ({ openDialog, onDeleteCategory }) => { const ItemsCategoryActionsBar = ({
openDialog,
onDeleteCategory,
onFilterChanged,
getResourceFields,
}) => {
const onClickNewCategory = () => { const onClickNewCategory = () => {
openDialog('item-form', {}); openDialog('item-form', {});
}; };
const handleDeleteCategory = category => { const handleDeleteCategory = (category) => {
onDeleteCategory(category); onDeleteCategory(category);
}; };
const categoriesFields = getResourceFields('itemCategories');
const filterDropdown = FilterDropdown({
fields: categoriesFields,
onFilterChange: (filterConditions) => {
onFilterChanged && onFilterChanged(filterConditions);
},
});
return ( return (
<DashboardActionsBar> <DashboardActionsBar>
<NavbarGroup> <NavbarGroup>
@@ -27,6 +51,17 @@ const ItemsCategoryActionsBar = ({ openDialog, onDeleteCategory }) => {
text='New Category' text='New Category'
onClick={onClickNewCategory} onClick={onClickNewCategory}
/> />
<Popover
content={filterDropdown}
interactionKind={PopoverInteractionKind.CLICK}
position={Position.BOTTOM_LEFT}
>
<Button
className={classNames(Classes.MINIMAL, 'button--filter')}
text='Filter'
icon={<Icon icon='filter' />}
/>
</Popover>
<Button <Button
className={Classes.MINIMAL} className={Classes.MINIMAL}
@@ -54,5 +89,6 @@ const ItemsCategoryActionsBar = ({ openDialog, onDeleteCategory }) => {
export default compose( export default compose(
DialogConnect, DialogConnect,
DashboardConnect, DashboardConnect,
ItemsCategoryConnect ItemsCategoryConnect,
ResourceConnect
)(ItemsCategoryActionsBar); )(ItemsCategoryActionsBar);

View File

@@ -1,4 +1,4 @@
import React, { useState, useCallback, useMemo } from 'react'; import React, { useState, useCallback, useMemo, useEffect } from 'react';
import { useFormik } from 'formik'; import { useFormik } from 'formik';
import * as Yup from 'yup'; import * as Yup from 'yup';
import { import {
@@ -10,16 +10,24 @@ import {
Classes, Classes,
} from '@blueprintjs/core'; } from '@blueprintjs/core';
import { optionsMapToArray, momentFormatter } from 'utils'; import { optionsMapToArray, momentFormatter, optionsArrayToMap } from 'utils';
import { TimezonePicker } from '@blueprintjs/timezone'; import { TimezonePicker } from '@blueprintjs/timezone';
import { Select } from '@blueprintjs/select'; import { Select } from '@blueprintjs/select';
import classNames from 'classnames'; import classNames from 'classnames';
import ErrorMessage from 'components/ErrorMessage'; import ErrorMessage from 'components/ErrorMessage';
import Icon from 'components/Icon'; import Icon from 'components/Icon';
import { compose } from 'utils';
import SettingsConnect from 'connectors/Settings.connect';
import AppToaster from 'components/AppToaster';
import { useIntl } from 'react-intl';
import useAsync from 'hooks/async';
function GeneralPreferences(props) { function GeneralPreferences({
organizationSettings,
requestSubmitOptions,
requestFetchOptions,
}) {
const [selectedItems, setSelectedItems] = useState({}); const [selectedItems, setSelectedItems] = useState({});
const [disableItems, setDisableItems] = useState(false);
const [timeZone, setTimeZone] = useState(''); const [timeZone, setTimeZone] = useState('');
const businessLocation = [ const businessLocation = [
@@ -28,8 +36,8 @@ function GeneralPreferences(props) {
{ id: 212, name: 'Morocco', code: 'MA' }, { id: 212, name: 'Morocco', code: 'MA' },
]; ];
const languagesDisplay = [ const languagesDisplay = [
{ name: 'EN', label: 'English' }, { id: 0, name: 'EN', label: 'English' },
{ name: 'Arb', label: 'Arabic' }, { id: 1, name: 'Arb', label: 'Arabic' },
]; ];
const currencies = [ const currencies = [
{ id: 0, name: 'US Dollar', code: 'USD' }, { id: 0, name: 'US Dollar', code: 'USD' },
@@ -41,34 +49,59 @@ function GeneralPreferences(props) {
{ id: 1, name: 'August-December', label: 'August-December' }, { id: 1, name: 'August-December', label: 'August-December' },
]; ];
const dateFormat = [ const dateFormat = [
{ name: '04/11/2020', format: 'MM-DD-YY' }, { id: 1, name: '04/11/2020', format: 'MM-DD-YY' },
{ name: '2020/03/21', format: 'YY/MM/DD' }, { id: 3, name: '2020/03/21', format: 'YY/MM/DD' },
{ name: 'Apr 11, 2020', format: 'MMMM yyyy' }, { id: 4, name: 'Apr 11, 2020', format: 'MMMM yyyy' },
{ name: 'Saturday, Apr 11, 2020', format: 'EEEE, MMM d, yyyy' }, { id: 6, name: 'Saturday, Apr 11, 2020', format: 'EEEE, MMM d, yyyy' },
]; ];
const intl = useIntl();
const validationSchema = Yup.object().shape({ const validationSchema = Yup.object().shape({
organization_name: Yup.string().required('required field'), name: Yup.string().required(intl.formatMessage({ id: 'required' })),
organization_industry: Yup.string().required('required field'), industry: Yup.string().required(intl.formatMessage({ id: 'required' })),
business_location: Yup.string().required('required field'), location: Yup.string().required(intl.formatMessage({ id: 'required' })),
base_currency: Yup.string().required('required field'), base_currency: Yup.string().required(
fiscal_year: Yup.string().required('required field'), intl.formatMessage({ id: 'required' })
language: Yup.string().required('required field'), ),
time_zone: Yup.date().required('required field'), fiscal_year: Yup.string().required(intl.formatMessage({ id: 'required' })),
date_format: Yup.date().required('required field'), language: Yup.string().required(intl.formatMessage({ id: 'required' })),
// time_zone: Yup.object().required(intl.formatMessage({ id: 'required' })),
date_format: Yup.date().required(intl.formatMessage({ id: 'required' })),
}); });
console.log(organizationSettings.name);
const formik = useFormik({ const formik = useFormik({
enableReinitialize: true, enableReinitialize: true,
initialValues: {}, initialValues: {
...organizationSettings,
},
validationSchema: validationSchema, validationSchema: validationSchema,
onSubmit: (values) => {
onSubmit: (values, { setSubmitting }) => {
const options = optionsMapToArray(values).map((option) => { const options = optionsMapToArray(values).map((option) => {
return { ...option, group: 'general' }; return { key: option.key, ...option, group: 'organization' };
}); });
requestSubmitOptions({ options })
.then((response) => {
AppToaster.show({
message: 'The_Options_has_been_Submit',
});
setSubmitting(false);
})
.catch((error) => {
setSubmitting(false);
});
}, },
}); });
const { errors, values, touched } = useMemo(() => formik, [formik]); const { errors, values, touched } = useMemo(() => formik, [formik]);
const fetchHook = useAsync(async () => {
await Promise.all([requestFetchOptions()]);
});
const businessLocationItem = (item, { handleClick }) => ( const businessLocationItem = (item, { handleClick }) => (
<MenuItem <MenuItem
className={'preferences-menu'} className={'preferences-menu'}
@@ -107,7 +140,7 @@ function GeneralPreferences(props) {
/> />
); );
const data_Format = (item, { handleClick }) => ( const date_format = (item, { handleClick }) => (
<MenuItem <MenuItem
className={'preferences-menu'} className={'preferences-menu'}
key={item.id} key={item.id}
@@ -126,6 +159,7 @@ function GeneralPreferences(props) {
formik.setFieldValue(filedName, filed.name); formik.setFieldValue(filedName, filed.name);
}; };
}; };
const getSelectedItemLabel = (filedName, defaultLabel) => { const getSelectedItemLabel = (filedName, defaultLabel) => {
return typeof selectedItems[filedName] !== 'undefined' return typeof selectedItems[filedName] !== 'undefined'
? selectedItems[filedName].name ? selectedItems[filedName].name
@@ -140,42 +174,26 @@ function GeneralPreferences(props) {
<FormGroup <FormGroup
label={'Organization Name'} label={'Organization Name'}
inline={true} inline={true}
intent={ intent={errors.name && touched.name && Intent.DANGER}
errors.organization_name && helperText={<ErrorMessage name='name' {...formik} />}
touched.organization_name &&
Intent.DANGER
}
helperText={<ErrorMessage name='organization_name' {...formik} />}
> >
<InputGroup <InputGroup
medium={true} medium={'true'}
intent={ intent={errors.name && touched.name && Intent.DANGER}
errors.organization_name && {...formik.getFieldProps('name')}
touched.organization_name &&
Intent.DANGER
}
{...formik.getFieldProps('organization_name')}
/> />
</FormGroup> </FormGroup>
<FormGroup <FormGroup
label={'Organization Industry'} label={'Organization Industry'}
inline={true} inline={true}
intent={ intent={errors.industry && touched.industry && Intent.DANGER}
errors.organization_industry && helperText={<ErrorMessage name='industry' {...formik} />}
touched.organization_industry &&
Intent.DANGER
}
helperText={<ErrorMessage name='organization_industry' {...formik} />}
> >
<InputGroup <InputGroup
medium={true} medium={'true'}
intent={ intent={errors.industry && touched.industry && Intent.DANGER}
errors.organization_industry && {...formik.getFieldProps('industry')}
touched.organization_industry &&
Intent.DANGER
}
{...formik.getFieldProps('organization_industry')}
/> />
</FormGroup> </FormGroup>
@@ -187,26 +205,22 @@ function GeneralPreferences(props) {
Classes.FILL Classes.FILL
)} )}
inline={true} inline={true}
helperText={<ErrorMessage name='business_location' {...formik} />} helperText={<ErrorMessage name='location' {...formik} />}
intent={ intent={errors.location && touched.location && Intent.DANGER}
errors.business_location &&
touched.business_location &&
Intent.DANGER
}
> >
<Select <Select
items={businessLocation} items={businessLocation}
noResults={<MenuItem disabled={true} text='No result.' />} noResults={<MenuItem disabled={true} text='No result.' />}
itemRenderer={businessLocationItem} itemRenderer={businessLocationItem}
popoverProps={{ minimal: true }} popoverProps={{ minimal: true }}
onItemSelect={onItemsSelect('business_location')} onItemSelect={onItemsSelect('location')}
> >
<Button <Button
fill={true} fill={true}
rightIcon='caret-down' rightIcon='caret-down'
text={getSelectedItemLabel( text={getSelectedItemLabel(
'business_location', 'location',
'Business Location' organizationSettings.location
)} )}
/> />
</Select> </Select>
@@ -235,7 +249,10 @@ function GeneralPreferences(props) {
<Button <Button
fill={true} fill={true}
rightIcon='caret-down' rightIcon='caret-down'
text={getSelectedItemLabel('base_currency', 'Base Currency')} text={getSelectedItemLabel(
'base_currency',
organizationSettings.base_currency
)}
/> />
</Select> </Select>
</FormGroup> </FormGroup>
@@ -261,7 +278,10 @@ function GeneralPreferences(props) {
<Button <Button
fill={true} fill={true}
rightIcon='caret-down' rightIcon='caret-down'
text={getSelectedItemLabel('fiscal_year', 'Fiscal Year')} text={getSelectedItemLabel(
'fiscal_year',
organizationSettings.fiscal_year
)}
/> />
</Select> </Select>
</FormGroup> </FormGroup>
@@ -286,11 +306,13 @@ function GeneralPreferences(props) {
> >
<Button <Button
rightIcon='caret-down' rightIcon='caret-down'
text={getSelectedItemLabel('language', 'English')} text={getSelectedItemLabel(
'language',
organizationSettings.language
)}
/> />
</Select> </Select>
</FormGroup> </FormGroup>
<FormGroup <FormGroup
label={'Time Zone'} label={'Time Zone'}
inline={true} inline={true}
@@ -309,30 +331,30 @@ function GeneralPreferences(props) {
valueDisplayFormat='composite' valueDisplayFormat='composite'
/> />
</FormGroup> </FormGroup>
<FormGroup <FormGroup
label={'Date Format'} label={'Date Format'}
inline={true} inline={true}
className={classNames( className={classNames(
'form-group--date-format', 'form-group--language',
'form-group--select-list', 'form-group--select-list',
Classes.FILL Classes.FILL
)} )}
intent={errors.date_format && touched.data_Format && Intent.DANGER} intent={errors.date_format && touched.date_format && Intent.DANGER}
helperText={<ErrorMessage name='date_format' {...formik} />} helperText={<ErrorMessage name='date_format' {...formik} />}
minimal={true}
> >
<Select <Select
items={dateFormat} items={dateFormat}
noResults={<MenuItem disabled={true} text='No result.' />} noResults={<MenuItem disabled={true} text='No result.' />}
itemRenderer={data_Format} itemRenderer={date_format}
popoverProps={{ minimal: true }} popoverProp={{ minimal: true }}
onItemSelect={onItemsSelect('date_format')} onItemSelect={onItemsSelect('date_format')}
> >
<Button <Button
fill={true}
rightIcon='caret-down' rightIcon='caret-down'
text={getSelectedItemLabel('fiscal_year', 'Fiscal Year')} text={getSelectedItemLabel(
'date_format',
organizationSettings.date_format
)}
/> />
</Select> </Select>
</FormGroup> </FormGroup>
@@ -352,4 +374,4 @@ function GeneralPreferences(props) {
); );
} }
export default GeneralPreferences; export default compose(SettingsConnect)(GeneralPreferences);

View File

@@ -29,17 +29,18 @@ function UsersPreferences({
onChange={onChangeTabs}> onChange={onChangeTabs}>
<Tab id="users" title="Users" /> <Tab id="users" title="Users" />
<Tab id="roles" title="Roles" /> <Tab id="roles" title="Roles" />
</Tabs>
<div class="preferences__tabs-extra-actions"> <div class="preferences__tabs-extra-actions">
<Button <Button
intent={Intent.PRIMARY} intent={Intent.PRIMARY}
onClick={onClickNewUser}>New User</Button> onClick={onClickNewUser}>New invite</Button>
<Button <Button
intent={Intent.PRIMARY} intent={Intent.PRIMARY}
onClick={onClickNewUser}>New Role</Button> onClick={onClickNewUser}>New Role</Button>
</div> </div>
</Tabs>
</div> </div>
<PreferencesSubContent preferenceTab="users" /> <PreferencesSubContent preferenceTab="users" />
</div> </div>

View File

@@ -1,10 +1,6 @@
import React, {useState} from 'react'; import React, { useState, useMemo, useCallback } from 'react';
import {useAsync} from 'react-use'; import { useAsync } from 'react-use';
import { import DataTable from 'components/DataTable';
GridComponent,
ColumnsDirective,
ColumnDirective,
} from '@syncfusion/ej2-react-grids';
import { import {
Alert, Alert,
Popover, Popover,
@@ -17,9 +13,12 @@ import {
} from '@blueprintjs/core'; } from '@blueprintjs/core';
import Icon from 'components/Icon'; import Icon from 'components/Icon';
import LoadingIndicator from 'components/LoadingIndicator'; import LoadingIndicator from 'components/LoadingIndicator';
import {snakeCase} from 'lodash'; import { snakeCase } from 'lodash';
import connector from 'connectors/UsersList.connector'; import UserListConnect from 'connectors/UsersList.connector';
import AppToaster from 'components/AppToaster'; import AppToaster from 'components/AppToaster';
import { compose } from 'utils';
import DialogConnect from 'connectors/Dialog.connector';
import DashboardConnect from 'connectors/Dashboard.connector';
function UsersListPreferences({ function UsersListPreferences({
fetchUsers, fetchUsers,
@@ -27,22 +26,23 @@ function UsersListPreferences({
openDialog, openDialog,
closeDialog, closeDialog,
deleteUser, deleteUser,
onFetchData,
}) { }) {
const [deleteUserState, setDeleteUserState] = useState(false); const [deleteUserState, setDeleteUserState] = useState(false);
const [inactiveUserState, setInactiveUserState] = useState(false); const [inactiveUserState, setInactiveUserState] = useState(false);
const asyncHook = useAsync(async () => { const asyncHook = useAsync(async () => {
await Promise.all([ await Promise.all([fetchUsers()]);
fetchUsers(),
]);
}, []); }, []);
const onInactiveUser = (user) => { const onInactiveUser = (user) => {};
const onDeleteUser = (user) => {
setDeleteUserState(user);
};
const handleCancelUserDelete = () => {
setDeleteUserState(false);
}; };
const onDeleteUser = (user) => { setDeleteUserState(user); };
const handleCancelUserDelete = () => { setDeleteUserState(false); };
const onEditUser = (user) => () => { const onEditUser = (user) => () => {
const form = Object.keys(user).reduce((obj, key) => { const form = Object.keys(user).reduce((obj, key) => {
@@ -51,11 +51,13 @@ function UsersListPreferences({
return obj; return obj;
}, {}); }, {});
openDialog('user-form', { action: 'edit', user: form, }); openDialog('user-form', { action: 'edit', user: form });
}; };
const handleConfirmUserDelete = () => { const handleConfirmUserDelete = () => {
if (!deleteUserState) { return; } if (!deleteUserState) {
return;
}
deleteUser(deleteUserState.id).then((response) => { deleteUser(deleteUserState.id).then((response) => {
setDeleteUserState(false); setDeleteUserState(false);
@@ -65,79 +67,96 @@ function UsersListPreferences({
}); });
}; };
const actionMenuList = (user) => const actionMenuList = (user) => (
(<Menu> <Menu>
<MenuItem text="Edit User" onClick={onEditUser(user)} /> <MenuItem text='Edit User' onClick={onEditUser(user)} />
<MenuItem text="New Account" /> <MenuItem text='New Account' />
<MenuDivider /> <MenuDivider />
<MenuItem text="Inactivate User" onClick={() => onInactiveUser(user)} /> <MenuItem text='Inactivate User' onClick={() => onInactiveUser(user)} />
<MenuItem text="Delete User" onClick={() => onDeleteUser(user)} /> <MenuItem text='Delete User' onClick={() => onDeleteUser(user)} />
</Menu>); </Menu>
);
console.log(usersList, 'X');
const columns = useMemo(
() => [
{
id: 'full_name',
Header: 'Full Name',
accessor: 'full_name',
width: 170,
},
{
id: 'email',
Header: 'Email',
accessor: 'email',
width: 150,
},
{
id: 'phone_number',
Header: 'Phone Number',
accessor: 'phone_number',
width: 150,
},
{
id: 'active',
Header: 'Status',
accessor: (user) =>
user.active ? <span>Active</span> : <span>Inactivate</span>,
width: 50,
},
{
id: 'actions',
Header: '',
Cell: ({ cell }) => (
<Popover
content={actionMenuList(cell.row.original)}
position={Position.RIGHT_TOP}
>
<Button icon={<Icon icon='ellipsis-h' />} />
</Popover>
),
className: 'actions',
width: 50,
},
],
[actionMenuList]
);
const handelDataTableFetchData = useCallback(() => {
onFetchData && onFetchData();
}, []);
const columns = [
{
field: '',
headerText: 'Avatar',
},
{
field: 'fullName',
headerText: 'Full Name',
},
{
field: 'email',
headerText: 'Email',
},
{
field: 'phoneNumber',
headerText: 'Phone Number',
},
{
field: '',
headerText: 'Status',
template: (user) => user.active
? (<span>Active</span>) : (<span>Inactive</span>)
},
{
template: (user) => (
<Popover content={actionMenuList(user)} position={Position.RIGHT_BOTTOM}>
<Button icon={<Icon icon="ellipsis-h" />} />
</Popover>
),
}
]
return ( return (
<LoadingIndicator loading={asyncHook.loading}> <LoadingIndicator>
<GridComponent <DataTable
dataSource={{result: usersList.results}}> columns={columns}
data={usersList}
<ColumnsDirective> onFetchData={handelDataTableFetchData()}
{columns.map((column) => { manualSortBy={true}
return (<ColumnDirective expandable={false}
field={column.field} />
headerText={column.headerText}
template={column.template}
allowSorting={true}
customAttributes={column.customAttributes}
/>);
})}
</ColumnsDirective>
</GridComponent>
<Alert <Alert
cancelButtonText="Cancel" cancelButtonText='Cancel'
confirmButtonText="Move to Trash" confirmButtonText='Move to Trash'
icon="trash" icon='trash'
intent={Intent.DANGER} intent={Intent.DANGER}
isOpen={deleteUserState} isOpen={deleteUserState}
onCancel={handleCancelUserDelete} onCancel={handleCancelUserDelete}
onConfirm={handleConfirmUserDelete}> onConfirm={handleConfirmUserDelete}
>
<p> <p>
Are you sure you want to move <b>filename</b> to Trash? You will be able to restore it later, Are you sure you want to move <b>filename</b> to Trash? You will be
but it will become private to you. able to restore it later, but it will become private to you.
</p> </p>
</Alert> </Alert>
</LoadingIndicator> </LoadingIndicator>
); );
} }
export default connector(UsersListPreferences); export default compose(
UserListConnect,
DialogConnect,
DashboardConnect
)(UsersListPreferences);

View File

@@ -2,5 +2,6 @@ export default {
ITEMS_CATEGORY_LIST_SET: 'ITEMS_CATEGORY_LIST_SET', ITEMS_CATEGORY_LIST_SET: 'ITEMS_CATEGORY_LIST_SET',
ITEMS_CATEGORY_DATA_TABLE: 'ITEMS_CATEGORY_DATA_TABLE', ITEMS_CATEGORY_DATA_TABLE: 'ITEMS_CATEGORY_DATA_TABLE',
CATEGORY_DELETE: 'CATEGORY_DELETE', CATEGORY_DELETE: 'CATEGORY_DELETE',
CLEAR_CATEGORY_FORM_ERRORS: 'CLEAR_CATEGORY_FORM_ERRORS' CLEAR_CATEGORY_FORM_ERRORS: 'CLEAR_CATEGORY_FORM_ERRORS',
CATEGORY_COUNTER:'CATEGORY_COUNTER'
}; };

View File

@@ -0,0 +1,25 @@
import ApiService from 'services/ApiService';
import t from 'store/types';
export const submitOptions = ({ form }) => {
return (dispatch) => {
return ApiService.post('options', form);
};
};
export const FetchOptions = ({ form }) => {
return (dispatch) =>
new Promise((resolve, reject) => {
ApiService.get('options')
.then((response) => {
dispatch({
type: t.SETTING_SET,
options: response.data.options,
});
resolve(response);
})
.catch((error) => {
reject(error);
});
});
};

View File

@@ -1,16 +1,16 @@
import { createReducer } from '@reduxjs/toolkit'; import { createReducer } from '@reduxjs/toolkit';
import t from 'store/types'; import t from 'store/types';
import { optionsArrayToMap } from 'utils';
const initialState = { const initialState = {
data: { data: {
organization: { organization: {},
name: 'Bigcapital, Limited Liabilities',
},
}, },
}; };
export default createReducer(initialState, { export default createReducer(initialState, {
['asdfas']: (state, action) => { [t.SETTING_SET]: (state, action) => {
const { options } = action;
state.data.organization = optionsArrayToMap(options);
}, },
}); });

View File

@@ -1,5 +1,5 @@
export default { export default {
SETTING_LIST_SET: 'SETTING_LIST_SET',
CLEAR_OPTIONS_FORM_ERRORS: 'CLEAR_OPTIONS_FORM_ERRORS',
SETTING_SET: 'SETTING_SET',
}; };

View File

@@ -1,8 +1,10 @@
import { createReducer } from "@reduxjs/toolkit"; import { createReducer } from '@reduxjs/toolkit';
import t from 'store/types'; import t from 'store/types';
const initialState = { const initialState = {
list: {}, list: {
results: [],
},
userById: {}, userById: {},
}; };
@@ -14,7 +16,7 @@ export default createReducer(initialState, {
[t.USER_DETAILS_SET]: (state, action) => { [t.USER_DETAILS_SET]: (state, action) => {
state.userById[action.user.id] = action.user; state.userById[action.user.id] = action.user;
}, },
}) });
/** /**
* Retrieve the user details of the given user id, * Retrieve the user details of the given user id,

View File

@@ -1,9 +1,9 @@
@import './normalize.scss';
@import "./normalize.scss"; $pt-popover-box-shadow: 0 0 0 1px rgba(16, 22, 26, 0.02),
0 2px 4px rgba(16, 22, 26, 0.1), 0 8px 24px rgba(16, 22, 26, 0.1);
$pt-popover-box-shadow: 0 0 0 1px rgba(16, 22, 26, 0.02), 0 2px 4px rgba(16, 22, 26, 0.1), 0 8px 24px rgba(16, 22, 26, 0.1); @import '@blueprintjs/core/src/common/_variables.scss';
@import "@blueprintjs/core/src/common/_variables.scss";
// @import "@blueprintjs/core/src/common/colors.scss"; // @import "@blueprintjs/core/src/common/colors.scss";
$menu-item-color-hover: $light-gray4; $menu-item-color-hover: $light-gray4;
@@ -12,42 +12,46 @@ $menu-item-color-active: $light-gray3;
$breadcrumbs-collapsed-icon: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='#6B8193' enable-background='new 0 0 16 16' xml:space='preserve'><g><circle cx='2' cy='8.03' r='2'/><circle cx='14' cy='8.03' r='2'/><circle cx='8' cy='8.03' r='2'/></g></svg>"); $breadcrumbs-collapsed-icon: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='#6B8193' enable-background='new 0 0 16 16' xml:space='preserve'><g><circle cx='2' cy='8.03' r='2'/><circle cx='14' cy='8.03' r='2'/><circle cx='8' cy='8.03' r='2'/></g></svg>");
// Blueprint framework. // Blueprint framework.
@import "@blueprintjs/core/src/blueprint.scss"; @import '@blueprintjs/core/src/blueprint.scss';
@import "@blueprintjs/datetime/src/blueprint-datetime.scss"; @import '@blueprintjs/datetime/src/blueprint-datetime.scss';
@import "basscss"; @import 'basscss';
$pt-font-family: Noto Sans, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, Ubuntu, Cantarell, Open Sans, Helvetica Neue, Icons16, sans-serif; $pt-font-family: Noto Sans, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto,
Oxygen, Ubuntu, Cantarell, Open Sans, Helvetica Neue, Icons16, sans-serif;
@import "functions"; @import 'functions';
// Objects // Objects
@import "objects/form"; @import 'objects/form';
@import "objects/typography"; @import 'objects/typography';
@import "objects/buttons"; @import 'objects/buttons';
// Components // Components
@import "components/data-table"; @import 'components/data-table';
@import "components/dialog"; @import 'components/dialog';
@import 'components/custom-scrollbar';
// Pages // Pages
@import "pages/dashboard"; @import 'pages/dashboard';
@import "pages/accounts-chart"; @import 'pages/accounts-chart';
@import "pages/authentication"; @import 'pages/authentication';
@import "pages/expense-form"; @import 'pages/expense-form';
@import "pages/financial-statements"; @import 'pages/financial-statements';
@import "pages/make-journal-entries"; @import 'pages/make-journal-entries';
@import "pages/preferences"; @import 'pages/preferences';
@import "pages/view-form"; @import 'pages/view-form';
@import "pages/manual-journals"; @import 'pages/manual-journals';
@import "pages/item-category"; @import 'pages/item-category';
@import "pages/items"; @import 'pages/items';
@import 'pages/invite-form.scss';
@import "pages/currency"; @import "pages/currency";
// Views
@import "views/filter-dropdown";
@import "views/sidebar";
.#{$ns}-tooltip{ // Views
@import 'views/filter-dropdown';
@import 'views/sidebar';
.#{$ns}-tooltip {
box-shadow: none; box-shadow: none;
} }

View File

@@ -0,0 +1,53 @@
.ScrollbarsCustom {
position: 'relative';
width: 100%;
height: 100%;
}
.ScrollbarsCustom-Wrapper {
position: 'absolute';
top: 0;
left: 0;
bottom: 0;
right: 0;
}
.ScrollbarsCustom-Content {
box-sizing: 'border-box';
}
.ScrollbarsCustom-Track {
&.ScrollbarsCustom-TrackY,
&.ScrollbarsCustom-TrackX {
position: absolute;
overflow: hidden;
border-radius: 4px;
user-select: none;
}
&.ScrollbarsCustom-TrackX {
height: 10px;
width: calc(100% - 10px);
bottom: 0;
left: 5px;
}
&.ScrollbarsCustom-TrackY {
width: 10px;
height: calc(100% - 10px);
top: 5px;
right: 2px;
}
}
.ScrollbarsCustom-Thumb {
&.ScrollbarsCustom-ThumbX,
&.ScrollbarsCustom-ThumbY {
cursor: pointer;
border-radius: 4px;
}
&.ScrollbarsCustom-ThumbX {
height: 100%;
width: 0px;
}
&.ScrollbarsCustom-ThumbY {
height: 100%;
width: 8px;
}
}

View File

@@ -0,0 +1,47 @@
// .dialog--invite-form {
// }
.dialog--invite-form {
&.bp3-dialog {
width: 400px;
}
&:not(.dialog--loading) .bp3-dialog-body {
margin-bottom: 25px;
}
.bp3-dialog-body {
// margin-right: 50px;
.bp3-form-group.bp3-inline {
.bp3-label {
min-width: 70px;
}
&.form-group--email {
.bp3-form-content {
width: 250px;
}
}
}
.bp3-dialog-footer-actions {
margin-right: 30px;
display: flex;
justify-content: flex-end;
}
}
}
// .bp3-dialog-body {
// .bp3-form-group.bp3-inline {
// .bp3-label {
// min-width: 100px;
// }
// .bp3-form-content {
// width: 250px;
// }
// }
// }
// .bp3-dialog-footer-actions {
// display: flex;
// justify-content: flex-end;
// margin-right: 100px;
// }

View File

@@ -90,3 +90,7 @@
} }
} }
} }
.preferences__tabs-extra-actions {
position: absolute;
right: 0;
}

View File

@@ -1,22 +1,37 @@
$sidebar-background: #01194e;
$sidebar-background: #01194E;
$sidebar-text-color: #fff; $sidebar-text-color: #fff;
$sidebar-width: 220px; $sidebar-width: 220px;
$sidebar-menu-item-color: #b8c0d5; $sidebar-menu-item-color: #b8c0d5;
$sidebar-popover-submenu-bg: rgb(1, 20, 62); $sidebar-popover-submenu-bg: rgb(1, 20, 62);
.sidebar{ .sidebar {
background: $sidebar-background; background: $sidebar-background;
color: $sidebar-text-color; color: $sidebar-text-color;
width: $sidebar-width; width: $sidebar-width;
position: fixed; position: fixed;
height: 100%; height: 100%;
&__inner{ .ScrollbarsCustom-Track {
overflow-y: scroll; &.ScrollbarsCustom-TrackY,
overflow-x: hidden; &.ScrollbarsCustom-TrackX{
height: 100%; background: rgba(0, 0, 0, 0);
}
}
.ScrollbarsCustom-Thumb{
&.ScrollbarsCustom-ThumbX,
&.ScrollbarsCustom-ThumbY {
background: rgba(0, 0, 0, 0);
}
}
&:hover {
.ScrollbarsCustom-Thumb{
&.ScrollbarsCustom-ThumbX,
&.ScrollbarsCustom-ThumbY {
background: rgba(255, 255, 255, 0.25);
}
}
} }
&__head{ &__head{
padding: 16px 12px; padding: 16px 12px;
@@ -30,14 +45,14 @@ $sidebar-popover-submenu-bg: rgb(1, 20, 62);
} }
} }
&-menu{ &-menu {
background: transparent; background: transparent;
padding: 0; padding: 0;
min-width: $sidebar-width; min-width: $sidebar-width;
border-radius: 0; border-radius: 0;
padding-bottom: 2rem; padding-bottom: 2rem;
.#{$ns}-menu-item{ .#{$ns}-menu-item {
color: $sidebar-menu-item-color; color: $sidebar-menu-item-color;
border-radius: 0; border-radius: 0;
padding: 10px 16px; padding: 10px 16px;
@@ -45,64 +60,63 @@ $sidebar-popover-submenu-bg: rgb(1, 20, 62);
font-weight: 400; font-weight: 400;
&:hover, &:hover,
&.bp3-active{ &.bp3-active {
background: #012470; background: #012470;
color: #c1c9dd; color: #c1c9dd;
} }
&:focus, &:focus,
&:active{ &:active {
background: #01143e; background: #01143e;
} }
> .#{$ns}-icon{ > .#{$ns}-icon {
color: #767b9b; color: #767b9b;
margin-right: 14px; margin-right: 14px;
margin-top: 0; margin-top: 0;
} }
> .#{$ns}-icon-caret-right{ > .#{$ns}-icon-caret-right {
margin-right: -4px; margin-right: -4px;
margin-top: 3px; margin-top: 3px;
color: #42547b; color: #42547b;
} }
} }
.#{$ns}-submenu{ .#{$ns}-submenu {
.#{$ns}-collapse {
.#{$ns}-collapse{
border-left: 2px solid rgba(255, 255, 255, 0.15); border-left: 2px solid rgba(255, 255, 255, 0.15);
&-body{ &-body {
background-color: rgb(11, 34, 85); background-color: rgb(11, 34, 85);
padding-bottom: 6px; padding-bottom: 6px;
padding-top: 6px; padding-top: 6px;
} }
.#{$ns}-menu-item{ .#{$ns}-menu-item {
padding: 7px 16px 7px 18px; padding: 7px 16px 7px 18px;
font-size: 15px; font-size: 15px;
color: #8a95b6; color: #8a95b6;
&:hover, &:hover,
&.bp3-active{ &.bp3-active {
background: transparent; background: transparent;
color: #C5CBE3; color: #c5cbe3;
} }
} }
} }
.#{$ns}-popover{ .#{$ns}-popover {
padding: 0; padding: 0;
&-content{ &-content {
box-shadow: 0 0 0; box-shadow: 0 0 0;
} }
} }
} }
.#{$ns}-popover-target.#{$ns}-popover-open .#{$ns}-menu-item{ .#{$ns}-popover-target.#{$ns}-popover-open .#{$ns}-menu-item {
color: $sidebar-menu-item-color; color: $sidebar-menu-item-color;
} }
.#{$ns}-menu-divider{ .#{$ns}-menu-divider {
border-top-color: #1D366A; border-top-color: #1d366a;
color: #6B708C; color: #6b708c;
margin: 4px 0; margin: 4px 0;
} }
} }