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

View File

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

View File

@@ -1,23 +1,30 @@
import React from 'react';
import { Switch, Route } from 'react-router';
import classNames from 'classnames';
import Sidebar from 'components/Sidebar/Sidebar';
import DashboardContent from 'components/Dashboard/DashboardContent';
import DialogsContainer from 'components/DialogsContainer';
import PreferencesContent from 'components/Preferences/PreferencesContent';
import PreferencesSidebar from 'components/Preferences/PreferencesSidebar';
import Search from 'containers/GeneralSearch/Search';
import withDashboard from 'containers/Dashboard/withDashboard';
export default function Dashboard() {
import { compose } from 'utils';
function Dashboard({ sidebarExpended }) {
return (
<div className='dashboard'>
<div className={classNames('dashboard', {
'has-mini-sidebar': !sidebarExpended,
})}>
<Switch>
<Route path='/preferences'>
<Route path="/preferences">
<Sidebar />
<PreferencesSidebar />
<PreferencesContent />
</Route>
<Route path='/'>
<Route path="/">
<Sidebar />
<DashboardContent />
</Route>
@@ -28,3 +35,9 @@ export default function Dashboard() {
</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 Icon from 'components/Icon';
import withDashboardActions from 'containers/Dashboard/withDashboardActions';
import withDashboard from 'containers/Dashboard/withDashboard';
import { compose } from 'utils';
function DashboardTopbar({
// #withDashboard
pageTitle,
pageSubtitle,
editViewId,
globalSearchShow,
// #withDashboardActions
toggleSidebarExpend,
// #withGlobalSearch
openGlobalSearch,
}) {
const history = useHistory();
@@ -38,11 +47,15 @@ function DashboardTopbar({
onClick={handlerClickEditView}
/>
);
const handleSidebarToggleBtn = () => {
toggleSidebarExpend();
};
return (
<div class='dashboard__topbar'>
<div class='dashboard__topbar-left'>
<div class='dashboard__topbar-sidebar-toggle'>
<Button minimal={true}>
<Button minimal={true} onClick={handleSidebarToggleBtn}>
<svg
xmlns='http://www.w3.org/2000/svg'
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(
SearchConnect,
connect(mapStateToProps)
withDashboard(({ pageTitle, pageSubtitle, editViewId }) => ({
pageTitle, pageSubtitle, editViewId
})),
withDashboardActions,
)(DashboardTopbar);

View File

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

View File

@@ -136,6 +136,7 @@ export default class MenuItem extends AbstractPureComponent2 {
intent,
labelClassName,
labelElement,
itemClassName,
multiline,
popoverProps,
shouldDismissPopover,
@@ -185,7 +186,7 @@ export default class MenuItem extends AbstractPureComponent2 {
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}>{
(dropdownType === 'collapse') ?
this.maybeRenderCollapse(target, children) :

View File

@@ -1,12 +1,41 @@
import * as React from 'react';
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 (
<div className='sidebar' id='sidebar'>
<Scrollbar noDefaultStyles={true}>
<div className='sidebar__inner'>{props.children}</div>
</Scrollbar>
<div
className={classNames('sidebar', {
'sidebar--mini-sidebar': !sidebarExpended,
})}
id="sidebar"
>
<div className={'sidebar__scroll-wrapper'}>
<Scrollbar noDefaultStyles={true}>
<div className="sidebar__inner">{children}</div>
</Scrollbar>
</div>
</div>
);
}
export default compose(
withDashboardActions,
withDashboard(({ sidebarExpended }) => ({
sidebarExpended,
})),
)(SidebarContainer);

View File

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

View File

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

View File

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

View File

@@ -12,7 +12,7 @@ import ManualJournalsViewTabs from 'containers/Accounting/ManualJournalsViewTabs
import ManualJournalsDataTable from 'containers/Accounting/ManualJournalsDataTable';
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 withViewsActions from 'containers/Views/withViewsActions';

View File

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

View File

@@ -15,7 +15,7 @@ import AccountsViewsTabs from 'containers/Accounts/AccountsViewsTabs';
import AccountsDataTable from 'containers/Accounts/AccountsDataTable';
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 withAccountsActions from 'containers/Accounts/withAccountsActions';
import withAccountsTableActions from 'containers/Accounts/withAccountsTableActions';
@@ -26,7 +26,7 @@ import { compose } from 'utils';
function AccountsChart({
// #withDashboard
// #withDashboardActions
changePageTitle,
// #withAccountsActions

View File

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

View File

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

View File

@@ -1,27 +1,15 @@
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,
}),
});
export default connect(null, mapActionsToProps);
export default (mapState) => {
const mapStateToProps = (state, props) => {
const mapped = {
pageTitle: state.dashboard.pageTitle,
pageSubtitle: state.dashboard.pageSubtitle,
editViewId: state.dashboard.topbarEditViewId,
sidebarExpended: state.dashboard.sidebarExpended,
};
return mapState ? mapState(mapped, state, props) : mapped;
};
return connect(mapStateToProps);
}

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -31,7 +31,7 @@ import withAccounts from 'containers/Accounts/withAccounts';
import withMediaActions from 'containers/Media/withMediaActions';
import useMedia from 'hooks/useMedia';
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 { compose } from 'utils';
@@ -47,7 +47,7 @@ const ItemForm = ({
onFormSubmit,
onCancelForm,
// #withDashboard
// #withDashboardActions
changePageTitle,
// #withItemCategories

View File

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

View File

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

View File

@@ -23,13 +23,13 @@ import AppToaster from 'components/AppToaster';
import withItems from 'containers/Items/withItems';
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 withViewsActions from 'containers/Views/withViewsActions';
function ItemsList({
// #withDashboard
// #withDashboardActions
changePageTitle,
// #withResourceActions

View File

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

View File

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

View File

@@ -25,7 +25,7 @@ import LoadingIndicator from 'components/LoadingIndicator';
import AppToaster from 'components/AppToaster';
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 withUsersActions from 'containers/Users/withUsersActions';
@@ -240,7 +240,7 @@ function UsersListPreferences({
export default compose(
DialogConnect,
withDashboard,
withDashboardActions,
withUsers,
withUsersActions,
)(UsersListPreferences);

View File

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

View File

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

View File

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

View File

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

View File

@@ -36,5 +36,4 @@ export default {
...search,
...register,
...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>");
$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.
@import '@blueprintjs/core/src/blueprint.scss';
@import '@blueprintjs/datetime/src/blueprint-datetime.scss';
@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';
// Objects

View File

@@ -1,8 +1,6 @@
.bigcapital-datatable{
display: block;
overflow-x: auto;
overflow-y: hidden;
.dashboard__page-content &{
@@ -111,6 +109,9 @@
}
.tbody{
width: 100%;
overflow: scroll;
.tr .td{
border-bottom: 1px solid #E8E8E8;
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{
.tbody{
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;
padding: 14px 16px;
border-top: 1px solid #ececec;
.has-mini-sidebar &{
left: 50px;
}
}
}

View File

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

View File

@@ -40,7 +40,6 @@
align-items: center;
}
&__header.is-hidden + .financial-statement__body{
border-top: 20px solid #FDFDFD;
@@ -84,17 +83,26 @@
&__table{
margin-top: 24px;
.tbody{
.code.td{
color: #777;
.table{
.tbody,
.thead{
.tr .td,
.tr .th{
background: #fff;
}
}
}
.tr.no-results{
.td{
flex-direction: column;
padding: 20px;
color: #666;
align-items: center;
.tbody{
.code.td{
color: #777;
}
}
.tr.no-results{
.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 {
background: $sidebar-background;
color: $sidebar-text-color;
width: $sidebar-width;
color: $sidebar-text-color;
position: fixed;
height: 100%;
z-index: $sidebar-zindex;
.ScrollbarsCustom-Track {
&.ScrollbarsCustom-TrackY,
@@ -45,6 +46,10 @@ $sidebar-popover-submenu-bg: rgb(1, 20, 62);
}
}
&__scroll-wrapper{
height: 100%;
}
&-menu {
background: transparent;
padding: 0;
@@ -120,4 +125,75 @@ $sidebar-popover-submenu-bg: rgb(1, 20, 62);
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.timestamps();
}).then(() => {
return knex.seed.run({
specific: 'seed_subscriptions_plans.js'
})
});
};