- Data table sticky header.

- Mini sidebar toggle.
- Refactor withDashboard and withDashboardActions.
This commit is contained in:
Ahmed Bouhuolia
2020-05-31 15:57:02 +02:00
parent c1659d191f
commit 2a466ce2da
49 changed files with 1045 additions and 669 deletions

View File

@@ -77,12 +77,15 @@
"react-redux": "^7.1.3", "react-redux": "^7.1.3",
"react-router-breadcrumbs-hoc": "^3.2.10", "react-router-breadcrumbs-hoc": "^3.2.10",
"react-router-dom": "^5.1.2", "react-router-dom": "^5.1.2",
"react-scroll-sync": "^0.7.1",
"react-scrollbars-custom": "^4.0.21", "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-table-sticky": "^1.1.2",
"react-use": "^13.26.1", "react-use": "^13.26.1",
"react-window": "^1.8.5", "react-window": "^1.8.5",
"redux": "^4.0.5", "redux": "^4.0.5",
"redux-localstorage": "^0.4.1",
"redux-thunk": "^2.3.0", "redux-thunk": "^2.3.0",
"resolve": "1.15.0", "resolve": "1.15.0",
"resolve-url-loader": "3.1.1", "resolve-url-loader": "3.1.1",

View File

@@ -9,7 +9,6 @@ import PrivateRoute from 'components/PrivateRoute';
import Authentication from 'components/Authentication'; import Authentication from 'components/Authentication';
import Dashboard from 'components/Dashboard/Dashboard'; import Dashboard from 'components/Dashboard/Dashboard';
import GlobalErrors from 'containers/GlobalErrors/GlobalErrors'; import GlobalErrors from 'containers/GlobalErrors/GlobalErrors';
import AuthenticationDialogs from 'containers/Authentication/AuthenticationDialogs';
import messages from 'lang/en'; import messages from 'lang/en';
import 'style/App.scss'; import 'style/App.scss';
@@ -30,7 +29,6 @@ function App({ locale }) {
<Switch> <Switch>
<Route path={'/auth'}> <Route path={'/auth'}>
<Authentication /> <Authentication />
<AuthenticationDialogs />
</Route> </Route>
<Route path={'/'}> <Route path={'/'}>

View File

@@ -1,23 +1,30 @@
import React from 'react'; import React from 'react';
import { Switch, Route } from 'react-router'; import { Switch, Route } from 'react-router';
import classNames from 'classnames';
import Sidebar from 'components/Sidebar/Sidebar'; import Sidebar from 'components/Sidebar/Sidebar';
import DashboardContent from 'components/Dashboard/DashboardContent'; import DashboardContent from 'components/Dashboard/DashboardContent';
import DialogsContainer from 'components/DialogsContainer'; import DialogsContainer from 'components/DialogsContainer';
import PreferencesContent from 'components/Preferences/PreferencesContent'; import PreferencesContent from 'components/Preferences/PreferencesContent';
import PreferencesSidebar from 'components/Preferences/PreferencesSidebar'; import PreferencesSidebar from 'components/Preferences/PreferencesSidebar';
import Search from 'containers/GeneralSearch/Search'; import Search from 'containers/GeneralSearch/Search';
import withDashboard from 'containers/Dashboard/withDashboard';
export default function Dashboard() { import { compose } from 'utils';
function Dashboard({ sidebarExpended }) {
return ( return (
<div className='dashboard'> <div className={classNames('dashboard', {
'has-mini-sidebar': !sidebarExpended,
})}>
<Switch> <Switch>
<Route path='/preferences'> <Route path="/preferences">
<Sidebar /> <Sidebar />
<PreferencesSidebar /> <PreferencesSidebar />
<PreferencesContent /> <PreferencesContent />
</Route> </Route>
<Route path='/'> <Route path="/">
<Sidebar /> <Sidebar />
<DashboardContent /> <DashboardContent />
</Route> </Route>
@@ -28,3 +35,9 @@ export default function Dashboard() {
</div> </div>
); );
} }
export default compose(
withDashboard(({ sidebarExpended }) => ({
sidebarExpended,
})),
)(Dashboard);

View File

@@ -14,14 +14,23 @@ import DashboardBreadcrumbs from 'components/Dashboard/DashboardBreadcrumbs';
import SearchConnect from 'connectors/Search.connect'; import SearchConnect from 'connectors/Search.connect';
import Icon from 'components/Icon'; import Icon from 'components/Icon';
import withDashboardActions from 'containers/Dashboard/withDashboardActions';
import withDashboard from 'containers/Dashboard/withDashboard';
import { compose } from 'utils'; import { compose } from 'utils';
function DashboardTopbar({ function DashboardTopbar({
// #withDashboard
pageTitle, pageTitle,
pageSubtitle, pageSubtitle,
editViewId, editViewId,
globalSearchShow,
// #withDashboardActions
toggleSidebarExpend,
// #withGlobalSearch
openGlobalSearch, openGlobalSearch,
}) { }) {
const history = useHistory(); const history = useHistory();
@@ -38,11 +47,15 @@ function DashboardTopbar({
onClick={handlerClickEditView} onClick={handlerClickEditView}
/> />
); );
const handleSidebarToggleBtn = () => {
toggleSidebarExpend();
};
return ( return (
<div class='dashboard__topbar'> <div class='dashboard__topbar'>
<div class='dashboard__topbar-left'> <div class='dashboard__topbar-left'>
<div class='dashboard__topbar-sidebar-toggle'> <div class='dashboard__topbar-sidebar-toggle'>
<Button minimal={true}> <Button minimal={true} onClick={handleSidebarToggleBtn}>
<svg <svg
xmlns='http://www.w3.org/2000/svg' xmlns='http://www.w3.org/2000/svg'
width='20' width='20'
@@ -106,13 +119,10 @@ function DashboardTopbar({
); );
} }
const mapStateToProps = (state) => ({
pageTitle: state.dashboard.pageTitle,
pageSubtitle: state.dashboard.pageSubtitle,
editViewId: state.dashboard.topbarEditViewId,
});
export default compose( export default compose(
SearchConnect, SearchConnect,
connect(mapStateToProps) withDashboard(({ pageTitle, pageSubtitle, editViewId }) => ({
pageTitle, pageSubtitle, editViewId
})),
withDashboardActions,
)(DashboardTopbar); )(DashboardTopbar);

View File

@@ -1,4 +1,4 @@
import React, {useEffect, useRef, useCallback} from 'react'; import React, { useEffect, useRef, useCallback } from 'react';
import { import {
useTable, useTable,
useExpanded, useExpanded,
@@ -6,19 +6,22 @@ import {
usePagination, usePagination,
useResizeColumns, useResizeColumns,
useSortBy, useSortBy,
useFlexLayout useFlexLayout,
} from 'react-table'; } from 'react-table';
import { Checkbox, Spinner } from '@blueprintjs/core'; import { Checkbox, Spinner } from '@blueprintjs/core';
import classnames from 'classnames'; import classnames from 'classnames';
import { FixedSizeList } from 'react-window' import { FixedSizeList } from 'react-window';
import { useSticky } from 'react-table-sticky';
import { ScrollSync, ScrollSyncPane } from 'react-scroll-sync';
import { ConditionalWrapper } from 'utils'; import { ConditionalWrapper } from 'utils';
import { useUpdateEffect } from 'hooks'; import { useUpdateEffect } from 'hooks';
import { If } from 'components'; import { If } from 'components';
const IndeterminateCheckbox = React.forwardRef( const IndeterminateCheckbox = React.forwardRef(
({ indeterminate, ...rest }, ref) => { ({ indeterminate, ...rest }, ref) => {
return (<Checkbox indeterminate={indeterminate} {...rest} />); return <Checkbox indeterminate={indeterminate} {...rest} />;
} },
); );
export default function DataTable({ export default function DataTable({
@@ -34,11 +37,11 @@ export default function DataTable({
noResults = 'This report does not contain any data.', noResults = 'This report does not contain any data.',
expanded = {}, expanded = {},
rowClassNames, rowClassNames,
stickyHeader = true, sticky = false,
virtualizedRows = false, virtualizedRows = false,
fixedSizeHeight = 100, fixedSizeHeight = 100,
fixedItemSize = 30, fixedItemSize = 30,
payload, payload,
expandable = false, expandable = false,
expandToggleColumn = 2, expandToggleColumn = 2,
noInitialFetch = false, noInitialFetch = false,
@@ -54,9 +57,10 @@ export default function DataTable({
selectedFlatRows, selectedFlatRows,
getToggleAllRowsExpandedProps, getToggleAllRowsExpandedProps,
isAllRowsExpanded, isAllRowsExpanded,
totalColumnsWidth,
// Get the state from the instance // Get the state from the instance
state: { pageIndex, pageSize, sortBy, selectedRowIds}, state: { pageIndex, pageSize, sortBy, selectedRowIds },
} = useTable( } = useTable(
{ {
columns, columns,
@@ -67,7 +71,7 @@ export default function DataTable({
// This means we'll also have to provide our own // This means we'll also have to provide our own
// pageCount. // pageCount.
// pageCount: controlledPageCount, // pageCount: controlledPageCount,
getSubRows: row => row.children, getSubRows: (row) => row.children,
manualSortBy, manualSortBy,
expandSubRows, expandSubRows,
payload, payload,
@@ -79,111 +83,150 @@ export default function DataTable({
usePagination, usePagination,
useResizeColumns, useResizeColumns,
useFlexLayout, useFlexLayout,
hooks => { useSticky,
hooks.visibleColumns.push(columns => [ (hooks) => {
hooks.visibleColumns.push((columns) => [
// Let's make a column for selection // Let's make a column for selection
...(selectionColumn) ? [{ ...(selectionColumn
id: 'selection', ? [
disableResizing: true, {
minWidth: 42, id: 'selection',
width: 42, disableResizing: true,
maxWidth: 42, minWidth: 42,
// The header can use the table's getToggleAllRowsSelectedProps method width: 42,
// to render a checkbox maxWidth: 42,
Header: ({ getToggleAllRowsSelectedProps }) => ( // The header can use the table's getToggleAllRowsSelectedProps method
<div> // to render a checkbox
<IndeterminateCheckbox {...getToggleAllRowsSelectedProps()} /> Header: ({ getToggleAllRowsSelectedProps }) => (
</div> <div>
), <IndeterminateCheckbox
// The cell can use the individual row's getToggleRowSelectedProps method {...getToggleAllRowsSelectedProps()}
// to the render a checkbox />
Cell: ({ row }) => ( </div>
<div> ),
<IndeterminateCheckbox {...row.getToggleRowSelectedProps()} /> // The cell can use the individual row's getToggleRowSelectedProps method
</div> // to the render a checkbox
), Cell: ({ row }) => (
className: 'selection', <div>
...(typeof selectionColumn === 'object') ? selectionColumn : {}, <IndeterminateCheckbox
}] : [], {...row.getToggleRowSelectedProps()}
/>
</div>
),
className: 'selection',
...(typeof selectionColumn === 'object' ? selectionColumn : {}),
},
]
: []),
...columns, ...columns,
]) ]);
} },
); );
const isInitialMount = useRef(noInitialFetch); const isInitialMount = useRef(noInitialFetch);
// When these table states change, fetch new data! // When these table states change, fetch new data!
useEffect(() => { useEffect(() => {
if (isInitialMount.current) { if (isInitialMount.current) {
isInitialMount.current = false; isInitialMount.current = false;
} else { } else {
onFetchData && onFetchData({ pageIndex, pageSize, sortBy }) onFetchData && onFetchData({ pageIndex, pageSize, sortBy });
} }
}, [pageIndex, pageSize, sortBy,onFetchData]); }, [pageIndex, pageSize, sortBy, onFetchData]);
useUpdateEffect(() => { useUpdateEffect(() => {
onSelectedRowsChange && onSelectedRowsChange(selectedFlatRows); onSelectedRowsChange && onSelectedRowsChange(selectedFlatRows);
}, [selectedRowIds, onSelectedRowsChange]); }, [selectedRowIds, onSelectedRowsChange]);
// Renders table cell. // Renders table cell.
const RenderCell = useCallback(({ row, cell, index }) => ( const RenderCell = useCallback(
<ConditionalWrapper ({ row, cell, index }) => (
condition={expandToggleColumn === index && expandable} <ConditionalWrapper
wrapper={(children) => (<div style={{ condition={expandToggleColumn === index && expandable}
'padding-left': `${row.depth * 1.5}rem`, wrapper={(children) => (
}}>{children}</div>)} <div
> style={{
{ 'padding-left': `${row.depth * 1.5}rem`,
// Use the row.canExpand and row.getToggleRowExpandedProps prop getter }}
// to build the toggle for expanding a row >
(row.canExpand && expandable && index === expandToggleColumn) && ( {children}
<span {...row.getToggleRowExpandedProps({ </div>
className: 'expand-toggle', )}
})}> >
<span className={classnames({ {
'arrow-down': row.isExpanded, // Use the row.canExpand and row.getToggleRowExpandedProps prop getter
'arrow-right': !row.isExpanded, // to build the toggle for expanding a row
})} /> row.canExpand && expandable && index === expandToggleColumn && (
</span> <span
) {...row.getToggleRowExpandedProps({
} className: 'expand-toggle',
{ cell.render('Cell') } })}
</ConditionalWrapper> >
), [expandable, expandToggleColumn]); <span
className={classnames({
'arrow-down': row.isExpanded,
'arrow-right': !row.isExpanded,
})}
/>
</span>
)
}
{cell.render('Cell')}
</ConditionalWrapper>
),
[expandable, expandToggleColumn],
);
// Renders table row. // Renders table row.
const RenderRow = useCallback(({ style = {}, row }) => { const RenderRow = useCallback(
prepareRow(row); ({ style = {}, row }) => {
const rowClasses = rowClassNames && rowClassNames(row); prepareRow(row);
const rowClasses = rowClassNames && rowClassNames(row);
return ( return (
<div {...row.getRowProps({ <div
className: classnames('tr', rowClasses), style {...row.getRowProps({
})}> className: classnames('tr', rowClasses),
{row.cells.map((cell, i) => { style,
const index = i + 1; })}
return <div {...cell.getCellProps({ >
className: classnames(cell.column.className || '', 'td'), {row.cells.map((cell, i) => {
})}> const index = i + 1;
{ RenderCell({ cell, row, index }) } return (
</div> <div
})} {...cell.getCellProps({
</div>); className: classnames(cell.column.className || '', 'td'),
}, [prepareRow, rowClassNames, expandable, RenderCell, expandToggleColumn]); })}
>
{RenderCell({ cell, row, index })}
</div>
);
})}
</div>
);
},
[prepareRow, rowClassNames, expandable, RenderCell, expandToggleColumn],
);
// Renders virtualize circle table rows. // Renders virtualize circle table rows.
const RenderVirtualizedRows = useCallback(({ index, style }) => { const RenderVirtualizedRows = useCallback(
const row = rows[index]; ({ index, style }) => {
return RenderRow({ row, style }); const row = rows[index];
}, [RenderRow, rows]); return RenderRow({ row, style });
},
[RenderRow, rows],
);
const RenderPage = useCallback(({ style, index } = {}) => { const RenderPage = useCallback(
return page.map((row, index) => RenderRow({ row })); ({ style, index } = {}) => {
}, [RenderRow, page]); return page.map((row, index) => RenderRow({ row }));
},
[RenderRow, page],
);
// Renders fixed size tbody. // Renders fixed size tbody.
const RenderTBody = useCallback(() => { const RenderTBody = useCallback(() => {
return (virtualizedRows) ? ( return virtualizedRows ? (
<FixedSizeList <FixedSizeList
height={fixedSizeHeight} height={fixedSizeHeight}
itemCount={rows.length} itemCount={rows.length}
@@ -191,79 +234,109 @@ export default function DataTable({
> >
{RenderVirtualizedRows} {RenderVirtualizedRows}
</FixedSizeList> </FixedSizeList>
) : RenderPage(); ) : (
}, [fixedSizeHeight, rows, fixedItemSize, virtualizedRows, RenderPage()
RenderVirtualizedRows, RenderPage]); );
}, [
fixedSizeHeight,
rows,
fixedItemSize,
virtualizedRows,
RenderVirtualizedRows,
RenderPage,
]);
return ( return (
<div className={classnames( <div
'bigcapital-datatable', className={classnames('bigcapital-datatable', className, {
className, 'has-sticky': sticky,
{
'has-sticky-header': stickyHeader,
'is-expandable': expandable, 'is-expandable': expandable,
'has-virtualized-rows': virtualizedRows, 'has-virtualized-rows': virtualizedRows,
})}> })}
<div {...getTableProps()} className="table"> >
<div className="thead"> <ScrollSync>
{headerGroups.map(headerGroup => ( <div
<div {...headerGroup.getHeaderGroupProps()} className="tr"> {...getTableProps({ style: { minWidth: 'none' } })}
{headerGroup.headers.map((column, index) => ( className="table"
<div {...column.getHeaderProps({ >
className: classnames(column.className || '', 'th'), <ScrollSyncPane>
})}> <div className="thead">
{(expandable && (index + 1) === expandToggleColumn) && ( {headerGroups.map((headerGroup) => (
<span <div {...headerGroup.getHeaderGroupProps()} className="tr">
{...getToggleAllRowsExpandedProps()} {headerGroup.headers.map((column, index) => (
className="expand-toggle">
<span className={classnames({
'arrow-down': isAllRowsExpanded,
'arrow-right': !isAllRowsExpanded,
})} />
</span>)}
<div {...column.getSortByToggleProps()}>
{column.render('Header')}
{column.isSorted && (
<span className={classnames({
'sort-icon--desc': column.isSortedDesc,
'sort-icon--asc': !column.isSortedDesc,
}, 'sort-icon')}>
</span>
)}
</div>
{column.canResize && (
<div <div
{...column.getResizerProps()} {...column.getHeaderProps({
className={`resizer ${ className: classnames(column.className || '', 'th'),
column.isResizing ? 'isResizing' : '' })}
}`}> >
<div class="inner-resizer" /> {expandable && index + 1 === expandToggleColumn && (
<span
{...getToggleAllRowsExpandedProps()}
className="expand-toggle"
>
<span
className={classnames({
'arrow-down': isAllRowsExpanded,
'arrow-right': !isAllRowsExpanded,
})}
/>
</span>
)}
<div {...column.getSortByToggleProps()}>
{column.render('Header')}
{column.isSorted && (
<span
className={classnames(
{
'sort-icon--desc': column.isSortedDesc,
'sort-icon--asc': !column.isSortedDesc,
},
'sort-icon',
)}
></span>
)}
</div>
{column.canResize && (
<div
{...column.getResizerProps()}
className={`resizer ${
column.isResizing ? 'isResizing' : ''
}`}
>
<div class="inner-resizer" />
</div>
)}
</div> </div>
)} ))}
</div> </div>
))} ))}
</div> </div>
))} </ScrollSyncPane>
</div>
<div {...getTableBodyProps()} className="tbody">
<If condition={!loading}>
{ RenderTBody() }
</If>
<If condition={!loading && (page.length === 0)}>
<div className={'tr no-results'}>
<div class="td">{ noResults }</div>
</div>
</If>
<If condition={loading}> <ScrollSyncPane>
<div class="loading"><Spinner size={spinnerProps.size} /></div> <div {...getTableBodyProps()} className="tbody">
</If> <div class="tbody-inner" style={{ minWidth: totalColumnsWidth }}>
<If condition={!loading}>{RenderTBody()}</If>
<If condition={!loading && page.length === 0}>
<div className={'tr no-results'}>
<div class="td">{noResults}</div>
</div>
</If>
<If condition={loading}>
<div class="loading">
<Spinner size={spinnerProps.size} />
</div>
</If>
</div>
</div>
</ScrollSyncPane>
</div> </div>
</div> </ScrollSync>
</div> </div>
) );
} }

View File

@@ -136,6 +136,7 @@ export default class MenuItem extends AbstractPureComponent2 {
intent, intent,
labelClassName, labelClassName,
labelElement, labelElement,
itemClassName,
multiline, multiline,
popoverProps, popoverProps,
shouldDismissPopover, shouldDismissPopover,
@@ -185,7 +186,7 @@ export default class MenuItem extends AbstractPureComponent2 {
hasSubmenu ? <Icon icon="caret-right" iconSize={caretIconSize} /> : undefined, hasSubmenu ? <Icon icon="caret-right" iconSize={caretIconSize} /> : undefined,
); );
const liClasses = classNames({ [Classes.MENU_SUBMENU]: hasSubmenu }); const liClasses = classNames({ [Classes.MENU_SUBMENU]: hasSubmenu }, itemClassName);
return <li className={liClasses}>{ return <li className={liClasses}>{
(dropdownType === 'collapse') ? (dropdownType === 'collapse') ?
this.maybeRenderCollapse(target, children) : this.maybeRenderCollapse(target, children) :

View File

@@ -1,12 +1,41 @@
import * as React from 'react'; import * as React from 'react';
import { Scrollbar } from 'react-scrollbars-custom'; import { Scrollbar } from 'react-scrollbars-custom';
import classNames from 'classnames';
export default function SidebarContainer(props) { import withDashboardActions from 'containers/Dashboard/withDashboardActions';
import withDashboard from 'containers/Dashboard/withDashboard';
import { compose } from 'utils';
function SidebarContainer({
// #ownProps
children,
// #withDashboardActions
toggleSidebarExpend,
// #withDashboard
sidebarExpended,
}) {
return ( return (
<div className='sidebar' id='sidebar'> <div
<Scrollbar noDefaultStyles={true}> className={classNames('sidebar', {
<div className='sidebar__inner'>{props.children}</div> 'sidebar--mini-sidebar': !sidebarExpended,
</Scrollbar> })}
id="sidebar"
>
<div className={'sidebar__scroll-wrapper'}>
<Scrollbar noDefaultStyles={true}>
<div className="sidebar__inner">{children}</div>
</Scrollbar>
</div>
</div> </div>
); );
} }
export default compose(
withDashboardActions,
withDashboard(({ sidebarExpended }) => ({
sidebarExpended,
})),
)(SidebarContainer);

View File

@@ -36,7 +36,10 @@ export default function SidebarMenu() {
caretIconSize={15} caretIconSize={15}
onClick={handleItemClick} onClick={handleItemClick}
callapseActive={!!isActive} callapseActive={!!isActive}
className={classNames({ 'is-active': isActive })} /> itemClassName={classNames({
'is-active': isActive,
'has-icon': !children && item.icon,
})} />
); );
}); });
}; };

View File

@@ -1,6 +1,12 @@
import React, {useMemo, useState, useEffect, useRef, useCallback} from 'react'; import React, {
useMemo,
useState,
useEffect,
useRef,
useCallback,
} from 'react';
import * as Yup from 'yup'; import * as Yup from 'yup';
import { useFormik } from "formik"; import { useFormik } from 'formik';
import moment from 'moment'; import moment from 'moment';
import { Intent } from '@blueprintjs/core'; import { Intent } from '@blueprintjs/core';
import { useIntl } from 'react-intl'; import { useIntl } from 'react-intl';
@@ -13,16 +19,18 @@ import MakeJournalEntriesTable from './MakeJournalEntriesTable';
import withJournalsActions from 'containers/Accounting/withJournalsActions'; import withJournalsActions from 'containers/Accounting/withJournalsActions';
import withManualJournalDetail from 'containers/Accounting/withManualJournalDetail'; import withManualJournalDetail from 'containers/Accounting/withManualJournalDetail';
import withAccountsActions from 'containers/Accounts/withAccountsActions'; import withAccountsActions from 'containers/Accounts/withAccountsActions';
import withDashboardActions from 'containers/Dashboard/withDashboard'; import withDashboardActions from 'containers/Dashboard/withDashboardActions';
import AppToaster from 'components/AppToaster'; import AppToaster from 'components/AppToaster';
import Dragzone from 'components/Dragzone'; import Dragzone from 'components/Dragzone';
import MediaConnect from 'connectors/Media.connect'; import MediaConnect from 'connectors/Media.connect';
import useMedia from 'hooks/useMedia'; import useMedia from 'hooks/useMedia';
import {compose} from 'utils'; import { compose } from 'utils';
/**
* Journal entries form.
*/
function MakeJournalEntriesForm({ function MakeJournalEntriesForm({
// #withMedia // #withMedia
requestSubmitMedia, requestSubmitMedia,
@@ -39,10 +47,16 @@ function MakeJournalEntriesForm({
manualJournalId, manualJournalId,
manualJournal, manualJournal,
onFormSubmit, onFormSubmit,
onCancelForm, onCancelForm,
}) { }) {
const { formatMessage } = useIntl(); const { formatMessage } = useIntl();
const { setFiles, saveMedia, deletedFiles, setDeletedFiles, deleteMedia } = useMedia({ const {
setFiles,
saveMedia,
deletedFiles,
setDeletedFiles,
deleteMedia,
} = useMedia({
saveCallback: requestSubmitMedia, saveCallback: requestSubmitMedia,
deleteCallback: requestDeleteMedia, deleteCallback: requestDeleteMedia,
}); });
@@ -51,79 +65,97 @@ function MakeJournalEntriesForm({
}, []); }, []);
const savedMediaIds = useRef([]); const savedMediaIds = useRef([]);
const clearSavedMediaIds = () => { savedMediaIds.current = []; } const clearSavedMediaIds = () => {
savedMediaIds.current = [];
};
useEffect(() => { useEffect(() => {
if (manualJournal && manualJournal.id) { if (manualJournal && manualJournal.id) {
changePageTitle(formatMessage({id:'edit_journal'})); changePageTitle(formatMessage({ id: 'edit_journal' }));
changePageSubtitle(`No. ${manualJournal.journal_number}`); changePageSubtitle(`No. ${manualJournal.journal_number}`);
} else { } else {
changePageTitle(formatMessage({id:'new_journal'})); changePageTitle(formatMessage({ id: 'new_journal' }));
} }
}, [changePageTitle, changePageSubtitle, manualJournal,formatMessage]); }, [changePageTitle, changePageSubtitle, manualJournal, formatMessage]);
const validationSchema = Yup.object().shape({ const validationSchema = Yup.object().shape({
journal_number: Yup.string().required().label(formatMessage({id:'journal_number_'})), journal_number: Yup.string()
date: Yup.date().required().label(formatMessage({id:'date'})), .required()
.label(formatMessage({ id: 'journal_number_' })),
date: Yup.date()
.required()
.label(formatMessage({ id: 'date' })),
reference: Yup.string(), reference: Yup.string(),
description: Yup.string(), description: Yup.string(),
entries: Yup.array().of( entries: Yup.array().of(
Yup.object().shape({ Yup.object().shape({
credit: Yup.number().nullable(), credit: Yup.number().nullable(),
debit: Yup.number().nullable(), debit: Yup.number().nullable(),
account_id: Yup.number().nullable().when(['credit', 'debit'], { account_id: Yup.number()
is: (credit, debit) => credit || debit, .nullable()
then: Yup.number().required(), .when(['credit', 'debit'], {
}), is: (credit, debit) => credit || debit,
then: Yup.number().required(),
}),
note: Yup.string().nullable(), note: Yup.string().nullable(),
}), }),
) ),
}); });
const saveInvokeSubmit = useCallback((payload) => { const saveInvokeSubmit = useCallback(
onFormSubmit && onFormSubmit(payload) (payload) => {
}, [onFormSubmit]); onFormSubmit && onFormSubmit(payload);
},
[onFormSubmit],
);
const [payload, setPayload] = useState({}); const [payload, setPayload] = useState({});
const defaultEntry = useMemo(() => ({ const defaultEntry = useMemo(
account_id: null, () => ({
credit: 0, account_id: null,
debit: 0, credit: 0,
note: '', debit: 0,
}), []); note: '',
}),
[],
);
const defaultInitialValues = useMemo(() => ({ const defaultInitialValues = useMemo(
journal_number: '', () => ({
date: moment(new Date()).format('YYYY-MM-DD'), journal_number: '',
description: '', date: moment(new Date()).format('YYYY-MM-DD'),
reference: '', description: '',
entries: [ reference: '',
defaultEntry, entries: [defaultEntry, defaultEntry, defaultEntry, defaultEntry],
defaultEntry, }),
defaultEntry, [defaultEntry],
defaultEntry, );
],
}), [defaultEntry]);
const initialValues = useMemo(() => ({ const initialValues = useMemo(
...(manualJournal) ? { () => ({
...pick(manualJournal, Object.keys(defaultInitialValues)), ...(manualJournal
entries: manualJournal.entries.map((entry) => ({ ? {
...pick(entry, Object.keys(defaultEntry)), ...pick(manualJournal, Object.keys(defaultInitialValues)),
})), entries: manualJournal.entries.map((entry) => ({
} : { ...pick(entry, Object.keys(defaultEntry)),
...defaultInitialValues, })),
} }
}), [manualJournal, defaultInitialValues, defaultEntry]); : {
...defaultInitialValues,
}),
}),
[manualJournal, defaultInitialValues, defaultEntry],
);
const initialAttachmentFiles = useMemo(() => { const initialAttachmentFiles = useMemo(() => {
return manualJournal && manualJournal.media return manualJournal && manualJournal.media
? manualJournal.media.map((attach) => ({ ? manualJournal.media.map((attach) => ({
preview: attach.attachment_file, preview: attach.attachment_file,
uploaded: true, uploaded: true,
metadata: { ...attach }, metadata: { ...attach },
})) : []; }))
: [];
}, [manualJournal]); }, [manualJournal]);
const formik = useFormik({ const formik = useFormik({
@@ -133,113 +165,128 @@ function MakeJournalEntriesForm({
...initialValues, ...initialValues,
}, },
onSubmit: async (values, { setErrors, setSubmitting, resetForm }) => { onSubmit: async (values, { setErrors, setSubmitting, resetForm }) => {
const entries = values.entries.filter((entry) => ( const entries = values.entries.filter(
(entry.credit || entry.debit) (entry) => entry.credit || entry.debit,
)); );
const getTotal = (type = 'credit') => { const getTotal = (type = 'credit') => {
return entries.reduce((total, item) => { return entries.reduce((total, item) => {
return item[type] ? item[type] + total : total; return item[type] ? item[type] + total : total;
}, 0); }, 0);
} };
const totalCredit = getTotal('credit'); const totalCredit = getTotal('credit');
const totalDebit = getTotal('debit'); const totalDebit = getTotal('debit');
// Validate the total credit should be eqials total debit. // Validate the total credit should be eqials total debit.
if (totalCredit !== totalDebit) { if (totalCredit !== totalDebit) {
AppToaster.show({ AppToaster.show({
message: formatMessage({id:'credit_and_debit_not_equal'}), message: formatMessage({ id: 'credit_and_debit_not_equal' }),
}); });
setSubmitting(false); setSubmitting(false);
return; return;
} }
const form = { ...values, status: payload.publish, entries }; const form = { ...values, status: payload.publish, entries };
const saveJournal = (mediaIds) => new Promise((resolve, reject) => { const saveJournal = (mediaIds) =>
const requestForm = { ...form, media_ids: mediaIds }; new Promise((resolve, reject) => {
const requestForm = { ...form, media_ids: mediaIds };
if (manualJournal && manualJournal.id) { if (manualJournal && manualJournal.id) {
requestEditManualJournal(manualJournal.id, requestForm) requestEditManualJournal(manualJournal.id, requestForm)
.then((response) => { .then((response) => {
AppToaster.show({ AppToaster.show({
message: formatMessage({ message: formatMessage(
id: 'the_journal_has_been_successfully_edited', { id: 'the_journal_has_been_successfully_edited' },
}, { { number: values.journal_number },
number: values.journal_number, ),
}), intent: Intent.SUCCESS,
intent: Intent.SUCCESS,
});
setSubmitting(false);
saveInvokeSubmit({ action: 'update', ...payload });
clearSavedMediaIds([]);
resetForm();
resolve(response);
}).catch((errors) => {
if (errors.find(e => e.type === 'JOURNAL.NUMBER.ALREADY.EXISTS')) {
setErrors({
journal_number: formatMessage({ id: 'journal_number_is_already_used' }),
}); });
} setSubmitting(false);
setSubmitting(false); saveInvokeSubmit({ action: 'update', ...payload });
}); clearSavedMediaIds([]);
} else { resetForm();
requestMakeJournalEntries(requestForm) resolve(response);
.then((response) => { })
AppToaster.show({ .catch((errors) => {
message: formatMessage({ if (
id: 'the_journal_has_been_successfully_created', errors.find((e) => e.type === 'JOURNAL.NUMBER.ALREADY.EXISTS')
}, { ) {
number: values.journal_number, setErrors({
}), journal_number: formatMessage({
intent: Intent.SUCCESS, id: 'journal_number_is_already_used',
}),
});
}
setSubmitting(false);
}); });
setSubmitting(false); } else {
saveInvokeSubmit({ action: 'new', ...payload }); requestMakeJournalEntries(requestForm)
clearSavedMediaIds(); .then((response) => {
resetForm(); AppToaster.show({
resolve(response); message: formatMessage(
}).catch((errors) => { { id: 'the_journal_has_been_successfully_created' },
if (errors.find(e => e.type === 'JOURNAL.NUMBER.ALREADY.EXISTS')) { { number: values.journal_number },
setErrors({ ),
journal_number: formatMessage({ id: 'journal_number_is_already_used' }), intent: Intent.SUCCESS,
}); });
} setSubmitting(false);
setSubmitting(false); saveInvokeSubmit({ action: 'new', ...payload });
}); clearSavedMediaIds();
} resetForm();
}); resolve(response);
})
.catch((errors) => {
if (
errors.find((e) => e.type === 'JOURNAL.NUMBER.ALREADY.EXISTS')
) {
setErrors({
journal_number: formatMessage({
id: 'journal_number_is_already_used',
}),
});
}
setSubmitting(false);
});
}
});
Promise.all([ Promise.all([saveMedia(), deleteMedia()])
saveMedia(), .then(([savedMediaResponses]) => {
deleteMedia(), const mediaIds = savedMediaResponses.map((res) => res.data.media.id);
]).then(([savedMediaResponses]) => { savedMediaIds.current = mediaIds;
const mediaIds = savedMediaResponses.map(res => res.data.media.id);
savedMediaIds.current = mediaIds;
return savedMediaResponses; return savedMediaResponses;
}).then(() => { })
return saveJournal(savedMediaIds.current); .then(() => {
}); return saveJournal(savedMediaIds.current);
});
}, },
}); });
const handleSubmitClick = useCallback((payload) => { const handleSubmitClick = useCallback(
setPayload(payload); (payload) => {
formik.handleSubmit(); setPayload(payload);
}, [setPayload, formik]); formik.handleSubmit();
},
[setPayload, formik],
);
const handleCancelClick = useCallback((payload) => { const handleCancelClick = useCallback(
onCancelForm && onCancelForm(payload); (payload) => {
}, [onCancelForm]); onCancelForm && onCancelForm(payload);
},
[onCancelForm],
);
const handleDeleteFile = useCallback((_deletedFiles) => { const handleDeleteFile = useCallback(
_deletedFiles.forEach((deletedFile) => { (_deletedFiles) => {
if (deletedFile.uploaded && deletedFile.metadata.id) { _deletedFiles.forEach((deletedFile) => {
setDeletedFiles([ if (deletedFile.uploaded && deletedFile.metadata.id) {
...deletedFiles, deletedFile.metadata.id, setDeletedFiles([...deletedFiles, deletedFile.metadata.id]);
]); }
} });
}); },
}, [setDeletedFiles, deletedFiles]); [setDeletedFiles, deletedFiles],
);
return ( return (
<div class="make-journal-entries"> <div class="make-journal-entries">
@@ -249,19 +296,22 @@ function MakeJournalEntriesForm({
<MakeJournalEntriesTable <MakeJournalEntriesTable
initialValues={initialValues} initialValues={initialValues}
formik={formik} formik={formik}
defaultRow={defaultEntry} /> defaultRow={defaultEntry}
/>
<MakeJournalEntriesFooter <MakeJournalEntriesFooter
formik={formik} formik={formik}
onSubmitClick={handleSubmitClick} onSubmitClick={handleSubmitClick}
onCancelClick={handleCancelClick} /> onCancelClick={handleCancelClick}
/>
</form> </form>
<Dragzone <Dragzone
initialFiles={initialAttachmentFiles} initialFiles={initialAttachmentFiles}
onDrop={handleDropFiles} onDrop={handleDropFiles}
onDeleteFile={handleDeleteFile} onDeleteFile={handleDeleteFile}
hint={'Attachments: Maxiumum size: 20MB'} /> hint={'Attachments: Maxiumum size: 20MB'}
/>
</div> </div>
); );
} }
@@ -272,4 +322,4 @@ export default compose(
withAccountsActions, withAccountsActions,
withDashboardActions, withDashboardActions,
MediaConnect, MediaConnect,
)(MakeJournalEntriesForm); )(MakeJournalEntriesForm);

View File

@@ -29,9 +29,9 @@ const ActionsCellRenderer = ({
}; };
return ( return (
<Button <Button
icon={<Icon icon='times-circle' iconSize={14} />} icon={<Icon icon="times-circle" iconSize={14} />}
iconSize={14} iconSize={14}
className='ml2' className="ml2"
minimal={true} minimal={true}
intent={Intent.DANGER} intent={Intent.DANGER}
onClick={onClickRemoveRole} onClick={onClickRemoveRole}
@@ -72,7 +72,7 @@ const NoteCellRenderer = (chainedComponent) => (props) => {
/** /**
* Make journal entries table component. * Make journal entries table component.
*/ */
function MakeJournalEntriesTable({ function MakeJournalEntriesTable({
// #withAccounts // #withAccounts
accounts, accounts,
@@ -107,10 +107,10 @@ function MakeJournalEntriesTable({
'entries', 'entries',
newRows.map((row) => ({ newRows.map((row) => ({
...omit(row, ['rowType']), ...omit(row, ['rowType']),
})) })),
); );
}, },
[rows, setFieldValue] [rows, setFieldValue],
); );
// Handles click remove datatable row. // Handles click remove datatable row.
@@ -124,11 +124,11 @@ function MakeJournalEntriesTable({
'entries', 'entries',
newRows newRows
.filter((row) => row.rowType === 'editor') .filter((row) => row.rowType === 'editor')
.map((row) => ({ ...omit(row, ['rowType']) })) .map((row) => ({ ...omit(row, ['rowType']) })),
); );
onClickRemoveRow && onClickRemoveRow(removeIndex); onClickRemoveRow && onClickRemoveRow(removeIndex);
}, },
[rows, setFieldValue, onClickRemoveRow] [rows, setFieldValue, onClickRemoveRow],
); );
// Memorized data table columns. // Memorized data table columns.
@@ -188,7 +188,7 @@ function MakeJournalEntriesTable({
width: 45, width: 45,
}, },
], ],
[formatMessage] [formatMessage],
); );
// Handles click new line. // Handles click new line.
@@ -201,15 +201,16 @@ function MakeJournalEntriesTable({
(row) => ({ (row) => ({
'row--total': rows.length === row.index + 2, 'row--total': rows.length === row.index + 2,
}), }),
[rows] [rows],
); );
return ( return (
<div class='make-journal-entries__table'> <div class="make-journal-entries__table">
<DataTable <DataTable
columns={columns} columns={columns}
data={rows} data={rows}
rowClassNames={rowClassNames} rowClassNames={rowClassNames}
sticky={true}
payload={{ payload={{
accounts, accounts,
errors: errors.entries || [], errors: errors.entries || [],
@@ -218,7 +219,7 @@ function MakeJournalEntriesTable({
}} }}
/> />
<div class='mt1'> <div class="mt1">
<Button <Button
small={true} small={true}
className={'button--secondary button--new-line'} className={'button--secondary button--new-line'}

View File

@@ -24,26 +24,26 @@ import DialogConnect from 'connectors/Dialog.connector';
import { useUpdateEffect } from 'hooks'; import { useUpdateEffect } from 'hooks';
import DataTable from 'components/DataTable'; import DataTable from 'components/DataTable';
import withDashboardActions from 'containers/Dashboard/withDashboard'; import withDashboardActions from 'containers/Dashboard/withDashboardActions';
import withViewDetails from 'containers/Views/withViewDetails'; import withViewDetails from 'containers/Views/withViewDetails';
import withManualJournals from 'containers/Accounting/withManualJournals'; import withManualJournals from 'containers/Accounting/withManualJournals';
import withManualJournalsActions from 'containers/Accounting/withManualJournalsActions'; import withManualJournalsActions from 'containers/Accounting/withManualJournalsActions';
import { If, Money } from 'components'; import { If, Money } from 'components';
function ManualJournalsDataTable({ function ManualJournalsDataTable({
loading, loading,
manualJournals, manualJournals,
manualJournalsLoading, manualJournalsLoading,
// #withDashboardActions
changeCurrentView, changeCurrentView,
changePageSubtitle, changePageSubtitle,
setTopbarEditView,
viewId, viewId,
viewMeta, viewMeta,
setTopbarEditView,
onFetchData, onFetchData,
onEditJournal, onEditJournal,
@@ -80,21 +80,21 @@ function ManualJournalsDataTable({
(journal) => () => { (journal) => () => {
onPublishJournal && onPublishJournal(journal); onPublishJournal && onPublishJournal(journal);
}, },
[onPublishJournal] [onPublishJournal],
); );
const handleEditJournal = useCallback( const handleEditJournal = useCallback(
(journal) => () => { (journal) => () => {
onEditJournal && onEditJournal(journal); onEditJournal && onEditJournal(journal);
}, },
[onEditJournal] [onEditJournal],
); );
const handleDeleteJournal = useCallback( const handleDeleteJournal = useCallback(
(journal) => () => { (journal) => () => {
onDeleteJournal && onDeleteJournal(journal); onDeleteJournal && onDeleteJournal(journal);
}, },
[onDeleteJournal] [onDeleteJournal],
); );
// const actionMenuList = (journal) => ( // const actionMenuList = (journal) => (
@@ -118,121 +118,141 @@ function ManualJournalsDataTable({
// /> // />
// </Menu> // </Menu>
// ); // );
const actionMenuList =useCallback((journal)=>( const actionMenuList = useCallback(
<Menu> (journal) => (
<MenuItem text={<T id={'view_details'} />} /> <Menu>
<MenuDivider /> <MenuItem text={<T id={'view_details'} />} />
{!journal.status && ( <MenuDivider />
{!journal.status && (
<MenuItem
text={<T id={'publish_journal'} />}
onClick={handlePublishJournal(journal)}
/>
)}
<MenuItem <MenuItem
text={<T id={'publish_journal'} />} text={<T id={'edit_journal'} />}
onClick={handlePublishJournal(journal)} onClick={handleEditJournal(journal)}
/> />
)} <MenuItem
<MenuItem text={<T id={'delete_journal'} />}
text={<T id={'edit_journal'} />} intent={Intent.DANGER}
onClick={handleEditJournal(journal)} onClick={handleDeleteJournal(journal)}
/> />
<MenuItem </Menu>
text={<T id={'delete_journal'} />} ),
intent={Intent.DANGER} [handleEditJournal, handleDeleteJournal, handlePublishJournal],
onClick={handleDeleteJournal(journal)} );
/>
</Menu>
),[handleEditJournal,handleDeleteJournal,handlePublishJournal]);
const columns = useMemo(() => [ const columns = useMemo(
{ () => [
id: 'date', {
Header: formatMessage({ id: 'date' }), id: 'date',
accessor: (r) => moment().format('YYYY-MM-DD'), Header: formatMessage({ id: 'date' }),
disableResizing: true, accessor: (r) => moment().format('YYYY-MM-DD'),
width: 150, disableResizing: true,
className: 'date', width: 150,
}, className: 'date',
{
id: 'amount',
Header: formatMessage({ id: 'amount' }),
accessor: r => (<Money amount={r.amount} currency={'USD'} />),
disableResizing: true,
className: 'amount',
},
{
id: 'journal_number',
Header: formatMessage({ id: 'journal_no' }),
accessor: 'journal_number',
disableResizing: true,
className: 'journal_number',
},
{
id: 'status',
Header: formatMessage({ id: 'status' }),
accessor: (r) => {
return r.status
? <Tag minimal={true}><T id={'published'} /></Tag> :
<Tag minimal={true} intent={Intent.WARNING}><T id={'draft'} /></Tag>;
}, },
disableResizing: true, {
width: 100, id: 'amount',
className: 'status', Header: formatMessage({ id: 'amount' }),
}, accessor: (r) => <Money amount={r.amount} currency={'USD'} />,
{ disableResizing: true,
id: 'note', className: 'amount',
Header: formatMessage({ id: 'note' }), },
accessor: (row) => ( {
<If condition={row.description}> id: 'journal_number',
<Tooltip Header: formatMessage({ id: 'journal_no' }),
className={Classes.TOOLTIP_INDICATOR} accessor: 'journal_number',
content={row.description} disableResizing: true,
position={Position.TOP} className: 'journal_number',
hoverOpenDelay={250}> },
<Icon icon={'file-alt'} iconSize={16} /> {
</Tooltip> id: 'status',
</If> Header: formatMessage({ id: 'status' }),
), accessor: (r) => {
disableResizing: true, return r.status ? (
disableSorting: true, <Tag minimal={true}>
width: 100, <T id={'published'} />
className: 'note', </Tag>
}, ) : (
{ <Tag minimal={true} intent={Intent.WARNING}>
id: 'transaction_type', <T id={'draft'} />
Header: formatMessage({ id: 'transaction_type' }), </Tag>
accessor: 'transaction_type', );
width: 100, },
className: 'transaction_type', disableResizing: true,
}, width: 100,
{ className: 'status',
id: 'created_at', },
Header: formatMessage({ id: 'created_at' }), {
accessor: r => moment().format('YYYY-MM-DD'), id: 'note',
disableResizing: true, Header: formatMessage({ id: 'note' }),
width: 150, accessor: (row) => (
className: 'created_at', <If condition={row.description}>
}, <Tooltip
{ className={Classes.TOOLTIP_INDICATOR}
id: 'actions', content={row.description}
Header: '', position={Position.TOP}
Cell: ({ cell }) => ( hoverOpenDelay={250}
<Popover >
content={actionMenuList(cell.row.original)} <Icon icon={'file-alt'} iconSize={16} />
position={Position.RIGHT_BOTTOM} </Tooltip>
> </If>
<Button icon={<Icon icon='ellipsis-h' />} /> ),
</Popover> disableResizing: true,
), disableSorting: true,
className: 'actions', width: 100,
width: 50, className: 'note',
disableResizing: true, },
}, {
], [actionMenuList,formatMessage]); id: 'transaction_type',
Header: formatMessage({ id: 'transaction_type' }),
accessor: 'transaction_type',
width: 100,
className: 'transaction_type',
},
{
id: 'created_at',
Header: formatMessage({ id: 'created_at' }),
accessor: (r) => moment().format('YYYY-MM-DD'),
disableResizing: true,
width: 150,
className: 'created_at',
},
{
id: 'actions',
Header: '',
Cell: ({ cell }) => (
<Popover
content={actionMenuList(cell.row.original)}
position={Position.RIGHT_BOTTOM}
>
<Button icon={<Icon icon="ellipsis-h" />} />
</Popover>
),
className: 'actions',
width: 50,
disableResizing: true,
},
],
[actionMenuList, formatMessage],
);
const handleDataTableFetchData = useCallback((...args) => { const handleDataTableFetchData = useCallback(
onFetchData && onFetchData(...args); (...args) => {
}, [onFetchData]); onFetchData && onFetchData(...args);
},
[onFetchData],
);
const handleSelectedRowsChange = useCallback((selectedRows) => { const handleSelectedRowsChange = useCallback(
onSelectedRowsChange && onSelectedRowsChange(selectedRows.map((s) => s.original)); (selectedRows) => {
}, [onSelectedRowsChange]); onSelectedRowsChange &&
onSelectedRowsChange(selectedRows.map((s) => s.original));
},
[onSelectedRowsChange],
);
return ( return (
<LoadingIndicator loading={loading} mount={false}> <LoadingIndicator loading={loading} mount={false}>
@@ -243,6 +263,7 @@ function ManualJournalsDataTable({
manualSortBy={true} manualSortBy={true}
selectionColumn={true} selectionColumn={true}
noInitialFetch={true} noInitialFetch={true}
sticky={true}
loading={manualJournalsLoading && !initialMount} loading={manualJournalsLoading && !initialMount}
onSelectedRowsChange={handleSelectedRowsChange} onSelectedRowsChange={handleSelectedRowsChange}
/> />
@@ -254,7 +275,7 @@ export default compose(
DialogConnect, DialogConnect,
withDashboardActions, withDashboardActions,
withManualJournalsActions, withManualJournalsActions,
withManualJournals(({ manualJournals, manualJournalsLoading, }) => ({ withManualJournals(({ manualJournals, manualJournalsLoading }) => ({
manualJournals, manualJournals,
manualJournalsLoading, manualJournalsLoading,
})), })),

View File

@@ -12,7 +12,7 @@ import ManualJournalsViewTabs from 'containers/Accounting/ManualJournalsViewTabs
import ManualJournalsDataTable from 'containers/Accounting/ManualJournalsDataTable'; import ManualJournalsDataTable from 'containers/Accounting/ManualJournalsDataTable';
import ManualJournalsActionsBar from 'containers/Accounting/ManualJournalActionsBar'; import ManualJournalsActionsBar from 'containers/Accounting/ManualJournalActionsBar';
import withDashboardActions from 'containers/Dashboard/withDashboard'; import withDashboardActions from 'containers/Dashboard/withDashboardActions';
import withManualJournalsActions from 'containers/Accounting/withManualJournalsActions'; import withManualJournalsActions from 'containers/Accounting/withManualJournalsActions';
import withViewsActions from 'containers/Views/withViewsActions'; import withViewsActions from 'containers/Views/withViewsActions';

View File

@@ -18,7 +18,7 @@ import Icon from 'components/Icon';
import withManualJournals from './withManualJournals'; import withManualJournals from './withManualJournals';
import withManualJournalsActions from './withManualJournalsActions'; import withManualJournalsActions from './withManualJournalsActions';
import withDashboard from 'containers/Dashboard/withDashboard'; import withDashboardActions from 'containers/Dashboard/withDashboardActions';
import { compose } from 'utils'; import { compose } from 'utils';
@@ -29,7 +29,7 @@ function ManualJournalsViewTabs({
// #withManualJournalsActions // #withManualJournalsActions
addManualJournalsTableQueries, addManualJournalsTableQueries,
// #withDashboard // #withDashboardActions
setTopbarEditView, setTopbarEditView,
// #ownProps // #ownProps
@@ -121,5 +121,5 @@ export default compose(
manualJournalsViews, manualJournalsViews,
})), })),
withManualJournalsActions, withManualJournalsActions,
withDashboard withDashboardActions
)(ManualJournalsViewTabs); )(ManualJournalsViewTabs);

View File

@@ -15,7 +15,7 @@ import AccountsViewsTabs from 'containers/Accounts/AccountsViewsTabs';
import AccountsDataTable from 'containers/Accounts/AccountsDataTable'; import AccountsDataTable from 'containers/Accounts/AccountsDataTable';
import DashboardActionsBar from 'containers/Accounts/AccountsActionsBar'; import DashboardActionsBar from 'containers/Accounts/AccountsActionsBar';
import withDashboardActions from 'containers/Dashboard/withDashboard'; import withDashboardActions from 'containers/Dashboard/withDashboardActions';
import withResourceActions from 'containers/Resources/withResourcesActions'; import withResourceActions from 'containers/Resources/withResourcesActions';
import withAccountsActions from 'containers/Accounts/withAccountsActions'; import withAccountsActions from 'containers/Accounts/withAccountsActions';
import withAccountsTableActions from 'containers/Accounts/withAccountsTableActions'; import withAccountsTableActions from 'containers/Accounts/withAccountsTableActions';
@@ -26,7 +26,7 @@ import { compose } from 'utils';
function AccountsChart({ function AccountsChart({
// #withDashboard // #withDashboardActions
changePageTitle, changePageTitle,
// #withAccountsActions // #withAccountsActions

View File

@@ -19,7 +19,7 @@ import DataTable from 'components/DataTable';
import Money from 'components/Money'; import Money from 'components/Money';
import { useUpdateEffect } from 'hooks'; import { useUpdateEffect } from 'hooks';
import withDashboardActions from 'containers/Dashboard/withDashboard'; import withDashboardActions from 'containers/Dashboard/withDashboardActions';
import withAccountsActions from 'containers/Accounts/withAccountsActions'; import withAccountsActions from 'containers/Accounts/withAccountsActions';
import withAccounts from 'containers/Accounts/withAccounts'; import withAccounts from 'containers/Accounts/withAccounts';
@@ -27,7 +27,7 @@ import { If } from 'components';
function AccountsDataTable({ function AccountsDataTable({
// #withAccounts // #withDashboardActions
accounts, accounts,
accountsLoading, accountsLoading,
@@ -193,6 +193,7 @@ function AccountsDataTable({
selectionColumn={selectionColumn} selectionColumn={selectionColumn}
expandable={true} expandable={true}
treeGraph={true} treeGraph={true}
sticky={true}
onSelectedRowsChange={handleSelectedRowsChange} onSelectedRowsChange={handleSelectedRowsChange}
loading={accountsLoading && !initialMount} loading={accountsLoading && !initialMount}
spinnerProps={{size: 30}} /> spinnerProps={{size: 30}} />

View File

@@ -15,7 +15,7 @@ import { Link } from 'react-router-dom';
import { FormattedMessage as T } from 'react-intl'; import { FormattedMessage as T } from 'react-intl';
import {useUpdateEffect} from 'hooks'; import {useUpdateEffect} from 'hooks';
import withDashboard from 'containers/Dashboard/withDashboard'; import withDashboardActions from 'containers/Dashboard/withDashboardActions';
import withAccounts from 'containers/Accounts/withAccounts'; import withAccounts from 'containers/Accounts/withAccounts';
import withAccountsTableActions from 'containers/Accounts/withAccountsTableActions'; import withAccountsTableActions from 'containers/Accounts/withAccountsTableActions';
import withViewDetail from 'containers/Views/withViewDetails'; import withViewDetail from 'containers/Views/withViewDetails';
@@ -34,7 +34,7 @@ function AccountsViewsTabs({
addAccountsTableQueries, addAccountsTableQueries,
changeAccountsCurrentView, changeAccountsCurrentView,
// #withDashboard // #withDashboardActions
setTopbarEditView, setTopbarEditView,
changePageSubtitle, changePageSubtitle,
@@ -125,7 +125,7 @@ const withAccountsViewsTabs = connect(mapStateToProps);
export default compose( export default compose(
withRouter, withRouter,
withAccountsViewsTabs, withAccountsViewsTabs,
withDashboard, withDashboardActions,
withAccounts(({ accountsViews }) => ({ withAccounts(({ accountsViews }) => ({
accountsViews, accountsViews,
})), })),

View File

@@ -1,27 +1,15 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import t from 'store/types';
const mapActionsToProps = (dispatch) => ({ export default (mapState) => {
changePageTitle: (pageTitle) => dispatch({ const mapStateToProps = (state, props) => {
type: t.CHANGE_DASHBOARD_PAGE_TITLE, pageTitle const mapped = {
}), pageTitle: state.dashboard.pageTitle,
pageSubtitle: state.dashboard.pageSubtitle,
changePageSubtitle: (pageSubtitle) => dispatch({ editViewId: state.dashboard.topbarEditViewId,
type: t.ALTER_DASHBOARD_PAGE_SUBTITLE, pageSubtitle, sidebarExpended: state.dashboard.sidebarExpended,
}), };
return mapState ? mapState(mapped, state, props) : mapped;
setTopbarEditView: (id) => dispatch({ };
type: t.SET_TOPBAR_EDIT_VIEW, id, return connect(mapStateToProps);
}), }
setDashboardRequestLoading: () => dispatch({
type: t.SET_DASHBOARD_REQUEST_LOADING,
}),
setDashboardRequestCompleted: () => dispatch({
type: t.SET_DASHBOARD_REQUEST_COMPLETED,
}),
});
export default connect(null, mapActionsToProps);

View File

@@ -0,0 +1,31 @@
import { connect } from 'react-redux';
import t from 'store/types';
const mapActionsToProps = (dispatch) => ({
changePageTitle: (pageTitle) => dispatch({
type: t.CHANGE_DASHBOARD_PAGE_TITLE, pageTitle
}),
changePageSubtitle: (pageSubtitle) => dispatch({
type: t.ALTER_DASHBOARD_PAGE_SUBTITLE, pageSubtitle,
}),
setTopbarEditView: (id) => dispatch({
type: t.SET_TOPBAR_EDIT_VIEW, id,
}),
setDashboardRequestLoading: () => dispatch({
type: t.SET_DASHBOARD_REQUEST_LOADING,
}),
setDashboardRequestCompleted: () => dispatch({
type: t.SET_DASHBOARD_REQUEST_COMPLETED,
}),
toggleSidebarExpend: () => dispatch({
type: t.SIDEBAR_EXPEND_TOGGLE,
}),
});
export default connect(null, mapActionsToProps);

View File

@@ -1,8 +1,12 @@
import React, { useEffect, useState, useCallback,useMemo } from 'react'; import React, { useEffect, useState, useCallback, useMemo } from 'react';
import { useQuery } from 'react-query'; import { useQuery } from 'react-query';
import { useParams } from 'react-router-dom'; import { useParams } from 'react-router-dom';
import { Alert, Intent } from '@blueprintjs/core'; import { Alert, Intent } from '@blueprintjs/core';
import { FormattedMessage as T, useIntl, FormattedHTMLMessage } from 'react-intl'; import {
FormattedMessage as T,
useIntl,
FormattedHTMLMessage,
} from 'react-intl';
import AppToaster from 'components/AppToaster'; import AppToaster from 'components/AppToaster';
import DashboardPageContent from 'components/Dashboard/DashboardPageContent'; import DashboardPageContent from 'components/Dashboard/DashboardPageContent';
@@ -10,15 +14,14 @@ import DashboardInsider from 'components/Dashboard/DashboardInsider';
import ExchangeRateTable from './ExchangeRateTable'; import ExchangeRateTable from './ExchangeRateTable';
import ExchangeRateActionsBar from './ExchangeRateActionsBar'; import ExchangeRateActionsBar from './ExchangeRateActionsBar';
import withDashboardActions from 'containers/Dashboard/withDashboard'; import withDashboardActions from 'containers/Dashboard/withDashboardActions';
import withResourceActions from 'containers/Resources/withResourcesActions'; import withResourceActions from 'containers/Resources/withResourcesActions';
import withExchangeRatesActions from 'containers/ExchangeRates/withExchangeRatesActions'; import withExchangeRatesActions from 'containers/ExchangeRates/withExchangeRatesActions';
import { compose } from 'utils'; import { compose } from 'utils';
function ExchangeRate({ function ExchangeRate({
// #withDashboard // #withDashboardActions
changePageTitle, changePageTitle,
//#withResourceActions //#withResourceActions
@@ -29,7 +32,6 @@ function ExchangeRate({
requestDeleteExchangeRate, requestDeleteExchangeRate,
addExchangeRatesTableQueries, addExchangeRatesTableQueries,
requestDeleteBulkExchangeRates, requestDeleteBulkExchangeRates,
}) { }) {
const { id } = useParams(); const { id } = useParams();
const [deleteExchangeRate, setDeleteExchangeRate] = useState(false); const [deleteExchangeRate, setDeleteExchangeRate] = useState(false);
@@ -37,21 +39,21 @@ function ExchangeRate({
const { formatMessage } = useIntl(); const { formatMessage } = useIntl();
const [bulkDelete, setBulkDelete] = useState(false); const [bulkDelete, setBulkDelete] = useState(false);
const fetchExchangeRates = useQuery('exchange-rates-table', const fetchExchangeRates = useQuery('exchange-rates-table', () =>
() => requestFetchExchangeRates()); requestFetchExchangeRates(),
);
useEffect(() => { useEffect(() => {
id id
? changePageTitle(formatMessage({id:'exchange_rate_details'})) ? changePageTitle(formatMessage({ id: 'exchange_rate_details' }))
: changePageTitle(formatMessage({id:'exchange_rate_list'})); : changePageTitle(formatMessage({ id: 'exchange_rate_list' }));
}, [id, changePageTitle,formatMessage]); }, [id, changePageTitle, formatMessage]);
const handelDeleteExchangeRate = useCallback( const handelDeleteExchangeRate = useCallback(
(exchange_rate) => { (exchange_rate) => {
setDeleteExchangeRate(exchange_rate); setDeleteExchangeRate(exchange_rate);
}, },
[setDeleteExchangeRate] [setDeleteExchangeRate],
); );
const handelEditExchangeRate = (exchange_rate) => {}; const handelEditExchangeRate = (exchange_rate) => {};
@@ -64,10 +66,12 @@ function ExchangeRate({
requestDeleteExchangeRate(deleteExchangeRate.id).then(() => { requestDeleteExchangeRate(deleteExchangeRate.id).then(() => {
setDeleteExchangeRate(false); setDeleteExchangeRate(false);
AppToaster.show({ AppToaster.show({
message: formatMessage({id:'the_exchange_rate_has_been_successfully_deleted'}), message: formatMessage({
id: 'the_exchange_rate_has_been_successfully_deleted',
}),
}); });
}); });
}, [deleteExchangeRate, requestDeleteExchangeRate,formatMessage]); }, [deleteExchangeRate, requestDeleteExchangeRate, formatMessage]);
// Handle fetch data of Exchange_rates datatable. // Handle fetch data of Exchange_rates datatable.
const handleFetchData = useCallback( const handleFetchData = useCallback(
@@ -81,50 +85,50 @@ function ExchangeRate({
: {}), : {}),
}); });
}, },
[addExchangeRatesTableQueries] [addExchangeRatesTableQueries],
); );
const handleSelectedRowsChange = useCallback( const handleSelectedRowsChange = useCallback(
(exchange_rates) => { (exchange_rates) => {
setSelectedRows(exchange_rates); setSelectedRows(exchange_rates);
}, },
[setSelectedRows] [setSelectedRows],
); );
// Handle Exchange Rates bulk delete. // Handle Exchange Rates bulk delete.
const handleBulkDelete = useCallback( const handleBulkDelete = useCallback(
(exchangeRates) => { (exchangeRates) => {
setBulkDelete(exchangeRates); setBulkDelete(exchangeRates);
}, },
[setBulkDelete] [setBulkDelete],
); );
//Handel cancel itemCategories bulk delete. //Handel cancel itemCategories bulk delete.
const handleCancelBulkDelete =useCallback(()=>{ const handleCancelBulkDelete = useCallback(() => {
setBulkDelete(false) setBulkDelete(false);
},[]) }, []);
// handle confirm Exchange Rates bulk delete. // handle confirm Exchange Rates bulk delete.
const handleConfirmBulkDelete = useCallback(() => { const handleConfirmBulkDelete = useCallback(() => {
requestDeleteBulkExchangeRates(bulkDelete) requestDeleteBulkExchangeRates(bulkDelete)
.then(() => { .then(() => {
setBulkDelete(false); setBulkDelete(false);
AppToaster.show({ AppToaster.show({
message: formatMessage({ message: formatMessage({
id: 'the_exchange_rates_has_been_successfully_deleted', id: 'the_exchange_rates_has_been_successfully_deleted',
}), }),
intent: Intent.SUCCESS, intent: Intent.SUCCESS,
});
})
.catch((errors) => {
setBulkDelete(false);
}); });
}) }, [requestDeleteBulkExchangeRates, bulkDelete, formatMessage]);
.catch((errors) => {
setBulkDelete(false);
});
}, [requestDeleteBulkExchangeRates, bulkDelete,formatMessage]);
// Calculates the data table selected rows count. // Calculates the data table selected rows count.
const selectedRowsCount = useMemo(() => Object.values(selectedRows).length, [selectedRows]); const selectedRowsCount = useMemo(() => Object.values(selectedRows).length, [
selectedRows,
]);
return ( return (
<DashboardInsider> <DashboardInsider>
@@ -132,7 +136,6 @@ const handleConfirmBulkDelete = useCallback(() => {
onDeleteExchangeRate={handelDeleteExchangeRate} onDeleteExchangeRate={handelDeleteExchangeRate}
selectedRows={selectedRows} selectedRows={selectedRows}
onBulkDelete={handleBulkDelete} onBulkDelete={handleBulkDelete}
/> />
<DashboardPageContent> <DashboardPageContent>
<ExchangeRateTable <ExchangeRateTable
@@ -144,32 +147,37 @@ const handleConfirmBulkDelete = useCallback(() => {
<Alert <Alert
cancelButtonText={<T id={'cancel'} />} cancelButtonText={<T id={'cancel'} />}
confirmButtonText={<T id={'move_to_trash'} />} confirmButtonText={<T id={'move_to_trash'} />}
icon='trash' icon="trash"
intent={Intent.DANGER} intent={Intent.DANGER}
isOpen={deleteExchangeRate} isOpen={deleteExchangeRate}
onCancel={handelCancelExchangeRateDelete} onCancel={handelCancelExchangeRateDelete}
onConfirm={handelConfirmExchangeRateDelete} onConfirm={handelConfirmExchangeRateDelete}
> >
<p> <p>
<FormattedHTMLMessage id={'once_delete_this_exchange_rate_you_will_able_to_restore_it'}/> <FormattedHTMLMessage
id={'once_delete_this_exchange_rate_you_will_able_to_restore_it'}
/>
</p> </p>
</Alert> </Alert>
<Alert <Alert
cancelButtonText={<T id={'cancel'} />} cancelButtonText={<T id={'cancel'} />}
confirmButtonText={`${formatMessage({id:'delete'})} (${selectedRowsCount})`} confirmButtonText={`${formatMessage({
icon='trash' id: 'delete',
intent={Intent.DANGER} })} (${selectedRowsCount})`}
isOpen={bulkDelete} icon="trash"
onCancel={handleCancelBulkDelete} intent={Intent.DANGER}
onConfirm={handleConfirmBulkDelete} isOpen={bulkDelete}
> onCancel={handleCancelBulkDelete}
<p> onConfirm={handleConfirmBulkDelete}
<FormattedHTMLMessage >
id={'once_delete_these_exchange_rates_you_will_not_able_restore_them'} <p>
/> <FormattedHTMLMessage
</p> id={
</Alert> 'once_delete_these_exchange_rates_you_will_not_able_restore_them'
}
/>
</p>
</Alert>
</DashboardPageContent> </DashboardPageContent>
</DashboardInsider> </DashboardInsider>
); );
@@ -178,5 +186,5 @@ const handleConfirmBulkDelete = useCallback(() => {
export default compose( export default compose(
withExchangeRatesActions, withExchangeRatesActions,
withResourceActions, withResourceActions,
withDashboardActions withDashboardActions,
)(ExchangeRate); )(ExchangeRate);

View File

@@ -13,7 +13,7 @@ import DashboardInsider from 'components/Dashboard/DashboardInsider';
import BalanceSheetActionsBar from './BalanceSheetActionsBar'; import BalanceSheetActionsBar from './BalanceSheetActionsBar';
import { FinancialStatement } from 'components'; import { FinancialStatement } from 'components';
import withDashboard from 'containers/Dashboard/withDashboard'; import withDashboardActions from 'containers/Dashboard/withDashboardActions';
import withSettings from 'containers/Settings/withSettings'; import withSettings from 'containers/Settings/withSettings';
import withBalanceSheetActions from './withBalanceSheetActions'; import withBalanceSheetActions from './withBalanceSheetActions';
import withBalanceSheetDetail from './withBalanceSheetDetail'; import withBalanceSheetDetail from './withBalanceSheetDetail';
@@ -21,7 +21,7 @@ import withBalanceSheetDetail from './withBalanceSheetDetail';
function BalanceSheet({ function BalanceSheet({
// #withDashboard // #withDashboardActions
changePageTitle, changePageTitle,
// #withBalanceSheetActions // #withBalanceSheetActions
@@ -100,7 +100,7 @@ function BalanceSheet({
} }
export default compose( export default compose(
withDashboard, withDashboardActions,
withBalanceSheetActions, withBalanceSheetActions,
withBalanceSheetDetail(({ balanceSheetLoading, balanceSheetFilter }) => ({ withBalanceSheetDetail(({ balanceSheetLoading, balanceSheetFilter }) => ({
balanceSheetLoading, balanceSheetLoading,

View File

@@ -103,6 +103,7 @@ function BalanceSheetTable({
onFetchData={handleFetchData} onFetchData={handleFetchData}
expanded={expandedRows} expanded={expandedRows}
expandSubRows={true} expandSubRows={true}
sticky={true}
/> />
</FinancialSheet> </FinancialSheet>
); );

View File

@@ -13,13 +13,13 @@ import DashboardPageContent from 'components/Dashboard/DashboardPageContent';
import GeneralLedgerActionsBar from './GeneralLedgerActionsBar'; import GeneralLedgerActionsBar from './GeneralLedgerActionsBar';
import withGeneralLedgerActions from './withGeneralLedgerActions'; import withGeneralLedgerActions from './withGeneralLedgerActions';
import withDashboard from 'containers/Dashboard/withDashboard'; import withDashboardActions from 'containers/Dashboard/withDashboardActions';
import withAccountsActions from 'containers/Accounts/withAccountsActions'; import withAccountsActions from 'containers/Accounts/withAccountsActions';
import withSettings from 'containers/Settings/withSettings'; import withSettings from 'containers/Settings/withSettings';
function GeneralLedger({ function GeneralLedger({
// #withDashboard // #withDashboardActions
changePageTitle, changePageTitle,
// #withGeneralLedgerActions // #withGeneralLedgerActions
@@ -94,7 +94,7 @@ function GeneralLedger({
export default compose( export default compose(
withGeneralLedgerActions, withGeneralLedgerActions,
withDashboard, withDashboardActions,
withAccountsActions, withAccountsActions,
withSettings, withSettings,
)(GeneralLedger); )(GeneralLedger);

View File

@@ -154,6 +154,7 @@ function GeneralLedgerTable({
fixedSizeHeight={1000} fixedSizeHeight={1000}
expandable={true} expandable={true}
expandToggleColumn={1} expandToggleColumn={1}
sticky={true}
/> />
</FinancialSheet> </FinancialSheet>
); );

View File

@@ -12,14 +12,14 @@ import DashboardPageContent from 'components/Dashboard/DashboardPageContent';
import DashboardInsider from 'components/Dashboard/DashboardInsider'; import DashboardInsider from 'components/Dashboard/DashboardInsider';
import SettingsConnect from 'connectors/Settings.connect'; import SettingsConnect from 'connectors/Settings.connect';
import withDashboard from 'containers/Dashboard/withDashboard'; import withDashboardActions from 'containers/Dashboard/withDashboardActions';
import withJournalActions from './withJournalActions'; import withJournalActions from './withJournalActions';
function Journal({ function Journal({
// #withJournalActions // #withJournalActions
requestFetchJournalSheet, requestFetchJournalSheet,
// #withDashboard // #withDashboardActions
changePageTitle, changePageTitle,
// #withPreferences // #withPreferences
@@ -93,7 +93,7 @@ function Journal({
} }
export default compose( export default compose(
withDashboard, withDashboardActions,
withJournalActions, withJournalActions,
SettingsConnect, SettingsConnect,
)(Journal); )(Journal);

View File

@@ -121,6 +121,7 @@ function JournalSheetTable({
id: 'this_report_does_not_contain_any_data_between_date_period', id: 'this_report_does_not_contain_any_data_between_date_period',
})} })}
expanded={expandedRows} expanded={expandedRows}
sticky={true}
/> />
</FinancialSheet> </FinancialSheet>
); );

View File

@@ -10,14 +10,14 @@ import ProfitLossActionsBar from './ProfitLossActionsBar';
import DashboardInsider from 'components/Dashboard/DashboardInsider' import DashboardInsider from 'components/Dashboard/DashboardInsider'
import DashboardPageContent from 'components/Dashboard/DashboardPageContent' import DashboardPageContent from 'components/Dashboard/DashboardPageContent'
import withDashboard from 'containers/Dashboard/withDashboard'; import withDashboardActions from 'containers/Dashboard/withDashboardActions';
import withProfitLossActions from './withProfitLossActions'; import withProfitLossActions from './withProfitLossActions';
import withProfitLoss from './withProfitLoss'; import withProfitLoss from './withProfitLoss';
import SettingsConnect from 'connectors/Settings.connect'; import SettingsConnect from 'connectors/Settings.connect';
function ProfitLossSheet({ function ProfitLossSheet({
// #withDashboard // #withDashboardActions
changePageTitle, changePageTitle,
// #withProfitLossActions // #withProfitLossActions
@@ -85,7 +85,7 @@ function ProfitLossSheet({
} }
export default compose( export default compose(
withDashboard, withDashboardActions,
withProfitLossActions, withProfitLossActions,
withProfitLoss(({ profitLossSheetLoading }) => ({ withProfitLoss(({ profitLossSheetLoading }) => ({
profitLossSheetLoading, profitLossSheetLoading,

View File

@@ -7,12 +7,9 @@ import DataTable from 'components/DataTable';
import Money from 'components/Money'; import Money from 'components/Money';
import { compose, defaultExpanderReducer } from 'utils'; import { compose, defaultExpanderReducer } from 'utils';
import { import { getFinancialSheetIndexByQuery } from 'store/financialStatement/financialStatements.selectors';
getFinancialSheetIndexByQuery,
} from 'store/financialStatement/financialStatements.selectors';
import withProfitLossDetail from './withProfitLoss'; import withProfitLossDetail from './withProfitLoss';
function ProfitLossSheetTable({ function ProfitLossSheetTable({
// #withProfitLoss // #withProfitLoss
profitLossTableRows, profitLossTableRows,
@@ -24,63 +21,79 @@ function ProfitLossSheetTable({
onFetchData, onFetchData,
companyName, companyName,
}) { }) {
const { formatMessage } = useIntl();
const {formatMessage} =useIntl(); const columns = useMemo(
() => [
const columns = useMemo(() => [
{
Header: formatMessage({id:'account_name'}),
accessor: 'name',
className: "name",
},
{
Header: formatMessage({id:'acc_code'}),
accessor: 'code',
className: "account_code",
},
...(profitLossQuery.display_columns_type === 'total') ? [
{ {
Header: formatMessage({id:'total'}), Header: formatMessage({ id: 'account_name' }),
Cell: ({ cell }) => { accessor: 'name',
const row = cell.row.original; className: 'name',
if (row.total) { },
return (<Money amount={row.total.formatted_amount} currency={'USD'} />); {
} Header: formatMessage({ id: 'acc_code' }),
return ''; accessor: 'code',
}, className: 'account_code',
className: "total", },
} ...(profitLossQuery.display_columns_type === 'total'
] : [], ? [
...(profitLossQuery.display_columns_type === 'date_periods') ? {
(profitLossColumns.map((column, index) => ({ Header: formatMessage({ id: 'total' }),
id: `date_period_${index}`, Cell: ({ cell }) => {
Header: column, const row = cell.row.original;
accessor: (row) => { if (row.total) {
if (row.periods && row.periods[index]) { return (
const amount = row.periods[index].formatted_amount; <Money
return (<Money amount={amount} currency={'USD'} />); amount={row.total.formatted_amount}
} currency={'USD'}
return ''; />
}, );
width: 100, }
}))) return '';
: [], },
], [profitLossQuery.display_columns_type, profitLossColumns,formatMessage]); className: 'total',
},
]
: []),
...(profitLossQuery.display_columns_type === 'date_periods'
? profitLossColumns.map((column, index) => ({
id: `date_period_${index}`,
Header: column,
accessor: (row) => {
if (row.periods && row.periods[index]) {
const amount = row.periods[index].formatted_amount;
return <Money amount={amount} currency={'USD'} />;
}
return '';
},
width: 100,
}))
: []),
],
[profitLossQuery.display_columns_type, profitLossColumns, formatMessage],
);
// Handle data table fetch data. // Handle data table fetch data.
const handleFetchData = useCallback((...args) => { const handleFetchData = useCallback(
onFetchData && onFetchData(...args); (...args) => {
}, [onFetchData]); onFetchData && onFetchData(...args);
},
[onFetchData],
);
// Retrieve default expanded rows of balance sheet. // Retrieve default expanded rows of balance sheet.
const expandedRows = useMemo(() => const expandedRows = useMemo(
defaultExpanderReducer(profitLossTableRows, 1), () => defaultExpanderReducer(profitLossTableRows, 1),
[profitLossTableRows]); [profitLossTableRows],
);
// Retrieve conditional datatable row classnames. // Retrieve conditional datatable row classnames.
const rowClassNames = useCallback((row) => ({ const rowClassNames = useCallback(
[`row--${row.rowType}`]: row.rowType, (row) => ({
}), []); [`row--${row.rowType}`]: row.rowType,
}),
[],
);
return ( return (
<FinancialSheet <FinancialSheet
@@ -90,8 +103,8 @@ function ProfitLossSheetTable({
toDate={profitLossQuery.to_date} toDate={profitLossQuery.to_date}
name="profit-loss-sheet" name="profit-loss-sheet"
loading={loading} loading={loading}
basis={profitLossQuery.basis}> basis={profitLossQuery.basis}
>
<DataTable <DataTable
className="bigcapital-datatable--financial-report" className="bigcapital-datatable--financial-report"
columns={columns} columns={columns}
@@ -100,7 +113,9 @@ function ProfitLossSheetTable({
expanded={expandedRows} expanded={expandedRows}
rowClassNames={rowClassNames} rowClassNames={rowClassNames}
expandable={true} expandable={true}
expandToggleColumn={1} /> expandToggleColumn={1}
sticky={true}
/>
</FinancialSheet> </FinancialSheet>
); );
} }
@@ -116,9 +131,11 @@ const withProfitLossTable = connect(mapStateToProps);
export default compose( export default compose(
withProfitLossTable, withProfitLossTable,
withProfitLossDetail(({ profitLossQuery, profitLossColumns, profitLossTableRows }) => ({ withProfitLossDetail(
profitLossColumns, ({ profitLossQuery, profitLossColumns, profitLossTableRows }) => ({
profitLossQuery, profitLossColumns,
profitLossTableRows, profitLossQuery,
})), profitLossTableRows,
)(ProfitLossSheetTable); }),
),
)(ProfitLossSheetTable);

View File

@@ -11,14 +11,14 @@ import DashboardInsider from 'components/Dashboard/DashboardInsider';
import { compose } from 'utils'; import { compose } from 'utils';
import DashboardPageContent from 'components/Dashboard/DashboardPageContent'; import DashboardPageContent from 'components/Dashboard/DashboardPageContent';
import withDashboard from 'containers/Dashboard/withDashboard'; import withDashboardActions from 'containers/Dashboard/withDashboardActions';
import withTrialBalanceActions from './withTrialBalanceActions'; import withTrialBalanceActions from './withTrialBalanceActions';
import withTrialBalance from './withTrialBalance'; import withTrialBalance from './withTrialBalance';
import withSettings from 'containers/Settings/withSettings'; import withSettings from 'containers/Settings/withSettings';
function TrialBalanceSheet({ function TrialBalanceSheet({
// #withDashboard // #withDashboardActions
changePageTitle, changePageTitle,
// #withTrialBalanceActions // #withTrialBalanceActions
@@ -93,7 +93,7 @@ function TrialBalanceSheet({
} }
export default compose( export default compose(
withDashboard, withDashboardActions,
withTrialBalanceActions, withTrialBalanceActions,
withTrialBalance(({ trialBalanceSheetLoading }) => ({ withTrialBalance(({ trialBalanceSheetLoading }) => ({
trialBalanceSheetLoading, trialBalanceSheetLoading,

View File

@@ -80,6 +80,7 @@ function TrialBalanceSheetTable({
onFetchData={handleFetchData} onFetchData={handleFetchData}
expandable={true} expandable={true}
expandToggleColumn={1} expandToggleColumn={1}
sticky={true}
/> />
</FinancialSheet> </FinancialSheet>
); );

View File

@@ -31,7 +31,7 @@ import withAccounts from 'containers/Accounts/withAccounts';
import withMediaActions from 'containers/Media/withMediaActions'; import withMediaActions from 'containers/Media/withMediaActions';
import useMedia from 'hooks/useMedia'; import useMedia from 'hooks/useMedia';
import withItemDetail from 'containers/Items/withItemDetail' import withItemDetail from 'containers/Items/withItemDetail'
import withDashboardActions from 'containers/Dashboard/withDashboard'; import withDashboardActions from 'containers/Dashboard/withDashboardActions';
import withAccountDetail from 'containers/Accounts/withAccountDetail'; import withAccountDetail from 'containers/Accounts/withAccountDetail';
import { compose } from 'utils'; import { compose } from 'utils';
@@ -47,7 +47,7 @@ const ItemForm = ({
onFormSubmit, onFormSubmit,
onCancelForm, onCancelForm,
// #withDashboard // #withDashboardActions
changePageTitle, changePageTitle,
// #withItemCategories // #withItemCategories

View File

@@ -5,7 +5,7 @@ import { useQuery } from 'react-query';
import DashboardInsider from 'components/Dashboard/DashboardInsider'; import DashboardInsider from 'components/Dashboard/DashboardInsider';
import ItemForm from 'containers/Items/ItemForm'; import ItemForm from 'containers/Items/ItemForm';
import withDashboard from 'containers/Dashboard/withDashboard'; import withDashboardActions from 'containers/Dashboard/withDashboardActions';
import withAccountsActions from 'containers/Accounts/withAccountsActions'; import withAccountsActions from 'containers/Accounts/withAccountsActions';
import withItemCategoriesActions from 'containers/Items/withItemCategoriesActions'; import withItemCategoriesActions from 'containers/Items/withItemCategoriesActions';
import withItemsActions from './withItemsActions'; import withItemsActions from './withItemsActions';
@@ -14,7 +14,7 @@ import { compose } from 'utils';
const ItemFormContainer = ({ const ItemFormContainer = ({
// #withDashboard // #withDashboardActions
changePageTitle, changePageTitle,
// #withAccountsActions // #withAccountsActions
@@ -64,7 +64,7 @@ const handleCancel =useCallback(()=>{
}; };
export default compose( export default compose(
withDashboard, withDashboardActions,
withAccountsActions, withAccountsActions,
withItemCategoriesActions, withItemCategoriesActions,
withItemsActions withItemsActions

View File

@@ -19,7 +19,7 @@ import FilterDropdown from 'components/FilterDropdown';
import withResourceDetail from 'containers/Resources/withResourceDetails'; import withResourceDetail from 'containers/Resources/withResourceDetails';
import withDialog from 'connectors/Dialog.connector'; import withDialog from 'connectors/Dialog.connector';
import withDashboard from 'containers/Dashboard/withDashboard'; import withDashboardActions from 'containers/Dashboard/withDashboardActions';
import { compose } from 'utils'; import { compose } from 'utils';
@@ -117,7 +117,7 @@ const withItemsCategoriesActionsBar = connect(mapStateToProps);
export default compose( export default compose(
withItemsCategoriesActionsBar, withItemsCategoriesActionsBar,
withDialog, withDialog,
withDashboard, withDashboardActions,
withResourceDetail(({ resourceFields }) => ({ withResourceDetail(({ resourceFields }) => ({
resourceFields, resourceFields,
})) }))

View File

@@ -23,13 +23,13 @@ import AppToaster from 'components/AppToaster';
import withItems from 'containers/Items/withItems'; import withItems from 'containers/Items/withItems';
import withResourceActions from 'containers/Resources/withResourcesActions'; import withResourceActions from 'containers/Resources/withResourcesActions';
import withDashboardActions from 'containers/Dashboard/withDashboard'; import withDashboardActions from 'containers/Dashboard/withDashboardActions';
import withItemsActions from 'containers/Items/withItemsActions'; import withItemsActions from 'containers/Items/withItemsActions';
import withViewsActions from 'containers/Views/withViewsActions'; import withViewsActions from 'containers/Views/withViewsActions';
function ItemsList({ function ItemsList({
// #withDashboard // #withDashboardActions
changePageTitle, changePageTitle,
// #withResourceActions // #withResourceActions

View File

@@ -16,7 +16,7 @@ import { compose } from 'utils';
import {useUpdateEffect} from 'hooks'; import {useUpdateEffect} from 'hooks';
import withItemsActions from 'containers/Items/withItemsActions'; import withItemsActions from 'containers/Items/withItemsActions';
import withDashboard from 'containers/Dashboard/withDashboard'; import withDashboardActions from 'containers/Dashboard/withDashboardActions';
import withViewDetail from 'containers/Views/withViewDetails'; import withViewDetail from 'containers/Views/withViewDetails';
import withItems from 'containers/Items/withItems'; import withItems from 'containers/Items/withItems';
@@ -34,7 +34,7 @@ function ItemsViewsTabs({
addItemsTableQueries, addItemsTableQueries,
changeItemsCurrentView, changeItemsCurrentView,
// #withDashboard // #withDashboardActions
setTopbarEditView, setTopbarEditView,
changePageSubtitle, changePageSubtitle,
@@ -121,7 +121,7 @@ const withItemsViewsTabs = connect(mapStateToProps);
export default compose( export default compose(
withRouter, withRouter,
withItemsViewsTabs, withItemsViewsTabs,
withDashboard, withDashboardActions,
withItemsActions, withItemsActions,
withViewDetail, withViewDetail,
withItems( ({ itemsViews }) => ({ withItems( ({ itemsViews }) => ({

View File

@@ -18,7 +18,6 @@ import LoadingIndicator from 'components/LoadingIndicator';
import DataTable from 'components/DataTable'; import DataTable from 'components/DataTable';
import AppToaster from 'components/AppToaster'; import AppToaster from 'components/AppToaster';
import withDashboard from 'connectors/Dashboard.connector';
import withCurrencies from 'containers/Currencies/withCurrencies'; import withCurrencies from 'containers/Currencies/withCurrencies';
import withCurrenciesActions from 'containers/Currencies/withCurrenciesActions'; import withCurrenciesActions from 'containers/Currencies/withCurrenciesActions';
import { FormattedMessage as T, useIntl } from 'react-intl'; import { FormattedMessage as T, useIntl } from 'react-intl';
@@ -157,5 +156,4 @@ export default compose(
})), })),
withCurrenciesActions, withCurrenciesActions,
DialogConnect, DialogConnect,
withDashboard
)(CurrenciesList); )(CurrenciesList);

View File

@@ -25,7 +25,7 @@ import LoadingIndicator from 'components/LoadingIndicator';
import AppToaster from 'components/AppToaster'; import AppToaster from 'components/AppToaster';
import DialogConnect from 'connectors/Dialog.connector'; import DialogConnect from 'connectors/Dialog.connector';
import withDashboard from 'containers/Dashboard/withDashboard'; import withDashboardActions from 'containers/Dashboard/withDashboardActions';
import withUsers from 'containers/Users/withUsers'; import withUsers from 'containers/Users/withUsers';
import withUsersActions from 'containers/Users/withUsersActions'; import withUsersActions from 'containers/Users/withUsersActions';
@@ -240,7 +240,7 @@ function UsersListPreferences({
export default compose( export default compose(
DialogConnect, DialogConnect,
withDashboard, withDashboardActions,
withUsers, withUsers,
withUsersActions, withUsersActions,
)(UsersListPreferences); )(UsersListPreferences);

View File

@@ -1,7 +1,7 @@
import {connect} from 'react-redux'; import {connect} from 'react-redux';
import {compose} from 'utils'; import {compose} from 'utils';
import withDashboard from 'containers/Dashboard/withDashboard'; import withDashboardActions from 'containers/Dashboard/withDashboardActions';
import withResourceDetail from 'containers/Resources/withResourceDetails'; import withResourceDetail from 'containers/Resources/withResourceDetails';
import withViewsActions from 'containers/Views/withViewsActions'; import withViewsActions from 'containers/Views/withViewsActions';
import withViewsDetails from 'containers/Views/withViewDetails'; import withViewsDetails from 'containers/Views/withViewDetails';
@@ -16,7 +16,7 @@ const mapStateToProps = (state, ownProps) => {
const viewFormConnect = connect(mapStateToProps); const viewFormConnect = connect(mapStateToProps);
export default compose( export default compose(
withDashboard, withDashboardActions,
withViewsActions, withViewsActions,
withViewsDetails, withViewsDetails,
viewFormConnect, viewFormConnect,

View File

@@ -14,11 +14,12 @@ import { If } from 'components';
import withResourcesActions from 'containers/Resources/withResourcesActions'; import withResourcesActions from 'containers/Resources/withResourcesActions';
import withViewsActions from 'containers/Views/withViewsActions'; import withViewsActions from 'containers/Views/withViewsActions';
import withDashboard from 'containers/Dashboard/withDashboard'; import withDashboardActions from 'containers/Dashboard/withDashboardActions';
// @flow // @flow
function ViewFormPage({ function ViewFormPage({
// #withDashboardActions
changePageTitle, changePageTitle,
changePageSubtitle, changePageSubtitle,
@@ -119,7 +120,7 @@ function ViewFormPage({
} }
export default compose( export default compose(
withDashboard, withDashboardActions,
withViewsActions, withViewsActions,
withResourcesActions withResourcesActions
)(ViewFormPage); )(ViewFormPage);

View File

@@ -3,10 +3,12 @@ import thunkMiddleware from 'redux-thunk';
import monitorReducerEnhancer from 'store/enhancers/monitorReducer'; import monitorReducerEnhancer from 'store/enhancers/monitorReducer';
import loggerMiddleware from 'middleware/logger' import loggerMiddleware from 'middleware/logger'
import rootReducer from 'store/reducers'; import rootReducer from 'store/reducers';
import { loadState, saveState } from 'store/localStorage'; import persistState from 'redux-localstorage'
const persistPaths = ['dashboard', 'authentication'];
const createStore = (initialState = { const createStore = (initialState = {
...loadState(), // ...loadState(),
}) => { }) => {
/** /**
|-------------------------------------------------- |--------------------------------------------------
@@ -25,6 +27,7 @@ const createStore = (initialState = {
*/ */
const enhancers = [ const enhancers = [
monitorReducerEnhancer, monitorReducerEnhancer,
persistState(persistPaths, { key: 'bigcapital' }),
]; ];
let composeEnhancers = compose; let composeEnhancers = compose;
@@ -45,12 +48,6 @@ const createStore = (initialState = {
composeEnhancers(applyMiddleware(...middleware), ...enhancers) composeEnhancers(applyMiddleware(...middleware), ...enhancers)
); );
store.asyncReducers = {}; store.asyncReducers = {};
store.subscribe(() => {
saveState({
authentication: store.getState().authentication,
});
});
return store; return store;
}; };
export default createStore(); export default createStore();

View File

@@ -5,6 +5,7 @@ const initialState = {
pageTitle: '', pageTitle: '',
pageSubtitle: 'Hello World', pageSubtitle: 'Hello World',
preferencesPageTitle: '', preferencesPageTitle: '',
sidebarExpended: true,
dialogs: {}, dialogs: {},
topbarEditViewId: null, topbarEditViewId: null,
requestsLoading: 0, requestsLoading: 0,
@@ -52,6 +53,10 @@ export default createReducer(initialState, {
[t.SET_DASHBOARD_REQUEST_COMPLETED]: (state, action) => { [t.SET_DASHBOARD_REQUEST_COMPLETED]: (state, action) => {
const requestsLoading = state.requestsLoading - 1; const requestsLoading = state.requestsLoading - 1;
state.requestsLoading = Math.max(requestsLoading, 0); state.requestsLoading = Math.max(requestsLoading, 0);
},
[t.SIDEBAR_EXPEND_TOGGLE]: (state) => {
state.sidebarExpended = !state.sidebarExpended;
} }
}); });

View File

@@ -11,4 +11,5 @@ export default {
SET_TOPBAR_EDIT_VIEW: 'SET_TOPBAR_EDIT_VIEW', SET_TOPBAR_EDIT_VIEW: 'SET_TOPBAR_EDIT_VIEW',
SET_DASHBOARD_REQUEST_LOADING: 'SET_DASHBOARD_REQUEST_LOADING', SET_DASHBOARD_REQUEST_LOADING: 'SET_DASHBOARD_REQUEST_LOADING',
SET_DASHBOARD_REQUEST_COMPLETED: 'SET_DASHBOARD_REQUEST_COMPLETED', SET_DASHBOARD_REQUEST_COMPLETED: 'SET_DASHBOARD_REQUEST_COMPLETED',
SIDEBAR_EXPEND_TOGGLE: 'SIDEBAR_EXPEND_TOGGLE',
}; };

View File

@@ -36,5 +36,4 @@ export default {
...search, ...search,
...register, ...register,
...exchangeRate, ...exchangeRate,
}; };

View File

@@ -11,15 +11,16 @@ $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>");
$sidebar-zindex: 15;
$pt-font-family: Noto Sans, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, Ubuntu, Cantarell, Open Sans, Helvetica Neue, Icons16, sans-serif;
// 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;
@import 'functions'; @import 'functions';
// Objects // Objects

View File

@@ -1,8 +1,6 @@
.bigcapital-datatable{ .bigcapital-datatable{
display: block; display: block;
overflow-x: auto;
overflow-y: hidden;
.dashboard__page-content &{ .dashboard__page-content &{
@@ -111,6 +109,9 @@
} }
.tbody{ .tbody{
width: 100%;
overflow: scroll;
.tr .td{ .tr .td{
border-bottom: 1px solid #E8E8E8; border-bottom: 1px solid #E8E8E8;
align-items: center; align-items: center;
@@ -198,6 +199,41 @@
} }
} }
&.has-sticky {
.thead,
.tfoot {
position: sticky;
z-index: 1;
}
.thead {
top: 0;
// box-shadow: 0px 3px 3px #ccc;
}
.tfoot {
bottom: 0;
// box-shadow: 0px -3px 3px #ccc;
}
.tbody {
position: relative;
z-index: 0;
}
[data-sticky-td] {
position: sticky;
}
[data-sticky-last-left-td] {
// box-shadow: 2px 0px 3px #ccc;
}
[data-sticky-first-right-td] {
// box-shadow: -2px 0px 3px #ccc;
}
}
&.has-virtualized-rows{ &.has-virtualized-rows{
.tbody{ .tbody{
overflow-y: scroll; overflow-y: scroll;

View File

@@ -11,6 +11,10 @@ $form-check-input-indeterminate-bg-image: url("data:image/svg+xml,<svg xmlns='ht
background: #fff; background: #fff;
padding: 14px 16px; padding: 14px 16px;
border-top: 1px solid #ececec; border-top: 1px solid #ececec;
.has-mini-sidebar &{
left: 50px;
}
} }
} }

View File

@@ -202,6 +202,11 @@
display: flex; display: flex;
flex-direction: column; flex-direction: column;
margin-left: 220px; margin-left: 220px;
.sidebar--mini-sidebar + &{
margin-left: 50px;
width: calc(100% - 50px);
}
} }
&__insider{ &__insider{
@@ -215,7 +220,6 @@
} }
&__page-content{ &__page-content{
// padding: 22px;
.bigcapital-datatable{ .bigcapital-datatable{
@@ -307,9 +311,8 @@
left: calc(50% - 250px); left: calc(50% - 250px);
z-index: 21; z-index: 21;
border-radius: 3px; border-radius: 3px;
-webkit-box-shadow: 0 0 0 1px rgba(16, 22, 26, 0.1), box-shadow: 0 0 0 1px rgba(16, 22, 26, 0.1),
0 4px 8px rgba(16, 22, 26, 0.2), 0 18px 46px 6px rgba(16, 22, 26, 0.2); 0 4px 8px rgba(16, 22, 26, 0.2),
box-shadow: 0 0 0 1px rgba(16, 22, 26, 0.1), 0 4px 8px rgba(16, 22, 26, 0.2),
0 18px 46px 6px rgba(16, 22, 26, 0.2); 0 18px 46px 6px rgba(16, 22, 26, 0.2);
background-color: #fff; background-color: #fff;
width: 500px; width: 500px;

View File

@@ -40,7 +40,6 @@
align-items: center; align-items: center;
} }
&__header.is-hidden + .financial-statement__body{ &__header.is-hidden + .financial-statement__body{
border-top: 20px solid #FDFDFD; border-top: 20px solid #FDFDFD;
@@ -84,17 +83,26 @@
&__table{ &__table{
margin-top: 24px; margin-top: 24px;
.tbody{ .table{
.code.td{ .tbody,
color: #777; .thead{
.tr .td,
.tr .th{
background: #fff;
}
} }
} .tbody{
.tr.no-results{ .code.td{
.td{ color: #777;
flex-direction: column; }
padding: 20px; }
color: #666; .tr.no-results{
align-items: center; .td{
flex-direction: column;
padding: 20px;
color: #666;
align-items: center;
}
} }
} }
} }

View File

@@ -7,10 +7,11 @@ $sidebar-popover-submenu-bg: rgb(1, 20, 62);
.sidebar { .sidebar {
background: $sidebar-background; background: $sidebar-background;
color: $sidebar-text-color;
width: $sidebar-width; width: $sidebar-width;
color: $sidebar-text-color;
position: fixed; position: fixed;
height: 100%; height: 100%;
z-index: $sidebar-zindex;
.ScrollbarsCustom-Track { .ScrollbarsCustom-Track {
&.ScrollbarsCustom-TrackY, &.ScrollbarsCustom-TrackY,
@@ -45,6 +46,10 @@ $sidebar-popover-submenu-bg: rgb(1, 20, 62);
} }
} }
&__scroll-wrapper{
height: 100%;
}
&-menu { &-menu {
background: transparent; background: transparent;
padding: 0; padding: 0;
@@ -120,4 +125,75 @@ $sidebar-popover-submenu-bg: rgb(1, 20, 62);
margin: 4px 0; margin: 4px 0;
} }
} }
&--mini-sidebar{
white-space: nowrap;
width: 50px;
// Hide text of bigcapital logo.
.sidebar__head-logo{
.bp3-icon-bigcapital{
path:not(.path-1):not(.path-2) {
opacity: 0;
}
}
}
// Hide text of menu items and right caret icon.
.bp3-collapse,
.bp3-icon-caret-right,
.bp3-menu-item .bp3-text-overflow-ellipsis{
display: none;
}
.sidebar__menu{
.bp3-menu{
> li:not(.bp3-submenu):not(.bp3-menu-divider):not(.has-icon){
.bp3-menu-item{
&:before{
content: "";
height: 18px;
width: 18px;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' data-icon='ellipsis-h' width='18' height='18' fill='%235c7080' viewBox='0 0 512 512'%3E%3Cdesc%3Eellipsis-h%3C/desc%3E%3Cpath d='M304 256c0 26.5-21.5 48-48 48s-48-21.5-48-48 21.5-48 48-48 48 21.5 48 48zm120-48c-26.5 0-48 21.5-48 48s21.5 48 48 48 48-21.5 48-48-21.5-48-48-48zm-336 0c-26.5 0-48 21.5-48 48s21.5 48 48 48 48-21.5 48-48-21.5-48-48-48z' class='path-1' fill-rule='evenodd'%3E%3C/path%3E%3C/svg%3E");
}
}
}
}
}
.sidebar__scroll-wrapper{
background: $sidebar-background;
transition: min-width 0.15s ease-in-out;
min-width: 50px;
&:hover{
min-width: $sidebar-width;
.sidebar__head-logo{
.bp3-icon-bigcapital{
path:not(.path-1):not(.path-2) {
opacity: 1;
}
}
}
.bp3-collapse,
.bp3-icon-caret-right,
.bp3-menu-item .bp3-text-overflow-ellipsis{
display: block;
}
.sidebar__menu .bp3-menu > li:not(.bp3-submenu):not(.bp3-menu-divider) .bp3-menu-item{
&:before{
display: none;
}
}
}
}
}
} }

View File

@@ -16,10 +16,6 @@ exports.up = function(knex) {
table.string('invoice_interval'); table.string('invoice_interval');
table.timestamps(); table.timestamps();
}).then(() => {
return knex.seed.run({
specific: 'seed_subscriptions_plans.js'
})
}); });
}; };