Merge pull request #816 from bigcapitalhq/darkmode

feat: Darkmode
This commit is contained in:
Ahmed Bouhuolia
2025-10-18 18:40:53 +02:00
committed by GitHub
224 changed files with 3429 additions and 2281 deletions

View File

@@ -1,5 +1,4 @@
import { Controller, Get } from '@nestjs/common'; import { Controller } from '@nestjs/common';
import { AppService } from './App.service';
@Controller() @Controller()
export class AppController {} export class AppController {}

View File

@@ -1,5 +1,5 @@
import { Model, raw } from 'objection';
import { DiscountType } from '@/common/types/Discount'; import { DiscountType } from '@/common/types/Discount';
import { BaseModel } from '@/models/Model';
import { Branch } from '@/modules/Branches/models/Branch.model'; import { Branch } from '@/modules/Branches/models/Branch.model';
import { Customer } from '@/modules/Customers/models/Customer'; import { Customer } from '@/modules/Customers/models/Customer';
import { ExportableModel } from '@/modules/Export/decorators/ExportableModel.decorator'; import { ExportableModel } from '@/modules/Export/decorators/ExportableModel.decorator';
@@ -8,7 +8,6 @@ import { TenantBaseModel } from '@/modules/System/models/TenantBaseModel';
import { InjectModelMeta } from '@/modules/Tenancy/TenancyModels/decorators/InjectModelMeta.decorator'; import { InjectModelMeta } from '@/modules/Tenancy/TenancyModels/decorators/InjectModelMeta.decorator';
import { ItemEntry } from '@/modules/TransactionItemEntry/models/ItemEntry'; import { ItemEntry } from '@/modules/TransactionItemEntry/models/ItemEntry';
import { Warehouse } from '@/modules/Warehouses/models/Warehouse.model'; import { Warehouse } from '@/modules/Warehouses/models/Warehouse.model';
import { mixin, Model, raw } from 'objection';
import { CreditNoteMeta } from './CreditNote.meta'; import { CreditNoteMeta } from './CreditNote.meta';
import { InjectModelDefaultViews } from '@/modules/Views/decorators/InjectModelDefaultViews.decorator'; import { InjectModelDefaultViews } from '@/modules/Views/decorators/InjectModelDefaultViews.decorator';
import { CreditNoteDefaultViews } from '../constants'; import { CreditNoteDefaultViews } from '../constants';

View File

@@ -1,4 +1,4 @@
<!DOCTYPE html> <!doctype html>
<html dir="ltr" lang="en"> <html dir="ltr" lang="en">
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
@@ -31,7 +31,7 @@
--> -->
<title>Bigcapital</title> <title>Bigcapital</title>
</head> </head>
<body> <body class="bp4-dark">
<noscript>You need to enable JavaScript to run this app.</noscript> <noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div> <div id="root"></div>
<div id="nprogress"></div> <div id="nprogress"></div>

View File

@@ -1,7 +1,7 @@
// @ts-nocheck // @ts-nocheck
import React from 'react'; import React from 'react';
import { Classes } from '@blueprintjs/core'; import { Classes } from '@blueprintjs/core';
import { ListSelect } from '../Select'; import { FSelect } from '../Forms';
import { getConditionTypeCompatators } from './utils'; import { getConditionTypeCompatators } from './utils';
export default function DynamicFilterCompatatorField({ export default function DynamicFilterCompatatorField({
@@ -11,9 +11,9 @@ export default function DynamicFilterCompatatorField({
const options = getConditionTypeCompatators(dataType); const options = getConditionTypeCompatators(dataType);
return ( return (
<ListSelect <FSelect
textProp={'label'} textAccessor={'label'}
selectedItemProp={'value'} valueAccessor={'value'}
items={options} items={options}
className={Classes.FILL} className={Classes.FILL}
filterable={false} filterable={false}

View File

@@ -1,16 +1,16 @@
// @ts-nocheck // @ts-nocheck
import React from 'react'; import React from 'react';
import { Formik, FastField, FieldArray } from 'formik'; import { Formik, FastField, FieldArray } from 'formik';
import { import { Button, Classes, InputGroup, MenuItem } from '@blueprintjs/core';
Button,
FormGroup,
Classes,
InputGroup,
MenuItem,
} from '@blueprintjs/core';
import { get, first, defaultTo, isEqual, isEmpty } from 'lodash'; import { get, first, defaultTo, isEqual, isEmpty } from 'lodash';
import intl from 'react-intl-universal'; import intl from 'react-intl-universal';
import { Choose, Icon, FormattedMessage as T, ListSelect } from '@/components'; import {
Choose,
Icon,
FormattedMessage as T,
FSelect,
FFormGroup,
} from '@/components';
import { useUpdateEffect } from '@/hooks'; import { useUpdateEffect } from '@/hooks';
import { import {
AdvancedFilterDropdownProvider, AdvancedFilterDropdownProvider,
@@ -58,38 +58,31 @@ function FilterConditionField() {
const conditionFieldPath = getConditionFieldPath('condition'); const conditionFieldPath = getConditionFieldPath('condition');
return ( return (
<FastField name={conditionFieldPath}> <FFormGroup className={'form-group--condition'} name={conditionFieldPath}>
{({ form, field }) => ( <Choose>
<FormGroup className={'form-group--condition'}> <Choose.When condition={conditionIndex === 0}>
<Choose> <InputGroup disabled value={intl.get('filter.when')} />
<Choose.When condition={conditionIndex === 0}> </Choose.When>
<InputGroup disabled value={intl.get('filter.when')} />
</Choose.When>
<Choose.Otherwise> <Choose.Otherwise>
<ListSelect <FSelect
selectedItem={field.value} name={conditionFieldPath}
textProp={'label'} textAccessor={'label'}
selectedItemProp={'value'} valueAccessor={'value'}
labelProp={'text'} labelAccessor={'text'}
items={conditionalsOptions} items={conditionalsOptions}
className={Classes.FILL} filterable={false}
filterable={false} popoverProps={{
onItemSelect={(option) => { inline: true,
form.setFieldValue(conditionFieldPath, option.value); minimal: true,
}} captureDismiss: true,
popoverProps={{ }}
inline: true, itemRenderer={ConditionItemRenderer}
minimal: true, className={Classes.FILL}
captureDismiss: true, />
}} </Choose.Otherwise>
itemRenderer={ConditionItemRenderer} </Choose>
/> </FFormGroup>
</Choose.Otherwise>
</Choose>
</FormGroup>
)}
</FastField>
); );
} }
@@ -103,20 +96,18 @@ function FilterCompatatorFilter() {
const fieldType = get(fieldMeta, 'fieldType'); const fieldType = get(fieldMeta, 'fieldType');
return ( return (
<FastField name={comparatorFieldPath}> <FFormGroup
{({ form, field }) => ( name={comparatorFieldPath}
<FormGroup className={'form-group--comparator'}> className={'form-group--comparator'}
<AdvancedFilterCompatatorField fastField
dataType={fieldType} >
className={Classes.FILL} <AdvancedFilterCompatatorField
selectedItem={field.value} name={comparatorFieldPath}
onItemSelect={(option) => { dataType={fieldType}
form.setFieldValue(comparatorFieldPath, option.value); className={Classes.FILL}
}} fastField
/> />
</FormGroup> </FFormGroup>
)}
</FastField>
); );
} }
@@ -169,11 +160,11 @@ function FilterFieldsField() {
return ( return (
<FastField name={fieldPath}> <FastField name={fieldPath}>
{({ field, form }) => ( {({ field, form }) => (
<FormGroup className={'form-group--fieldKey'}> <FFormGroup className={'form-group--fieldKey'} name={fieldPath}>
<ListSelect <FSelect
selectedItem={field.value} selectedItem={field.value}
textProp={'label'} textAccessor={'label'}
selectedItemProp={'value'} valueAccessor={'value'}
items={transformFieldsToOptions(fields)} items={transformFieldsToOptions(fields)}
className={Classes.FILL} className={Classes.FILL}
onItemSelect={(option) => { onItemSelect={(option) => {
@@ -188,7 +179,7 @@ function FilterFieldsField() {
captureDismiss: true, captureDismiss: true,
}} }}
/> />
</FormGroup> </FFormGroup>
)} )}
</FastField> </FastField>
); );
@@ -219,7 +210,7 @@ function FilterValueField() {
shouldUpdate={shouldFilterValueFieldUpdate} shouldUpdate={shouldFilterValueFieldUpdate}
> >
{({ form: { setFieldValue }, field }) => ( {({ form: { setFieldValue }, field }) => (
<FormGroup className={'form-group--value'}> <FFormGroup className={'form-group--value'} name={valueFieldPath}>
<AdvancedFilterValueField <AdvancedFilterValueField
isFocus={conditionIndex === 0} isFocus={conditionIndex === 0}
value={field.value} value={field.value}
@@ -231,7 +222,7 @@ function FilterValueField() {
setFieldValue(valueFieldPath, value); setFieldValue(valueFieldPath, value);
}} }}
/> />
</FormGroup> </FFormGroup>
)} )}
</FastField> </FastField>
); );

View File

@@ -15,6 +15,7 @@ export function Alert({ title, description, children, intent, className }) {
const AlertRoot = styled.div` const AlertRoot = styled.div`
border: 1px solid rgb(223, 227, 230); border: 1px solid rgb(223, 227, 230);
background: var(--color-alert-default-background);
padding: 12px; padding: 12px;
border-radius: 6px; border-radius: 6px;
margin-bottom: 20px; margin-bottom: 20px;
@@ -22,40 +23,40 @@ const AlertRoot = styled.div`
${(props) => ${(props) =>
props.intent === 'danger' && props.intent === 'danger' &&
` `
border-color: rgb(249, 198, 198); border-color: var(--color-alert-danger-border);
background: rgb(255, 248, 248); background: var(--color-alert-danger-background);
${AlertDesc} { ${AlertDesc} {
color: #d95759; color: var(--color-alert-danger-description-text);
} }
${AlertTitle} { ${AlertTitle} {
color: rgb(205, 43, 49); color: var(--color-alert-danger-title-text);
} }
`} `}
${(props) => ${(props) =>
props.intent === 'primary' && props.intent === 'primary' &&
` `
background: #fff; background: var(--color-alert-primary-background);
border-color: #98a8ee; border-color: var(--color-alert-primary-border);
${AlertTitle} { ${AlertTitle} {
color: #1a3bd4; color: var(--color-alert-primary-title-text);
} }
${AlertDesc} { ${AlertDesc} {
color: #455883; color: var(--color-alert-primary-description-text);
} }
`} `}
`; `;
export const AlertTitle = styled.h3` export const AlertTitle = styled.h3`
color: rgb(17, 24, 28); color: var(--color-alert-default-title-text);
margin-bottom: 4px; margin-bottom: 4px;
font-size: 14px; font-size: 14px;
font-weight: 600; font-weight: 600;
`; `;
export const AlertDesc = styled.p` export const AlertDesc = styled.p`
color: rgb(104, 112, 118); color: var(--color-alert-default-description-text);
margin: 0; margin: 0;
`; `;

View File

@@ -14,7 +14,7 @@
width: var(--aside-width); width: var(--aside-width);
min-width: var(--aside-min-width); min-width: var(--aside-min-width);
height: 100dvh; height: 100dvh;
border-left: 1px solid rgba(17, 20, 24, 0.15); border-left: 1px solid var(--color-app-shell-divider);
height: inherit; height: inherit;
overflow: auto; overflow: auto;
display: flex; display: flex;

View File

@@ -6,8 +6,8 @@
.title{ .title{
align-items: center; align-items: center;
background: #fff; background: var(--color-aside-background);
border-bottom: 1px solid #E1E2E9; border-bottom: 1px solid var(--color-aside-divider);
display: flex; display: flex;
flex: 0 0 auto; flex: 0 0 auto;
min-height: 40px; min-height: 40px;
@@ -20,6 +20,6 @@
display: flex; display: flex;
flex-direction: column; flex-direction: column;
flex: 1 1 auto; flex: 1 1 auto;
background-color: #fff; background-color: var(--color-aside-title-background);
overflow-y: auto; overflow-y: auto;
} }

View File

@@ -28,7 +28,6 @@ export function Aside({
<Box className={clsx(styles.root, className, classNames?.root)}> <Box className={clsx(styles.root, className, classNames?.root)}>
<Group position="apart" className={clsx(styles.title, classNames?.title)}> <Group position="apart" className={clsx(styles.title, classNames?.title)}>
{title} {title}
{hideCloseButton !== true && ( {hideCloseButton !== true && (
<Button <Button
aria-label="Close" aria-label="Close"
@@ -45,13 +44,13 @@ export function Aside({
); );
} }
interface AsideContentProps extends BoxProps {} interface AsideContentProps extends BoxProps { }
function AsideContent({ ...props }: AsideContentProps) { function AsideContent({ ...props }: AsideContentProps) {
return <Box {...props} className={clsx(styles.content, props?.className)} />; return <Box {...props} className={clsx(styles.content, props?.className)} />;
} }
interface AsideFooterProps extends BoxProps {} interface AsideFooterProps extends BoxProps { }
function AsideFooter({ ...props }: AsideFooterProps) { function AsideFooter({ ...props }: AsideFooterProps) {
return <Box {...props} />; return <Box {...props} />;

View File

@@ -104,13 +104,14 @@ const BankAccountWrap = styled.div`
display: flex; display: flex;
flex-direction: column; flex-direction: column;
border-radius: 3px; border-radius: 3px;
background: #fff; background: var(--color-bank-account-card-background);
margin: 8px; margin: 8px;
border: 1px solid #c8cad0; border: 1px solid var(--color-bank-account-card-border);
transition: all 0.1s ease-in-out; transition: all 0.1s ease-in-out;
color: var(--color-bank-account-card-text);
&:hover { &:hover {
border-color: #0153cc; border-color: var(--color-bank-account-card-hover-border);
} }
`; `;
@@ -124,7 +125,7 @@ const BankAccountTitle = styled.div`
font-size: 15px; font-size: 15px;
font-style: inherit; font-style: inherit;
letter-spacing: -0.003em; letter-spacing: -0.003em;
color: rgb(23, 43, 77); // color: rgb(23, 43, 77);
white-space: nowrap; white-space: nowrap;
font-weight: 600; font-weight: 600;
line-height: 1; line-height: 1;
@@ -137,7 +138,7 @@ const BankAccountTitle = styled.div`
const BnakAccountCode = styled.div` const BnakAccountCode = styled.div`
font-size: 11px; font-size: 11px;
margin-top: 4px; margin-top: 4px;
color: rgb(23, 43, 77); color: var(--color-bank-account-code-text);
display: inline-block; display: inline-block;
`; `;
@@ -145,7 +146,7 @@ const BankAccountBalanceWrap = styled.div`
display: flex; display: flex;
flex-direction: column; flex-direction: column;
margin-top: auto; margin-top: auto;
border-top: 1px solid #dfdfdf; border-top: 1px solid var(--color-bank-account-card-border);
padding: 10px 12px; padding: 10px 12px;
`; `;
@@ -153,7 +154,7 @@ const BankAccountBalanceAmount = styled.div`
font-size: 16px; font-size: 16px;
font-weight: 600; font-weight: 600;
line-height: 1; line-height: 1;
color: #57657e; // color: #57657e;
`; `;
const BankAccountBalanceLabel = styled.div` const BankAccountBalanceLabel = styled.div`
@@ -167,7 +168,7 @@ const BankAccountBalanceLabel = styled.div`
const MetaLineWrap = styled.div` const MetaLineWrap = styled.div`
font-size: 11px; font-size: 11px;
display: flex; display: flex;
color: #2f3c58; // color: #2f3c58;
&:not(:first-of-type) { &:not(:first-of-type) {
margin-top: 6px; margin-top: 6px;
@@ -178,7 +179,7 @@ const MetaLineTitle = styled.div``;
const MetaLineValue = styled.div` const MetaLineValue = styled.div`
box-sizing: border-box; box-sizing: border-box;
font-style: inherit; font-style: inherit;
background: rgb(223, 225, 230); background: var(--color-bank-account-card-tag-background);
line-height: initial; line-height: initial;
align-content: center; align-content: center;
padding: 0px 2px; padding: 0px 2px;
@@ -187,9 +188,9 @@ const MetaLineValue = styled.div`
text-transform: none; text-transform: none;
width: 30px; width: 30px;
min-width: 30px; min-width: 30px;
// color: rgb(23, 43, 77);
height: 16px; height: 16px;
text-align: center; text-align: center;
color: rgb(23, 43, 77);
font-size: 11px; font-size: 11px;
margin-left: auto; margin-left: auto;
`; `;

View File

@@ -2,7 +2,7 @@
import styled from 'styled-components'; import styled from 'styled-components';
export const ButtonLink = styled.button` export const ButtonLink = styled.button`
color: #0052cc; color: var(--color-primary);
border: 0; border: 0;
background: transparent; background: transparent;
cursor: pointer; cursor: pointer;

View File

@@ -1,8 +1,13 @@
// @ts-nocheck
import React from 'react'; import React from 'react';
import styled from 'styled-components'; import styled from 'styled-components';
export function Card({ className, style, children }) { interface CardProps {
className?: string;
style?: React.CSSProperties;
children?: React.ReactNode;
}
export function Card({ className, style, children }: CardProps) {
return ( return (
<CardRoot className={className} style={style}> <CardRoot className={className} style={style}>
{children} {children}
@@ -13,13 +18,18 @@ export function Card({ className, style, children }) {
const CardRoot = styled.div` const CardRoot = styled.div`
padding: 15px; padding: 15px;
margin: 15px; margin: 15px;
background: #fff; background: var(--color-card-background);
border: 1px solid #d2dce2; border: 1px solid var(--color-card-border);
`; `;
export const CardFooterActions = styled.div` export const CardFooterActions = styled.div`
--x-color-border: #e0e7ea;
.bp4-dark & {
--x-color-border: rgba(255, 255, 255, 0.25);
}
padding-top: 16px; padding-top: 16px;
border-top: 1px solid #e0e7ea; border-top: 1px solid var(--x-color-border);
margin-top: 30px; margin-top: 30px;
.bp4-button { .bp4-button {

View File

@@ -3,6 +3,10 @@ import { Card } from '../Card';
import { DataTable } from '../Datatable'; import { DataTable } from '../Datatable';
export const CommercialDocBox = styled(Card)` export const CommercialDocBox = styled(Card)`
--x-background-color: var(--x-white);
--x-background-color: var(--color-dark-gray2);
background-color: var(--x-background-color);
padding: 22px 20px; padding: 22px 20px;
`; `;
@@ -16,7 +20,7 @@ export const CommercialDocTopHeader = styled.div`
export const CommercialDocEntriesTable = styled(DataTable)` export const CommercialDocEntriesTable = styled(DataTable)`
.tbody .tr:last-child .td { .tbody .tr:last-child .td {
border-bottom: 1px solid #d2dce2; border-bottom-width: 1px;
} }
`; `;

View File

@@ -12,8 +12,9 @@ interface ContentTabItemRootProps {
} }
const ContentTabItemRoot = styled.button<ContentTabItemRootProps>` const ContentTabItemRoot = styled.button<ContentTabItemRootProps>`
flex: 1 0; flex: 1 0;
background: #fff; background: var(--color-card-background);
border: 1px solid #e1e2e8; border: 1px solid var(--color-content-tab-border);
color: var(--color-content-tab-text);
border-radius: 5px; border-radius: 5px;
padding: 11px; padding: 11px;
text-align: left; text-align: left;
@@ -28,32 +29,30 @@ const ContentTabItemRoot = styled.button<ContentTabItemRootProps>`
${(props) => ${(props) =>
props.active && props.active &&
` `
border-color: #1552c8; border-color: var(--color-content-tab-active-border);
color: var(--color-content-tab-active-text);
box-shadow: 0 0 0 0.25px #1552c8; box-shadow: 0 0 0 0.25px #1552c8;
${ContentTabTitle} { ${ContentTabTitle} {
color: #1552c8;
font-weight: 500; font-weight: 500;
} }
${ContentTabDesc} { ${ContentTabDesc} {
color: #1552c8;
} }
`} `}
&:hover, &:hover,
&:active { &:active {
border-color: #1552c8; border-color: var(--color-content-tab-hover-border);
} }
`; `;
const ContentTabTitle = styled('h3')` const ContentTabTitle = styled('h3')`
font-size: 14px; font-size: 14px;
font-weight: 400; font-weight: 400;
color: #2f343c;
`; `;
const ContentTabDesc = styled('p')` const ContentTabDesc = styled('p')`
margin: 0; margin: 0;
color: #5f6b7c;
margin-top: 4px; margin-top: 4px;
font-size: 12px; font-size: 12px;
opacity: 0.7;
`; `;
interface ContentTabsItemProps { interface ContentTabsItemProps {

View File

@@ -1,83 +1,28 @@
// @ts-nocheck // @ts-nocheck
import React, { useCallback, useEffect, useState } from 'react'; import React from 'react';
import { FormattedMessage as T } from '@/components'; import { FormattedMessage as T } from '@/components';
import { CLASSES } from '@/constants/classes'; import { FSelect } from '../Forms';
import classNames from 'classnames';
import { MenuItem, Button } from '@blueprintjs/core';
import { Select } from '@blueprintjs/select';
/**
* Currency select field.
* @returns {React.ReactNode}
*/
export function CurrencySelectList({ export function CurrencySelectList({
currenciesList, // #ownProps
selectedCurrencyCode, items,
defaultSelectText = <T id={'select_currency_code'} />, name,
onCurrencySelected, placeholder = <T id={'select_currency_code'} />,
popoverFill = false, ...props
disabled = false,
}) { }) {
const [selectedCurrency, setSelectedCurrency] = useState(null);
// Filters currencies list.
const filterCurrencies = (query, currency, _index, exactMatch) => {
const normalizedTitle = currency.currency_code.toLowerCase();
const normalizedQuery = query.toLowerCase();
if (exactMatch) {
return normalizedTitle === normalizedQuery;
} else {
return (
`${currency.currency_code} ${normalizedTitle}`.indexOf(
normalizedQuery,
) >= 0
);
}
};
const onCurrencySelect = useCallback((currency) => {
setSelectedCurrency({ ...currency });
onCurrencySelected && onCurrencySelected(currency);
});
const currencyCodeRenderer = useCallback((CurrencyCode, { handleClick }) => {
return (
<MenuItem
key={CurrencyCode.id}
text={CurrencyCode.currency_code}
onClick={handleClick}
/>
);
}, []);
useEffect(() => {
if (typeof selectedCurrencyCode !== 'undefined') {
const currency = selectedCurrencyCode
? currenciesList.find((a) => a.currency_code === selectedCurrencyCode)
: null;
setSelectedCurrency(currency);
}
}, [selectedCurrencyCode, currenciesList, setSelectedCurrency]);
return ( return (
<Select <FSelect
items={currenciesList} name={name}
itemRenderer={currencyCodeRenderer} items={items}
itemPredicate={filterCurrencies} textAccessor={'currency_code'}
onItemSelect={onCurrencySelect} valueAccessor={'id'}
filterable={true} placeholder={placeholder}
popoverProps={{ popoverProps={{ minimal: true, usePortal: true, inline: false }}
minimal: true, {...props}
usePortal: !popoverFill, />
inline: popoverFill,
}}
className={classNames('form-group--select-list', {
[CLASSES.SELECT_LIST_FILL_POPOVER]: popoverFill,
})}
>
<Button
disabled={disabled}
text={
selectedCurrency ? selectedCurrency.currency_code : defaultSelectText
}
/>
</Select>
); );
} }

View File

@@ -4,15 +4,28 @@ import classNames from 'classnames';
import { Icon } from '@/components'; import { Icon } from '@/components';
import '@/style/components/BigcapitalLoading.scss'; import '@/style/components/BigcapitalLoading.scss';
import { useIsDarkMode } from '@/hooks/useDarkMode';
/** /**
* Bigcapital logo loading. * Bigcapital logo loading.
*/ */
export default function BigcapitalLoading({ className }) { export default function BigcapitalLoading({ className }) {
const isDarkmode = useIsDarkMode();
return ( return (
<div className={classNames('bigcapital-loading', className)}> <div className={classNames('bigcapital-loading', className)}>
<div class="center"> <div class="center">
<Icon icon="bigcapital" height={37} width={228} /> {isDarkmode ? (
<Icon
icon="bigcapital-alt"
height={37}
width={228}
color="#fff"
className="bigcapital-logo"
/>
) : (
<Icon icon="bigcapital" height={37} width={228} />
)}
</div> </div>
</div> </div>
); );

View File

@@ -9,6 +9,17 @@ import withUniversalSearchActions from '@/containers/UniversalSearch/withUnivers
import { compose } from '@/utils'; import { compose } from '@/utils';
// Toggle dark/light mode by toggling 'bp4-dark' class on body
const handleToggleDarkMode = () => {
const body = document.body;
if (body.classList.contains('bp4-dark')) {
body.classList.remove('bp4-dark');
} else {
body.classList.add('bp4-dark');
}
};
function GlobalHotkeys({ function GlobalHotkeys({
// #withDashboardActions // #withDashboardActions
toggleSidebarExpand, toggleSidebarExpand,
@@ -55,6 +66,9 @@ function GlobalHotkeys({
openGlobalSearch(); openGlobalSearch();
}, 0); }, 0);
}); });
useHotkeys('shift+h', () => {
handleToggleDarkMode();
});
return <div></div>; return <div></div>;
} }

View File

@@ -21,30 +21,47 @@ export function DataTableEditable({
} }
const DatatableEditableRoot = styled.div` const DatatableEditableRoot = styled.div`
--x-table-background: #fff;
--x-table-border: #d2dce2;
--x-table-head-border: #d2dce2;
--x-table-head-background: #f2f3fb;
--x-table-head-text: #415060;
--x-color-table-body-input-text: #222;
--x-color-table-cell-border: #d8d8d8;
.bp4-dark & {
--x-table-background: var(--color-dark-gray1);
--x-table-border: rgba(255, 255, 255, 0.1);
--x-table-head-background: var(--color-dark-gray2);
--x-table-head-border: rgba(255, 255, 255, 0.1);
--x-table-head-text: rgba(--color-light-gray1);
--x-color-table-body-input-text: var(--color-light-gray2);
--x-color-table-cell-border: rgba(255, 255, 255, 0.1);
}
.bp4-form-group { .bp4-form-group {
margin-bottom: 0; margin-bottom: 0;
} }
.table { .table {
border: 1px solid #d2dce2; border: 1px solid var(--x-table-border);
background-color: var(--x-table-background);
border-radius: 5px; border-radius: 5px;
background-color: #fff;
.th, .th,
.td { .td {
border-left: 1px solid #e2e2e2; border-left: 1px solid var(--x-table-border);
&:first-of-type { &:first-of-type {
border-left: 0; border-left: 0;
} }
} }
.thead { .thead {
.tr .th { .tr .th {
padding: 9px 14px; padding: 9px 14px;
background-color: #f2f3fb; background-color: var(--x-table-head-background);
font-size: 13px; font-size: 13px;
color: #415060; color: var(--x-table-head-text);
border-bottom: 1px solid #d2dce2; border-bottom: 1px solid var(--x-table-head-border);
&, &,
.inner-resizer { .inner-resizer {
@@ -55,7 +72,7 @@ const DatatableEditableRoot = styled.div`
.tbody { .tbody {
.tr .td { .tr .td {
border-bottom: 0; border-bottom: 0;
border-bottom: 1px solid #d8d8d8; border-bottom: 1px solid var(--x-color-table-cell-border);
min-height: 38px; min-height: 38px;
padding: 4px 14px; padding: 4px 14px;
@@ -74,8 +91,9 @@ const DatatableEditableRoot = styled.div`
} }
.bp4-form-group:not(.bp4-intent-danger) .bp4-input, .bp4-form-group:not(.bp4-intent-danger) .bp4-input,
.form-group--select-list .bp4-button { .form-group--select-list .bp4-button {
border-color: #ffffff; border-color: transparent;
color: #222; box-shadow: 0 0 0;
color: var(--x-color-table-body-input-text);
border-radius: 3px; border-radius: 3px;
text-align: inherit; text-align: inherit;
} }

View File

@@ -0,0 +1,23 @@
.root {
--x-color-background: var(--color-white);
--x-color-border: hsla(0, 0%, 100%, 0.2);
:global(.bp4-dark) & {
--x-color-background: transparent;
--x-color-border: rgba(255, 255, 255, 0.2);
}
&:global(.bp4-navbar){
background-color: var(--x-color-background);
box-shadow: 0 1px 0 var(--x-color-border);
}
&:global(.bp4-navbar),
:global(.bp4-navbar-group){
height: 45px;
}
:global(.bp4-navbar-divider){
margin-left: 4px;
margin-right: 4px;
}
}

View File

@@ -1,13 +1,8 @@
// @ts-nocheck // @ts-nocheck
import React from 'react'; import React from 'react';
import styled from 'styled-components'; import { Navbar } from '@blueprintjs/core';
import styles from './DrawerActionBar.module.scss';
import { DashboardActionsBar } from '../Dashboard'; export function DrawerActionsBar({ children, ...props }) {
return <Navbar className={styles.root}>{children}</Navbar>;
export function DrawerActionsBar({ ...props }) {
return <DrawerActionsBarRoot {...props} />;
} }
const DrawerActionsBarRoot = styled(DashboardActionsBar)`
border-bottom: 1px solid #d9d9da;
`;

View File

@@ -64,7 +64,12 @@ function SubTitle({ children }) {
} }
const SubTitleHead = styled.div` const SubTitleHead = styled.div`
color: #666; --x-color-text: #666;
.bp4-dark & {
--x-color-text: rgba(255, 255, 255, 0.6);
}
color: var(--x-color-text);
font-size: 12px; font-size: 12px;
font-weight: 400; font-weight: 400;
line-height: 1; line-height: 1;

View File

@@ -18,24 +18,36 @@ export function DrawerMainTabs({ children, ...restProps }) {
const DrawerMainTabsRoot = styled.div` const DrawerMainTabsRoot = styled.div`
.bp4-tabs { .bp4-tabs {
--x-tab-list-background: #fff;
--x-tab-list-border: #e1e2e8;
--x-tab-item-text: #7f8596;
--x-tab-list-background: transparent;
--x-tab-list-border: rgba(255, 255, 255, 0.2);
--x-tab-item-text: var(--color-light-gray1);
--x-tab-item-height: 36px;
.bp4-tab-list { .bp4-tab-list {
position: relative; position: relative;
background-color: #fff; background-color: var(--x-tab-list-background);
padding: 0 15px; padding: 0 15px;
border-bottom: 2px solid #e1e2e8; border-bottom: 2px solid var(--x-tab-list-border);
> *:not(:last-child) { > *:not(:last-child) {
margin-right: 25px; margin-right: 25px;
} }
.bp4-tab {
color: var(--x-tab-item-text);
line-height: var(--x-tab-item-height);
}
&.bp4-large > .bp4-tab { &.bp4-large > .bp4-tab {
font-size: 15px; font-size: 15px;
color: #7f8596;
margin: 0 1rem; margin: 0 1rem;
&[aria-selected='true'], &[aria-selected='true'],
&:not([aria-disabled='true']):hover { &:not([aria-disabled='true']):hover {
color: #0052cc; color: var(--color-primary);
} }
} }
.bp4-tab-indicator-wrapper .bp4-tab-indicator { .bp4-tab-indicator-wrapper .bp4-tab-indicator {

View File

@@ -29,7 +29,6 @@ import { ReceiptCustomizeDrawer } from '@/containers/Sales/Receipts/ReceiptCusto
import { CreditNoteCustomizeDrawer } from '@/containers/Sales/CreditNotes/CreditNoteCustomize/CreditNoteCustomizeDrawer'; import { CreditNoteCustomizeDrawer } from '@/containers/Sales/CreditNotes/CreditNoteCustomize/CreditNoteCustomizeDrawer';
import { PaymentReceivedCustomizeDrawer } from '@/containers/Sales/PaymentsReceived/PaymentReceivedCustomize/PaymentReceivedCustomizeDrawer'; import { PaymentReceivedCustomizeDrawer } from '@/containers/Sales/PaymentsReceived/PaymentReceivedCustomize/PaymentReceivedCustomizeDrawer';
import { BrandingTemplatesDrawer } from '@/containers/BrandingTemplates/BrandingTemplatesDrawer'; import { BrandingTemplatesDrawer } from '@/containers/BrandingTemplates/BrandingTemplatesDrawer';
import { DRAWERS } from '@/constants/drawers'; import { DRAWERS } from '@/constants/drawers';
import { InvoiceSendMailDrawer } from '@/containers/Sales/Invoices/InvoiceSendMailDrawer/InvoiceSendMailDrawer'; import { InvoiceSendMailDrawer } from '@/containers/Sales/Invoices/InvoiceSendMailDrawer/InvoiceSendMailDrawer';
import { EstimateSendMailDrawer } from '@/containers/Sales/Estimates/EstimateSendMailDrawer'; import { EstimateSendMailDrawer } from '@/containers/Sales/Estimates/EstimateSendMailDrawer';

View File

@@ -1,11 +1,19 @@
.root { .root {
--color-dropzone-background: #fff;
--color-dropzone-border: #c5cbd3;
--color-dropzone-background: rgba(255, 255, 255, 0.05);
--color-dropzone-border: rgba(255, 255, 255, 0.1);
padding: 20px; padding: 20px;
border: 2px dotted #c5cbd3;
border-radius: 6px; border-radius: 6px;
min-height: 200px; min-height: 200px;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
background: #fff; border-style: dotted;
border-width: 2px;
border-color: var(--color-dropzone-border);
background: var(--color-dropzone-background);
position: relative; position: relative;
transition: background-color 0.3s ease, border-color 0.3s ease; transition: background-color 0.3s ease, border-color 0.3s ease;
@@ -13,6 +21,7 @@
border-color: rgb(0, 82, 204); border-color: rgb(0, 82, 204);
background: rgba(0, 82, 204, 0.05); background: rgba(0, 82, 204, 0.05);
} }
&.dropzoneReject { &.dropzoneReject {
border-color: #AC2F33; border-color: #AC2F33;
background: rgba(172, 47, 51, 0.05) background: rgba(172, 47, 51, 0.05)

View File

@@ -13,18 +13,18 @@ import {
import { DropzoneProvider } from './DropzoneProvider'; import { DropzoneProvider } from './DropzoneProvider';
import { DropzoneAccept, DropzoneIdle, DropzoneReject } from './DropzoneStatus'; import { DropzoneAccept, DropzoneIdle, DropzoneReject } from './DropzoneStatus';
import { Box } from '../Layout'; import { Box } from '../Layout';
import styles from './Dropzone.module.css';
import { CloudLoadingIndicator } from '../Indicator'; import { CloudLoadingIndicator } from '../Indicator';
import styles from './Dropzone.module.css';
export type DropzoneStylesNames = 'root' | 'inner'; export type DropzoneStylesNames = 'root' | 'inner';
export type DropzoneVariant = 'filled' | 'light'; export type DropzoneVariant = 'filled' | 'light';
export type DropzoneCssVariables = { export type DropzoneCssVariables = {
root: root:
| '--dropzone-radius' | '--dropzone-radius'
| '--dropzone-accept-color' | '--dropzone-accept-color'
| '--dropzone-accept-bg' | '--dropzone-accept-bg'
| '--dropzone-reject-color' | '--dropzone-reject-color'
| '--dropzone-reject-bg'; | '--dropzone-reject-bg';
}; };
export interface DropzoneProps { export interface DropzoneProps {

View File

@@ -2,7 +2,7 @@
import styled from 'styled-components'; import styled from 'styled-components';
export const FinancialSheetRoot = styled.div` export const FinancialSheetRoot = styled.div`
border: 2px solid #f0f0f0; border: 2px solid var(--color-financial-sheet-card-border);
border-radius: 10px; border-radius: 10px;
min-width: 640px; min-width: 640px;
width: auto; width: auto;
@@ -12,7 +12,6 @@ export const FinancialSheetRoot = styled.div`
min-height: 400px; min-height: 400px;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
background: #fff;
${(props) => ${(props) =>
props.fullWidth && props.fullWidth &&
@@ -29,7 +28,7 @@ export const FinancialSheetRoot = styled.div`
${FinancialSheetTitle} { ${FinancialSheetTitle} {
font-size: 18px; font-size: 18px;
color: #333; color: var(--color-financial-sheet-minimal-title-text);
} }
${FinancialSheetTitle} + ${FinancialSheetDate} { ${FinancialSheetTitle} + ${FinancialSheetDate} {
margin-top: 8px; margin-top: 8px;
@@ -44,7 +43,7 @@ export const FinancialSheetTitle = styled.h1`
margin: 0; margin: 0;
font-weight: 400; font-weight: 400;
font-size: 20px; font-size: 20px;
color: #464646; color: var(--color-financial-sheet-title-text);
text-align: center; text-align: center;
`; `;
@@ -53,18 +52,18 @@ export const FinancialSheetType = styled.h6`
margin: 0; margin: 0;
font-size: 16px; font-size: 16px;
font-weight: 400; font-weight: 400;
color: #666; color: var(--color-financial-sheet-type-text);
margin-top: 6px; margin-top: 6px;
`; `;
export const FinancialSheetDate = styled.div` export const FinancialSheetDate = styled.div`
text-align: center; text-align: center;
color: #666; color: var(--color-financial-sheet-date-text);
margin-top: 6px; margin-top: 6px;
`; `;
export const FinancialSheetFooter = styled.div` export const FinancialSheetFooter = styled.div`
color: #888; color: var(--color-financial-sheet-footer-text);
text-align: center; text-align: center;
margin-top: auto; margin-top: auto;
padding-top: 18px; padding-top: 18px;

View File

@@ -9,6 +9,7 @@ import {
Switch, Switch,
EditableText, EditableText,
TextArea, TextArea,
HTMLSelect,
} from '@blueprintjs-formik/core'; } from '@blueprintjs-formik/core';
import { MultiSelect, SuggestField } from '@blueprintjs-formik/select'; import { MultiSelect, SuggestField } from '@blueprintjs-formik/select';
import { DateInput } from '@blueprintjs-formik/datetime'; import { DateInput } from '@blueprintjs-formik/datetime';
@@ -27,4 +28,5 @@ export {
SuggestField as FSuggest, SuggestField as FSuggest,
TextArea as FTextArea, TextArea as FTextArea,
DateInput as FDateInput, DateInput as FDateInput,
HTMLSelect as FHTMLSelect,
}; };

View File

@@ -17,17 +17,25 @@ export function FSelect({ ...props }) {
return <Select input={input} fill={true} {...props} />; return <Select input={input} fill={true} {...props} />;
} }
const SelectButton = styled(Button)` export const SelectButton = styled(Button)`
--x-color-select-background: #fff;
--x-color-select-border: #ced4da;
--x-color-select-caret: #8d8d8d;
.bp4-dark & {
--x-color-select-background: rgba(17, 20, 24, 0.3);
--x-color-select-border: rgba(255, 255, 255, 0.15);
--x-color-select-caret: rgba(255, 255, 255, 0.25);
}
outline: none; outline: none;
box-shadow: 0 0 0 transparent; box-shadow: 0 0 0 transparent;
border: 1px solid #ced4da; border: 1px solid var(--x-color-select-border);
position: relative; position: relative;
padding-right: 30px; padding-right: 30px;
&.bp4-small { &.bp4-small {
padding-right: 24px; padding-right: 24px;
} }
&:not(.is-selected):not([class*='bp4-intent-']):not(.bp4-minimal) { &:not(.is-selected):not([class*='bp4-intent-']):not(.bp4-minimal) {
color: #8f99a8; color: #8f99a8;
} }
@@ -36,10 +44,9 @@ const SelectButton = styled(Button)`
display: inline-block; display: inline-block;
width: 0; width: 0;
height: 0; height: 0;
border-left: 4px solid transparent; border-left: 4px solid transparent;
border-right: 4px solid transparent; border-right: 4px solid transparent;
border-top: 5px solid #8d8d8d; border-top: 5px solid var(--x-color-select-caret);
position: absolute; position: absolute;
right: 0; right: 0;
@@ -51,7 +58,7 @@ const SelectButton = styled(Button)`
&:not([class*='bp4-intent-']):not(.bp4-disabled) { &:not([class*='bp4-intent-']):not(.bp4-disabled) {
&, &,
&:hover { &:hover {
background: #fff; background: var(--x-color-select-background);
} }
} }
.bp4-intent-danger & { .bp4-intent-danger & {

View File

@@ -0,0 +1,23 @@
interface BigcapitalAltProps extends React.SVGProps<SVGSVGElement> {
}
export function BigcapitalAlt(props: BigcapitalAltProps) {
return (
<svg data-icon="bigcapital-alt" width="214" height="37" viewBox="0 0 309.09 42.89" {...props}>
<desc>bigcapital</desc>
<path fill="currentColor" d="M56,3.16,61.33,8.5,31.94,37.9l-5.35-5.35Z" fill-rule="evenodd"></path>
<path fill="currentColor" d="M29.53,6.94l5.35,5.34L5.49,41.67.14,36.33l15.8-15.8Z" fill-rule="evenodd"></path>
<path fill="currentColor" d="M94.36,38.87H79.62v-31H94c6.33,0,10.22,3.15,10.22,8V16a7.22,7.22,0,0,1-4.07,6.69c3.58,1.37,5.8,3.45,5.8,7.61v.09C106,36,101.35,38.87,94.36,38.87Zm3.1-21.81c0-2-1.59-3.19-4.47-3.19H86.26v6.55h6.29c3,0,4.91-1,4.91-3.28Zm1.72,12.39c0-2.08-1.54-3.37-5-3.37H86.26V32.9h8.1c3,0,4.82-1.06,4.82-3.36Z" fill-rule="evenodd"></path>
<path fill="currentColor" d="M110.56,12.54v-6h7.08v6Zm.18,26.33V15.15h6.72V38.87Z" fill-rule="evenodd"></path>
<path fill="currentColor" d="M134,46a22.55,22.55,0,0,1-10.49-2.47l2.3-5a15.52,15.52,0,0,0,8,2.17c4.61,0,6.78-2.21,6.78-6.46V33.08c-2,2.39-4.16,3.85-7.75,3.85-5.53,0-10.53-4-10.53-11.07v-.09c0-7.08,5.09-11.06,10.53-11.06a9.63,9.63,0,0,1,7.66,3.54v-3.1h6.72V33.52C147.2,42.46,142.78,46,134,46Zm6.6-20.27a5.79,5.79,0,0,0-11.56,0v.09a5.42,5.42,0,0,0,5.76,5.49,5.49,5.49,0,0,0,5.8-5.49Z" fill-rule="evenodd"></path>
<path fill="currentColor" d="M164,39.41a12.11,12.11,0,0,1-12.35-12.26v-.09a12.18,12.18,0,0,1,12.44-12.35c4.47,0,7.25,1.5,9.47,4l-4.12,4.43a6.93,6.93,0,0,0-5.4-2.61c-3.36,0-5.75,3-5.75,6.46v.09c0,3.63,2.34,6.55,6,6.55,2.26,0,3.8-1,5.44-2.53l3.94,4A12,12,0,0,1,164,39.41Z" fill-rule="evenodd"></path>
<path fill="currentColor" d="M191.51,38.87V36.31a9.15,9.15,0,0,1-7.17,3c-4.47,0-8.15-2.57-8.15-7.26V32c0-5.18,3.94-7.57,9.56-7.57a16.74,16.74,0,0,1,5.8,1V25c0-2.79-1.72-4.34-5.09-4.34a17.57,17.57,0,0,0-6.55,1.28l-1.68-5.13a21,21,0,0,1,9.21-1.9c7.34,0,10.57,3.8,10.57,10.22V38.87Zm.13-9.55a10.3,10.3,0,0,0-4.29-.89c-2.88,0-4.65,1.15-4.65,3.27v.09c0,1.82,1.5,2.88,3.67,2.88,3.15,0,5.27-1.73,5.27-4.16Z" fill-rule="evenodd"></path>
<path fill="currentColor" d="M217.49,39.32a9.1,9.1,0,0,1-7.39-3.54V46h-6.73V15.15h6.73v3.41a8.7,8.7,0,0,1,7.39-3.85c5.53,0,10.8,4.34,10.8,12.26v.09C228.29,35,223.11,39.32,217.49,39.32ZM221.56,27c0-3.94-2.66-6.55-5.8-6.55S210,23,210,27v.09c0,3.94,2.61,6.55,5.75,6.55s5.8-2.57,5.8-6.55Z" fill-rule="evenodd"></path>
<path fill="currentColor" d="M232.93,12.54v-6H240v6Zm.18,26.33V15.15h6.73V38.87Z" fill-rule="evenodd"></path>
<path fill="currentColor" d="M253.73,39.27c-4.11,0-6.9-1.63-6.9-7.12V20.91H244V15.15h2.83V9.09h6.73v6.06h5.57v5.76h-5.57V31c0,1.55.66,2.3,2.16,2.3A6.84,6.84,0,0,0,259,32.5v5.4A9.9,9.9,0,0,1,253.73,39.27Z" fill-rule="evenodd"></path>
<path fill="currentColor" d="M277.55,38.87V36.31a9.15,9.15,0,0,1-7.18,3c-4.46,0-8.14-2.57-8.14-7.26V32c0-5.18,3.94-7.57,9.56-7.57a16.74,16.74,0,0,1,5.8,1V25c0-2.79-1.73-4.34-5.09-4.34A17.57,17.57,0,0,0,266,21.92l-1.68-5.13a20.94,20.94,0,0,1,9.2-1.9c7.35,0,10.58,3.8,10.58,10.22V38.87Zm.13-9.55a10.31,10.31,0,0,0-4.3-.89c-2.87,0-4.64,1.15-4.64,3.27v.09c0,1.82,1.5,2.88,3.67,2.88,3.14,0,5.27-1.73,5.27-4.16Z" fill-rule="evenodd"></path>
<path fill="currentColor" d="M289.72,38.87V6.57h6.72v32.3Z" fill-rule="evenodd"></path>
<path fill="currentColor" d="M302.06,38.87V31.79h7.17v7.08Z" fill-rule="evenodd"></path></svg>
);
}

View File

@@ -1,63 +0,0 @@
// @ts-nocheck
import React, { useCallback } from 'react';
import { FormattedMessage as T } from '@/components';
import { ListSelect } from '@/components';
import { MenuItem } from '@blueprintjs/core';
import { saveInvoke } from '@/utils';
import classNames from 'classnames';
import { CLASSES } from '@/constants/classes';
export function CategoriesSelectList({
categories,
selecetedCategoryId,
defaultSelectText = <T id={'select_category'} />,
onCategorySelected,
popoverFill = false,
className,
...restProps
}) {
// Filter Items Category
const filterItemCategory = (query, item, _index, exactMatch) => {
const normalizedTitle = item.name.toLowerCase();
const normalizedQuery = query.toLowerCase();
if (exactMatch) {
return normalizedTitle === normalizedQuery;
} else {
return `${item.code} ${normalizedTitle}`.indexOf(normalizedQuery) >= 0;
}
};
const handleItemCategorySelected = useCallback(
(ItemCategory) => saveInvoke(onCategorySelected, ItemCategory),
[onCategorySelected],
);
const categoryItem = useCallback(
(item, { handleClick }) => (
<MenuItem key={item.id} text={item.name} onClick={handleClick} />
),
[],
);
return (
<ListSelect
items={categories}
selectedItemProp={'id'}
selectedItem={selecetedCategoryId}
textProp={'name'}
defaultText={defaultSelectText}
onItemSelect={handleItemCategorySelected}
itemPredicate={filterItemCategory}
itemRenderer={categoryItem}
popoverProps={{ minimal: true, usePortal: !popoverFill }}
className={classNames(
'form-group--select-list',
{
[CLASSES.SELECT_LIST_FILL_POPOVER]: popoverFill,
},
className,
)}
{...restProps}
/>
);
}

View File

@@ -1,2 +0,0 @@
// @ts-nocheck
export * from './CategoriesSelectList';

View File

@@ -1,139 +1,83 @@
// @ts-nocheck // @ts-nocheck
import React from 'react'; import React from 'react';
import { FastField, ErrorMessage } from 'formik'; import { FSelect, FFormGroup, FSwitch } from '@/components';
import { FormGroup, Checkbox, Switch } from '@blueprintjs/core';
import { CLASSES } from '@/constants/classes';
import { ListSelect } from '@/components';
import { FormattedMessage as T } from '@/components'; import { FormattedMessage as T } from '@/components';
import { inputIntent } from '@/utils';
import { import {
moneyFormat, moneyFormat,
negativeFormat, negativeFormat,
decimalPlaces, decimalPlaces,
} from '@/constants/numberFormatsOptions'; } from '@/constants/numberFormatsOptions';
import classNames from 'classnames';
/** /**
* Number Formats Fields. * Number Formats Fields.
*/ */
export default function NumberFormatFields({}) { export default function NumberFormatFields() {
return ( return (
<div className={'number-format-dropdown__content'}> <div className={'number-format-dropdown__content'}>
{/*------------ Negative formats -----------*/} {/*------------ Negative formats -----------*/}
<FastField name={'negativeFormat'}> <FFormGroup name={'negativeFormat'} label={<T id={'negative_format'} />}>
{({ form, field: { value }, meta: { error, touched } }) => ( <FSelect
<FormGroup name={'negativeFormat'}
label={<T id={'negative_format'} />} items={negativeFormat}
helperText={<ErrorMessage name="negativeFormat" />} valueAccessor={'key'}
intent={inputIntent({ error, touched })} textAccessor={'text'}
className={classNames(CLASSES.FILL)} popoverProps={{ minimal: true, captureDismiss: true }}
> filterable
<ListSelect />
items={negativeFormat} </FFormGroup>
onItemSelect={(format) => {
form.setFieldValue('negativeFormat', format.key);
}}
filterable={false}
selectedItem={value}
selectedItemProp={'key'}
textProp={'text'}
popoverProps={{ minimal: true, captureDismiss: true }}
/>
</FormGroup>
)}
</FastField>
{/*------------ Decimal places -----------*/} {/*------------ Decimal places -----------*/}
<FastField name={'precision'}> <FFormGroup name={'precision'} label={<T id={'decimal_places'} />}>
{({ form, field: { value }, meta: { error, touched } }) => ( <FSelect
<FormGroup name={'precision'}
label={<T id={'decimal_places'} />} items={decimalPlaces}
helperText={<ErrorMessage name="format_money" />} filterable={false}
intent={inputIntent({ error, touched })} valueAccessor={'key'}
className={classNames(CLASSES.FILL)} textAccessor={'text'}
> popoverProps={{ minimal: true, captureDismiss: true }}
<ListSelect />
items={decimalPlaces} </FFormGroup>
onItemSelect={(format) => {
form.setFieldValue('precision', format.key);
}}
filterable={false}
selectedItem={value}
selectedItemProp={'key'}
textProp={'text'}
popoverProps={{ minimal: true, captureDismiss: true }}
/>
</FormGroup>
)}
</FastField>
{/*------------ Money formats -----------*/} {/*------------ Money formats -----------*/}
<FastField name={'formatMoney'}> <FFormGroup name={'formatMoney'} label={<T id={'money_format'} />}>
{({ form, field: { value }, meta: { error, touched } }) => ( <FSelect
<FormGroup name={'formatMoney'}
label={<T id={'money_format'} />} items={moneyFormat}
helperText={<ErrorMessage name="formatMoney" />} filterable={false}
intent={inputIntent({ error, touched })} valueAccessor={'key'}
className={classNames('form-group--money-format', CLASSES.FILL)} textAccessor={'text'}
> popoverProps={{ minimal: true, captureDismiss: true }}
<ListSelect />
items={moneyFormat} </FFormGroup>
onItemSelect={(format) => {
form.setFieldValue('formatMoney', format.key);
}}
filterable={false}
selectedItem={value}
selectedItemProp={'key'}
textProp={'text'}
popoverProps={{ minimal: true, captureDismiss: true }}
/>
</FormGroup>
)}
</FastField>
<div className="toggles-fields"> <div className="toggles-fields">
{/*------------ show zero -----------*/} {/*------------ show zero -----------*/}
<FastField name={'showZero'} type={'checkbox'}> <FFormGroup name={'showZero'} inline={true}>
{({ field }) => ( <FSwitch
<FormGroup inline={true}> name={'showZero'}
<Switch inline={true}
inline={true} small={true}
small={true} label={<T id={'show_zero'} />}
label={<T id={'show_zero'} />} />
name={'showZero'} </FFormGroup>
{...field}
/>
</FormGroup>
)}
</FastField>
{/*------------ show negative in red-----------*/} {/*------------ show negative in red-----------*/}
<FastField name={'showInRed'} type={'checkbox'}> <FFormGroup name={'showInRed'} inline={true}>
{({ field }) => ( <FSwitch
<FormGroup inline={true}> name={'showInRed'}
<Switch inline={true}
inline={true} label={<T id={'show_negative_in_red'} />}
label={<T id={'show_negative_in_red'} />} />
name={'showInRed'} </FFormGroup>
{...field}
/>
</FormGroup>
)}
</FastField>
{/*------------ Divide on 1000 -----------*/} {/*------------ Divide on 1000 -----------*/}
<FastField name={'divideOn1000'} type={'checkbox'}> <FFormGroup name={'divideOn1000'} inline={true}>
{({ field }) => ( <FSwitch
<FormGroup inline={true}> name={'divideOn1000'}
<Switch inline={true}
inline={true} label={<T id={'divide_on_1000'} />}
label={<T id={'divide_on_1000'} />} />
name={'divideOn1000'} </FFormGroup>
{...field}
/>
</FormGroup>
)}
</FastField>
</div> </div>
</div> </div>
); );

View File

@@ -13,11 +13,23 @@ export function FormTopbar({ className, children }) {
} }
const FormTopBarRoot = styled(Navbar)` const FormTopBarRoot = styled(Navbar)`
box-shadow: 0 0 0; --color-form-topbar-background: #fff;
border-bottom: 1px solid #c7d5db; --color-form-topbar-border: #c7d5db;
.bp4-dark & {
--color-form-topbar-background: var(--color-dark-gray1);
--color-form-topbar-border: rgba(255, 255, 255, 0.15);
}
height: 35px; height: 35px;
padding: 0 20px; padding: 0 20px;
&,
.bp4-dark & {
border-bottom: 1px solid var(--color-form-topbar-border);
background-color: var(--color-form-topbar-background);
box-shadow: 0 0 0;
}
.bp4-navbar-group { .bp4-navbar-group {
height: 35px; height: 35px;
} }

View File

@@ -37,21 +37,54 @@ const PageFormBody: FC<{ children: React.ReactNode } & SystemProps> = ({
}; };
PageFormBody.displayName = 'PageFormBody'; PageFormBody.displayName = 'PageFormBody';
const PageFormHeader: FC<GroupProps> = ({ className, ...props }) => {
return (
<Group
position="apart"
align={'flex-start'}
p="25px 32px"
{...props}
className={clsx(css(pageFormHeaderStyle), className)}
/>
);
};
const pageFormHeaderStyle = `
--color-invoice-form-header-background: #fff;
--color-invoice-form-header-border: #d2dce2;
.bp4-dark & {
--color-invoice-form-header-background: var(--color-dark-gray1);
--color-invoice-form-header-border: rgba(255, 255, 255, 0.1);
}
border-bottom: 1px solid var(--color-invoice-form-header-border);
background-color: var(--color-invoice-form-header-background);
`;
/** /**
* Page form footer. * Page form footer.
* @returns {React.ReactNode} * @returns {React.ReactNode}
*/ */
const PageFormFooter: FC<{ children: React.ReactNode } & SystemProps> = ({ children }) => { const PageFormFooter: FC<{ children: React.ReactNode } & SystemProps> = ({
children,
}) => {
return <x.div>{children} </x.div>; return <x.div>{children} </x.div>;
}; };
PageFormFooter.displayName = 'PageFormFooter'; PageFormFooter.displayName = 'PageFormFooter';
const footerActionsStyle = ` const footerActionsStyle = `
--x-color-background: #fff;
--x-color-border: rgb(210, 221, 226);
.bp4-dark & {
--x-color-background: var(--color-dark-gray1);
--x-color-border: rgba(255, 255, 255, 0.1);
}
width: 100%; width: 100%;
background: #fff; background: var(--x-color-background);
padding: 14px 20px; padding: 14px 20px;
border-top: 1px solid rgb(210, 221, 226); border-top: 1px solid var(--x-color-border);
box-shadow: 0px -1px 4px 0px rgba(0, 0, 0, 0.05); box-shadow: 0px -1px 4px 0px rgba(0, 0, 0, 0.05);
.bp4-button-group{ .bp4-button-group{
@@ -89,3 +122,4 @@ PageFormFooterActions.displayName = 'PageFormFooterActions';
PageForm.Body = PageFormBody; PageForm.Body = PageFormBody;
PageForm.Footer = PageFormFooter; PageForm.Footer = PageFormFooter;
PageForm.FooterActions = PageFormFooterActions; PageForm.FooterActions = PageFormFooterActions;
PageForm.Header = PageFormHeader;

View File

@@ -1,23 +1,19 @@
// @ts-nocheck // @ts-nocheck
import React from 'react'; import React from 'react';
import classNames from 'classnames'; import clsx from 'classnames';
import { CLASSES } from '@/constants/classes'; import { CLASSES } from '@/constants/classes';
import styles from '@/style/components/BigAmount.module.scss';
import '@/style/components/BigAmount.scss';
interface PageFormBigNumberProps { interface PageFormBigNumberProps {
label: string; label: string;
amount: string | number; amount: string | number;
} }
export function PageFormBigNumber({ export function PageFormBigNumber({ label, amount }: PageFormBigNumberProps) {
label,
amount,
}: PageFormBigNumberProps) {
return ( return (
<div className={classNames(CLASSES.PAGE_FORM_HEADER_BIG_NUMBERS)}> <div className={clsx(CLASSES.PAGE_FORM_HEADER_BIG_NUMBERS)}>
<div class="big-amount"> <div className={clsx(styles.root)}>
<span class="big-amount__label">{label}</span> <span className={clsx(styles.label)}>{label}</span>
<h1 class="big-amount__number">{amount}</h1> <h1 className={clsx(styles.number)}>{amount}</h1>
</div> </div>
</div> </div>
); );

View File

@@ -0,0 +1,14 @@
.root{
--x-color-background: #fff;
--x-color-border: #d2dce2;
:global(.bp4-dark) & {
--x-color-background: var(--color-dark-gray1);
--x-color-border: rgba(255, 255, 255, 0.1);
}
background-color: var(--x-color-background);
border: 1px solid var(--x-color-border);
padding: 10px;
}

View File

@@ -1,5 +1,7 @@
import React from 'react'; import React from 'react';
import { x, SystemProps } from '@xstyled/emotion'; import { x, SystemProps } from '@xstyled/emotion';
import clsx from 'classnames';
import styles from './Paper.module.scss';
interface PaperProps extends SystemProps { interface PaperProps extends SystemProps {
children: React.ReactNode; children: React.ReactNode;
@@ -8,10 +10,8 @@ interface PaperProps extends SystemProps {
export const Paper = ({ children, ...props }: PaperProps) => { export const Paper = ({ children, ...props }: PaperProps) => {
return ( return (
<x.div <x.div
background={'white'}
p={'10px'}
border={'1px solid #d2dce2'}
{...props} {...props}
className={clsx(styles.root)}
> >
{children} {children}
</x.div> </x.div>

View File

@@ -1,50 +1,68 @@
// @ts-nocheck import React, { useMemo } from 'react';
import React from 'react';
import intl from 'react-intl-universal'; import intl from 'react-intl-universal';
import { ListSelect } from './ListSelect'; import { FSelect } from '../Forms';
import { useFormikContext } from 'formik';
export function DisplayNameList({ export type DisplayNameListItem = { label: string };
salutation,
firstName, export interface DisplayNameListProps
lastName, extends Omit<
company, React.ComponentProps<typeof FSelect>,
...restProps 'items' | 'valueAccessor' | 'textAccessor' | 'labelAccessor'
}) { > {}
const formats = [
{ export function DisplayNameList({ ...restProps }: DisplayNameListProps) {
format: '{1} {2} {3}', const {
values: [salutation, firstName, lastName], values: {
required: [1], first_name: firstName,
last_name: lastName,
company_name: companyName,
salutation,
}, },
{ format: '{1} {2}', values: [firstName, lastName], required: [] }, } = useFormikContext<any>();
{ format: '{1}, {2}', values: [firstName, lastName], required: [1, 2] },
{ format: '{1}', values: [company], required: [1] },
];
const formatOptions = formats const formats = useMemo(
.filter( () => [
(format) => {
!format.values.some((value, index) => { format: '{1} {2} {3}',
return !value && format.required.indexOf(index + 1) !== -1; values: [salutation, firstName, lastName],
required: [1],
},
{ format: '{1} {2}', values: [firstName, lastName], required: [] },
{ format: '{1}, {2}', values: [firstName, lastName], required: [1, 2] },
{ format: '{1}', values: [companyName], required: [1] },
],
[firstName, lastName, companyName, salutation],
);
const formatOptions: DisplayNameListItem[] = useMemo(
() =>
formats
.filter(
(format) =>
!format.values.some((value, index) => {
return !value && format.required.indexOf(index + 1) !== -1;
}),
)
.map((formatOption) => {
const { format, values } = formatOption;
let label = format;
values.forEach((value, index) => {
const replaceWith = value || '';
label = label.replace(`{${index + 1}}`, replaceWith).trim();
});
return { label: label.replace(/\s+/g, ' ') };
}), }),
) [formats],
.map((formatOption) => { );
const { format, values } = formatOption;
let label = format;
values.forEach((value, index) => {
const replaceWith = value || '';
label = label.replace(`{${index + 1}}`, replaceWith).trim();
});
return { label: label.replace(/\s+/g, ' ') };
});
return ( return (
<ListSelect <FSelect
items={formatOptions} items={formatOptions}
selectedItemProp={'label'} valueAccessor={'label'}
textProp={'label'} textAccessor={'label'}
defaultText={intl.get('select_display_name_as')} placeholder={intl.get('select_display_name_as')}
filterable={false} filterable={false}
{...restProps} {...restProps}
/> />

View File

@@ -1,10 +1,16 @@
// @ts-nocheck
import React from 'react'; import React from 'react';
import intl from 'react-intl-universal'; import intl from 'react-intl-universal';
import { FSelect } from '../Forms';
import { ListSelect } from './ListSelect'; export type SalutationItem = { key: string; label: string };
export function SalutationList({ ...restProps }) { export interface SalutationListProps
extends Omit<
React.ComponentProps<typeof FSelect>,
'items' | 'valueAccessor' | 'textAccessor' | 'labelAccessor'
> {}
export function SalutationList({ ...restProps }: SalutationListProps) {
const saluations = [ const saluations = [
intl.get('mr'), intl.get('mr'),
intl.get('mrs'), intl.get('mrs'),
@@ -12,17 +18,17 @@ export function SalutationList({ ...restProps }) {
intl.get('miss'), intl.get('miss'),
intl.get('dr'), intl.get('dr'),
]; ];
const items = saluations.map((saluation) => ({ const items: SalutationItem[] = saluations.map((saluation) => ({
key: saluation, key: saluation,
label: saluation, label: saluation,
})); }));
return ( return (
<ListSelect <FSelect
items={items} items={items}
selectedItemProp={'key'} valueAccessor={'key'}
textProp={'label'} textAccessor={'label'}
defaultText={intl.get('salutation')} placeholder={intl.get('salutation')}
filterable={false} filterable={false}
{...restProps} {...restProps}
/> />

View File

@@ -41,8 +41,8 @@ export function Stepper({
active === index active === index
? StepperStepState.Progress ? StepperStepState.Progress
: active > index : active > index
? StepperStepState.Completed ? StepperStepState.Completed
: StepperStepState.Inactive; : StepperStepState.Inactive;
const shouldAllowSelect = () => { const shouldAllowSelect = () => {
if (typeof onStepClick !== 'function') { if (typeof onStepClick !== 'function') {
@@ -105,7 +105,7 @@ const StepsContent = styled(Box)`
const StepSeparator = styled.div` const StepSeparator = styled.div`
flex: 1; flex: 1;
display: block; display: block;
border-color: #c5cbd3; border-color: var(--color-stepper-separator);
border-top-style: solid; border-top-style: solid;
border-top-width: 1px; border-top-width: 1px;
`; `;

View File

@@ -74,21 +74,27 @@ const StepIcon = styled.span`
border-radius: 24px; border-radius: 24px;
text-align: center; text-align: center;
background-color: ${(props) => background-color: ${(props) =>
props.isCompleted || props.isActive ? 'rgb(0, 82, 204)' : '#9e9e9e'}; props.isCompleted || props.isActive
color: #fff; ? 'var(--color-stepper-step-active-background)'
: 'var(--color-stepper-step-background)'};
color: var(--color-stepper-step-text);
margin: auto; margin: auto;
font-size: 12px; font-size: 12px;
`; `;
const StepTitle = styled.div` const StepTitle = styled.div`
color: ${(props) => color: ${(props) =>
props.isCompleted || props.isActive ? 'rgb(0, 82, 204)' : '#738091'}; props.isCompleted || props.isActive
? 'var(--color-stepper-step-title-active-text)'
: 'var(--color-stepper-step-title-text)'};
`; `;
const StepDescription = styled.div` const StepDescription = styled.div`
font-size: 12px; font-size: 12px;
margin-top: 10px; margin-top: 10px;
color: ${(props) => color: ${(props) =>
props.isCompleted || props.isActive ? 'rgb(0, 82, 204)' : '#738091'}; props.isCompleted || props.isActive
? 'var(--color-stepper-step-description-active-text)'
: 'var(--color-stepper-step-description-text)'};
`; `;
const StepIconWrap = styled.div` const StepIconWrap = styled.div`

View File

@@ -1,4 +1,9 @@
.root{ .root{
--color-minimum-border: #e1e2e8;
--color-minimum-border: rgba(255, 255, 255, 0.2);
display: flex; display: flex;
flex-direction: row; flex-direction: row;
gap: 10px; gap: 10px;
@@ -9,7 +14,7 @@
&:global(.bp4-minimal:not([class*='bp4-intent-'])) { &:global(.bp4-minimal:not([class*='bp4-intent-'])) {
background: #fff; background: #fff;
border: 1px solid #e1e2e8; border: 1px solid var(--color-minimum-border);
&:global(.bp4-interactive:hover) { &:global(.bp4-interactive:hover) {
background-color: rgba(143, 153, 168, 0.05); background-color: rgba(143, 153, 168, 0.05);

View File

@@ -64,32 +64,38 @@ export const TotalLinesRoot = styled.div`
`; `;
export const TotalLinePrimitive = styled.div` export const TotalLinePrimitive = styled.div`
--x-color-divider: #d2dde2;
--x-color-divider-dark: #000;
--x-color-divider: rgba(255, 255, 255, 0.1);
--x-color-divider-dark: rgba(255, 255, 255, 0.2);
display: table-row; display: table-row;
.amount, .amount,
.title { .title {
display: table-cell; display: table-cell;
padding: 8px; padding: 8px;
border-bottom: 1px solid #d2dde2; border-bottom: 1px solid var(--x-color-divider);
${(props) => ${(props) =>
props.borderStyle === TotalLineBorderStyle.DoubleDark && props.borderStyle === TotalLineBorderStyle.DoubleDark &&
` `
border-bottom: 3px double #000; border-bottom: 3px double var(--x-color-divider-dark);
`} `}
${(props) => ${(props) =>
props.borderStyle === TotalLineBorderStyle.SingleDark && props.borderStyle === TotalLineBorderStyle.SingleDark &&
` `
border-bottom: 1px double #000; border-bottom: 1px double var(--x-color-divider-dark);
`} `}
${(props) => ${(props) =>
props.borderStyle === TotalLineBorderStyle.None && props.borderStyle === TotalLineBorderStyle.None &&
` `
border-bottom-color: transparent; border-bottom-color: transparent;
`} `}
${(props) => ${(props) =>
props.textStyle === TotalLineTextStyle.Bold && props.textStyle === TotalLineTextStyle.Bold &&
` `
font-weight: 600; font-weight: 600;
`} `}
} }

View File

@@ -49,7 +49,6 @@ export * from './FlexGrid';
export * from './Menu'; export * from './Menu';
export * from './Icon'; export * from './Icon';
export * from './Items'; export * from './Items';
export * from './ItemsCategories';
export * from './Select'; export * from './Select';
export * from './FormattedMessage'; export * from './FormattedMessage';
export * from './MaterialProgressBar'; export * from './MaterialProgressBar';

View File

@@ -6,6 +6,7 @@ import intl from 'react-intl-universal';
import * as R from 'ramda'; import * as R from 'ramda';
import { sumBy, round, isEmpty, omit } from 'lodash'; import { sumBy, round, isEmpty, omit } from 'lodash';
import classNames from 'classnames'; import classNames from 'classnames';
import { css } from '@emotion/css';
import { useHistory } from 'react-router-dom'; import { useHistory } from 'react-router-dom';
import { CLASSES } from '@/constants/classes'; import { CLASSES } from '@/constants/classes';
@@ -25,6 +26,7 @@ import withSettings from '@/containers/Settings/withSettings';
import withCurrentOrganization from '@/containers/Organization/withCurrentOrganization'; import withCurrentOrganization from '@/containers/Organization/withCurrentOrganization';
import { AppToaster } from '@/components'; import { AppToaster } from '@/components';
import { PageForm } from '@/components/PageForm';
import { compose, orderingLinesIndexes, transactionNumber } from '@/utils'; import { compose, orderingLinesIndexes, transactionNumber } from '@/utils';
import { import {
transformErrors, transformErrors,
@@ -175,18 +177,32 @@ function MakeJournalEntriesForm({
validationSchema={isNewMode ? CreateJournalSchema : EditJournalSchema} validationSchema={isNewMode ? CreateJournalSchema : EditJournalSchema}
onSubmit={handleSubmit} onSubmit={handleSubmit}
> >
<Form> <Form
<MakeJournalFormTopBar /> className={css({
<MakeJournalEntriesHeader /> overflow: 'hidden',
<MakeJournalEntriesField /> display: 'flex',
<MakeJournalFormFooter /> flexDirection: 'column',
<MakeJournalFormFloatingActions /> flex: 1,
})}
>
<PageForm flex={1}>
<PageForm.Body>
<MakeJournalFormTopBar />
<MakeJournalEntriesHeader />
<MakeJournalEntriesField />
<MakeJournalFormFooter />
</PageForm.Body>
{/* --------- Dialogs --------- */} <PageForm.Footer>
<MakeJournalFormDialogs /> <MakeJournalFormFloatingActions />
</PageForm.Footer>
{/* --------- Effects --------- */} {/* --------- Dialogs --------- */}
<JournalSyncIncrementSettingsToForm /> <MakeJournalFormDialogs />
{/* --------- Effects --------- */}
<JournalSyncIncrementSettingsToForm />
</PageForm>
</Form> </Form>
</Formik> </Formik>
</div> </div>

View File

@@ -1,17 +1,20 @@
// @ts-nocheck // @ts-nocheck
import React from 'react'; import React from 'react';
import classNames from 'classnames'; import {
import { CLASSES } from '@/constants/classes'; Group,
import { PageFormBigNumber, FormattedMessage as T } from '@/components'; PageForm,
PageFormBigNumber,
FormattedMessage as T,
} from '@/components';
import MakeJournalEntriesHeaderFields from './MakeJournalEntriesHeaderFields'; import MakeJournalEntriesHeaderFields from './MakeJournalEntriesHeaderFields';
import { useManualJournalTotalFormatted } from './utils'; import { useManualJournalTotalFormatted } from './utils';
export default function MakeJournalEntriesHeader() { export default function MakeJournalEntriesHeader() {
return ( return (
<div className={classNames(CLASSES.PAGE_FORM_HEADER)}> <PageForm.Header>
<MakeJournalEntriesHeaderFields /> <MakeJournalEntriesHeaderFields />
<MakeJournalHeaderBigNumber /> <MakeJournalHeaderBigNumber />
</div> </PageForm.Header>
); );
} }

View File

@@ -1,139 +1,141 @@
// @ts-nocheck // @ts-nocheck
import React from 'react'; import React from 'react';
import { InputGroup, FormGroup, Position } from '@blueprintjs/core'; import { Position } from '@blueprintjs/core';
import { FastField, ErrorMessage } from 'formik'; import { useFormikContext } from 'formik';
import { DateInput } from '@blueprintjs/datetime';
import classNames from 'classnames'; import classNames from 'classnames';
import { useTheme } from '@emotion/react';
import { css } from '@emotion/css';
import { CLASSES } from '@/constants/classes'; import { CLASSES } from '@/constants/classes';
import { import {} from '@/utils';
momentFormatter,
inputIntent,
handleDateChange,
tansformDateValue,
} from '@/utils';
import { import {
Hint, Hint,
FieldRequiredHint, FieldRequiredHint,
Icon, Icon,
CurrencySelectList, FSelect,
FormattedMessage as T, FormattedMessage as T,
FFormGroup,
FInputGroup,
FDateInput,
Stack,
} from '@/components'; } from '@/components';
import { useMakeJournalFormContext } from './MakeJournalProvider'; import { useMakeJournalFormContext } from './MakeJournalProvider';
import { JournalExchangeRateInputField } from './components'; import { JournalExchangeRateInputField } from './components';
import { currenciesFieldShouldUpdate } from './utils';
import { MakeJournalTransactionNoField } from './MakeJournalTransactionNoField'; import { MakeJournalTransactionNoField } from './MakeJournalTransactionNoField';
const getFieldsStyle = (theme: Theme) => css`
.${theme.bpPrefix}-form-group {
margin-bottom: 0;
&.${theme.bpPrefix}-inline {
max-width: 450px;
}
.${theme.bpPrefix}-label {
min-width: 150px;
font-weight: 500;
}
.${theme.bpPrefix}-form-content {
width: 100%;
}
}
`;
/** /**
* Make journal entries header. * Make journal entries header.
*/ */
export default function MakeJournalEntriesHeader({}) { export default function MakeJournalEntriesHeader({}) {
const { currencies } = useMakeJournalFormContext(); const { currencies } = useMakeJournalFormContext();
const form = useFormikContext();
const theme = useTheme();
const fieldsClassName = getFieldsStyle(theme);
return ( return (
<div className={classNames(CLASSES.PAGE_FORM_HEADER_FIELDS)}> <Stack spacing={18} flex={1} className={fieldsClassName}>
{/*------------ Posting date -----------*/} {/*------------ Posting date -----------*/}
<FastField name={'date'}> <FFormGroup
{({ form, field: { value }, meta: { error, touched } }) => ( name={'date'}
<FormGroup label={<T id={'posting_date'} />}
label={<T id={'posting_date'} />} labelInfo={<FieldRequiredHint />}
labelInfo={<FieldRequiredHint />} inline
intent={inputIntent({ error, touched })} fastField
helperText={<ErrorMessage name="date" />} >
minimal={true} <FDateInput
inline={true} name={'date'}
className={classNames(CLASSES.FILL)} formatDate={(date) => date.toLocaleDateString()}
> parseDate={(str) => new Date(str)}
<DateInput popoverProps={{
{...momentFormatter('YYYY/MM/DD')} position: Position.BOTTOM_LEFT,
onChange={handleDateChange((formattedDate) => { minimal: true,
form.setFieldValue('date', formattedDate); fill: true,
})} }}
value={tansformDateValue(value)} inputProps={{
popoverProps={{ leftIcon: <Icon icon={'date-range'} />,
position: Position.BOTTOM, }}
minimal: true, fill
}} fastField
inputProps={{ />
leftIcon: <Icon icon={'date-range'} />, </FFormGroup>
}}
/>
</FormGroup>
)}
</FastField>
{/*------------ Journal number -----------*/} {/*------------ Journal number -----------*/}
<MakeJournalTransactionNoField /> <MakeJournalTransactionNoField />
{/*------------ Reference -----------*/} {/*------------ Reference -----------*/}
<FastField name={'reference'}> <FFormGroup
{({ form, field, meta: { error, touched } }) => ( name={'reference'}
<FormGroup label={<T id={'reference'} />}
label={<T id={'reference'} />} labelInfo={
labelInfo={ <Hint
<Hint content={<T id={'journal_reference_hint'} />}
content={<T id={'journal_reference_hint'} />} position={Position.RIGHT}
position={Position.RIGHT} />
/> }
} inline
className={'form-group--reference'} fastField
intent={inputIntent({ error, touched })} >
helperText={<ErrorMessage name="reference" />} <FInputGroup name={'reference'} minimal fill />
fill={true} </FFormGroup>
inline={true}
>
<InputGroup fill={true} {...field} />
</FormGroup>
)}
</FastField>
{/*------------ Journal type -----------*/} {/*------------ Journal type -----------*/}
<FastField name={'journal_type'}> <FFormGroup
{({ form, field, meta: { error, touched } }) => ( name={'journal_type'}
<FormGroup label={<T id={'journal_type'} />}
label={<T id={'journal_type'} />} inline
className={classNames('form-group--account-type', CLASSES.FILL)} fastField
inline={true} >
> <FInputGroup name={'journal_type'} minimal fill />
<InputGroup </FFormGroup>
intent={inputIntent({ error, touched })}
fill={true}
{...field}
/>
</FormGroup>
)}
</FastField>
{/*------------ Currency -----------*/} {/*------------ Currency -----------*/}
<FastField <FFormGroup
name={'currency_code'} name={'currency_code'}
currencies={currencies} label={<T id={'currency'} />}
shouldUpdate={currenciesFieldShouldUpdate} inline
fastField
> >
{({ form, field: { value }, meta: { error, touched } }) => ( <FSelect
<FormGroup name={'currency_code'}
label={<T id={'currency'} />} items={currencies}
className={classNames('form-group--currency', CLASSES.FILL)} onItemChange={(currencyItem) => {
inline={true} form.setFieldValue('currency_code', currencyItem.currency_code);
> form.setFieldValue('exchange_rate', '');
<CurrencySelectList }}
currenciesList={currencies} popoverProps={{
selectedCurrencyCode={value} inline: true,
onCurrencySelected={(currencyItem) => { minimal: true,
form.setFieldValue('currency_code', currencyItem.currency_code); captureDismiss: true,
form.setFieldValue('exchange_rate', ''); }}
}} valueAccessor={'currency_code'}
defaultSelectText={value} labelAccessor={'currency_name'}
/> textAccessor={'currency_code'}
</FormGroup> fastField
)} />
</FastField> </FFormGroup>
{/* ----------- Exchange rate ----------- */} {/* ----------- Exchange rate ----------- */}
<JournalExchangeRateInputField <JournalExchangeRateInputField
name={'exchange_rate'} name={'exchange_rate'}
formGroupProps={{ label: ' ', inline: true }} formGroupProps={{ label: ' ', inline: true }}
/> />
</div> </Stack>
); );
} }

View File

@@ -14,6 +14,7 @@ import { useHistory } from 'react-router-dom';
import { useFormikContext } from 'formik'; import { useFormikContext } from 'formik';
import classNames from 'classnames'; import classNames from 'classnames';
import { Group, Icon, If, FormattedMessage as T } from '@/components'; import { Group, Icon, If, FormattedMessage as T } from '@/components';
import { PageForm } from '@/components/PageForm';
import { CLASSES } from '@/constants/classes'; import { CLASSES } from '@/constants/classes';
import { useMakeJournalFormContext } from './MakeJournalProvider'; import { useMakeJournalFormContext } from './MakeJournalProvider';
@@ -76,7 +77,7 @@ export default function MakeJournalFloatingAction() {
}; };
return ( return (
<Group <PageForm.FooterActions
spacing={10} spacing={10}
className={classNames(CLASSES.PAGE_FORM_FLOATING_ACTIONS)} className={classNames(CLASSES.PAGE_FORM_FLOATING_ACTIONS)}
> >
@@ -191,6 +192,6 @@ export default function MakeJournalFloatingAction() {
onClick={handleCancelBtnClick} onClick={handleCancelBtnClick}
text={<T id={'cancel'} />} text={<T id={'cancel'} />}
/> />
</Group> </PageForm.FooterActions>
); );
} }

View File

@@ -34,6 +34,9 @@ export function MakeJournalFormFooterRight() {
} }
const MakeJouranlTotalLines = styled(TotalLines)` const MakeJouranlTotalLines = styled(TotalLines)`
--x-color-text: #555;
--x-color-text: var(--color-light-gray4);
width: 100%; width: 100%;
color: #555555; color: var(--x-color-text);
`; `;

View File

@@ -4,11 +4,18 @@
} }
.attachmentButton:not([class*=bp4-intent-]) { .attachmentButton:not([class*=bp4-intent-]) {
--x-background-color: #fff;
--x-border-color: rgb(206, 212, 218);
:global(.bp4-dark) & {
--x-border-color: rgba(255, 255, 255, 0.1);
}
&, &,
&:hover{ &:hover{
background-color: #fff; background-color: #fff;
} }
border: 1px solid rgb(206, 212, 218); border: 1px solid var(--x-border-color);
} }
.attachmentField :global .bp4-label{ .attachmentField :global .bp4-label{

View File

@@ -11,14 +11,22 @@ import { Box, Icon, FormattedMessage as T } from '@/components';
import { AuthMetaBootProvider } from './AuthMetaBoot'; import { AuthMetaBootProvider } from './AuthMetaBoot';
import '@/style/pages/Authentication/Auth.scss'; import '@/style/pages/Authentication/Auth.scss';
import { useIsDarkMode } from '@/hooks/useDarkMode';
import { BigcapitalAlt } from '@/components/Icons/BigcapitalAlt';
export function Authentication() { export function Authentication() {
const isDarkMode = useIsDarkMode();
return ( return (
<BodyClassName className={'authentication'}> <BodyClassName className={'authentication'}>
<AuthPage> <AuthPage>
<AuthInsider> <AuthInsider>
<AuthLogo> <AuthLogo>
<Icon icon="bigcapital" height={37} width={214} /> {isDarkMode ? (
<BigcapitalAlt color={"rgba(255, 255, 255, 0.6)"} height={37} width={214} />
) : (
<Icon icon="bigcapital" height={37} width={214} />
)}
</AuthLogo> </AuthLogo>
<AuthMetaBootProvider> <AuthMetaBootProvider>

View File

@@ -27,10 +27,17 @@ export const AuthInsiderContent = styled.div`
position: relative; position: relative;
`; `;
export const AuthInsiderCard = styled.div` export const AuthInsiderCard = styled.div`
border: 1px solid #d5d5d5; --x-color-background: #fff;
--x-color-border: #d5d5d5;
.bp4-dark & {
--x-color-background: var(--color-dark-gray2);
--x-color-border: rgba(255, 255, 255, 0.1);
}
border: 1px solid var(--x-color-border);
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04); box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04);
padding: 26px 22px; padding: 26px 22px;
background: #ffff; background: var(--x-color-background);
border-radius: 3px; border-radius: 3px;
`; `;
@@ -59,7 +66,12 @@ export const AuthFooterLinks = styled.div`
`; `;
export const AuthFooterLink = styled.p` export const AuthFooterLink = styled.p`
color: #666; --x-color-text: #666;
.bp4-dark & {
--x-color-text: rgba(255, 255, 255, 0.75);
}
color: var(--x-color-text);
margin: 0; margin: 0;
`; `;
@@ -67,11 +79,11 @@ export const AuthSubmitButton = styled(Button)`
margin-top: 20px; margin-top: 20px;
&.bp4-intent-primary { &.bp4-intent-primary {
background-color: #0052cc; // background-color: #0052cc;
&:disabled, &:disabled,
&.bp4-disabled { &.bp4-disabled {
background-color: rgba(0, 82, 204, 0.4); // background-color: rgba(0, 82, 204, 0.4);
} }
} }
`; `;

View File

@@ -1,7 +1,7 @@
// @ts-nocheck // @ts-nocheck
import React, { useMemo } from 'react'; import React, { useMemo } from 'react';
import { Button, NavbarGroup, Intent } from '@blueprintjs/core'; import { Button, NavbarGroup, Intent } from '@blueprintjs/core';
import { DashboardActionsBar, Icon } from '@/components'; import { DrawerActionsBar, Icon } from '@/components';
import withDrawerActions from '@/containers/Drawer/withDrawerActions'; import withDrawerActions from '@/containers/Drawer/withDrawerActions';
import { import {
getButtonLabelFromResource, getButtonLabelFromResource,
@@ -26,7 +26,7 @@ function BrandingTemplateActionsBarRoot({ openDrawer }) {
const label = useMemo(() => getButtonLabelFromResource(resource), [resource]); const label = useMemo(() => getButtonLabelFromResource(resource), [resource]);
return ( return (
<DashboardActionsBar> <DrawerActionsBar>
<NavbarGroup> <NavbarGroup>
<Button <Button
intent={Intent.PRIMARY} intent={Intent.PRIMARY}
@@ -37,7 +37,7 @@ function BrandingTemplateActionsBarRoot({ openDrawer }) {
{label} {label}
</Button> </Button>
</NavbarGroup> </NavbarGroup>
</DashboardActionsBar> </DrawerActionsBar>
); );
} }
export const BrandingTemplateActionsBar = compose(withDrawerActions)( export const BrandingTemplateActionsBar = compose(withDrawerActions)(

View File

@@ -166,7 +166,7 @@ const DashboardConstrantTable = styled(DataTable)`
.table { .table {
.thead { .thead {
.th { .th {
background: #fff; // background: #fff;
letter-spacing: 1px; letter-spacing: 1px;
text-transform: uppercase; text-transform: uppercase;
font-size: 13px; font-size: 13px;
@@ -182,6 +182,12 @@ const DashboardConstrantTable = styled(DataTable)`
`; `;
const CashflowTransactionsTable = styled(DashboardConstrantTable)` const CashflowTransactionsTable = styled(DashboardConstrantTable)`
--table-cell-border-color: #e6e6e6;
.bp4-dark & {
--table-cell-border-color: rgba(255, 255, 255, 0.15);
}
.table .tbody { .table .tbody {
.tbody-inner .tr.no-results { .tbody-inner .tr.no-results {
.td { .td {
@@ -195,7 +201,7 @@ const CashflowTransactionsTable = styled(DashboardConstrantTable)`
.tbody-inner { .tbody-inner {
.tr .td:not(:first-child) { .tr .td:not(:first-child) {
border-left: 1px solid #e6e6e6; border-left: 1px solid var(--table-cell-border-color);
} }
} }
} }

View File

@@ -173,13 +173,14 @@ const DetailsBarSkeletonBase = styled.div`
const AccountBalanceItemWrap = styled.div` const AccountBalanceItemWrap = styled.div`
margin-left: 18px; margin-left: 18px;
color: #5f6d86; // color: #5f6d86;
`; `;
const AccountTransactionDetailsWrap = styled.div` const AccountTransactionDetailsWrap = styled.div`
display: flex; display: flex;
background: #fff; background: var(--color-bank-transactions-details-bar-background);
border-bottom: 1px solid #d2dce2; color: var(--color-bank-transactions-details-bar-text);
border-bottom: 1px solid var(--color-bank-transactions-details-bar-divider);
padding: 0 22px; padding: 0 22px;
height: 42px; height: 42px;
align-items: center; align-items: center;
@@ -192,7 +193,7 @@ const AccountSwitchText = styled.div`
const AccountBalanceAmount = styled.span` const AccountBalanceAmount = styled.span`
font-weight: 600; font-weight: 600;
display: inline-block; display: inline-block;
color: rgb(31, 50, 85); // color: rgb(31, 50, 85);
margin-left: 10px; margin-left: 10px;
`; `;

View File

@@ -37,7 +37,7 @@ export function AccountTransactionsFilterTabs() {
id={'uncategorized'} id={'uncategorized'}
title={ title={
<> <>
<span style={{ color: '#ff0000' }}> <span style={{ color: 'var(--color-danger)' }}>
{currentAccount.uncategorized_transactions} {currentAccount.uncategorized_transactions}
</span>{' '} </span>{' '}
Uncategorized Transactions Uncategorized Transactions

View File

@@ -11,10 +11,10 @@ const Box = styled.div`
`; `;
const CashflowTransactionsTableCard = styled.div` const CashflowTransactionsTableCard = styled.div`
border: 2px solid #f0f0f0; background: var(--color-bank-transactions-content-background);
border: 2px solid var(--color-bank-transactions-content-border);
border-radius: 10px; border-radius: 10px;
padding: 30px 18px; padding: 30px 18px;
background: #fff;
flex: 0 1; flex: 0 1;
`; `;

View File

@@ -1,9 +1,12 @@
.emptyState{ .emptyState{
--x-color-text: #738091;
:global(.bp4-dark) & {
--x-color-text: rgba(255, 255, 255, 0.6);
}
text-align: center; text-align: center;
font-size: 15px; font-size: 15px;
color: #738091; color: var(--x-color-text);
:global ul{ :global ul{
list-style: inside; list-style: inside;

View File

@@ -2,9 +2,9 @@ import styled from 'styled-components';
export const AccountTransactionsCard = styled.div` export const AccountTransactionsCard = styled.div`
border: 2px solid #f0f0f0; border: 2px solid var(--color-bank-transactions-content-border);
background: var(--color-bank-transactions-content-background);
border-radius: 10px; border-radius: 10px;
padding: 30px 18px; padding: 30px 18px;
background: #fff;
flex: 0 1; flex: 0 1;
`; `;

View File

@@ -1,11 +1,24 @@
.root{ .root {
--color-background: #fff;
--color-border: #e1e2e8;
--color-text: var(--color-dark-gray1);
:global(.bp4-dark) & {
--color-background: #c5cbd3;
--color-border: rgba(255, 255, 255, 0.2);
}
min-height: 26px; min-height: 26px;
border-radius: 15px; border-radius: 15px;
font-size: 13px; font-size: 13px;
padding: 0 10px; padding: 0 10px;
&:global(.bp4-button:not([class*=bp4-intent-]):not(.bp4-minimal)) { &:global(.bp4-button:not([class*='bp4-intent-']):not(.bp4-minimal)) {
background: #fff; background: var(--color-background);
border: 1px solid #e1e2e8; color: var(--color-text);
border: 1px solid var(--color-border);
& :global(.bp4-icon) {
color: var(--color-text);
}
} }
} }

View File

@@ -2,7 +2,7 @@
:global .table{ :global .table{
.thead { .thead {
.th { .th {
background: #fff; // background: #fff;
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 1px; letter-spacing: 1px;
font-size: 13px; font-size: 13px;
@@ -22,7 +22,7 @@
.tbody-inner { .tbody-inner {
.tr .td{ .tr .td{
border-bottom: 1px solid #ececec; border-bottom-width: 1px;
} }
} }
} }

View File

@@ -45,6 +45,6 @@ export const CategorizeTransactionFormFooter = R.compose(withBankingActions)(
); );
const Root = styled.div` const Root = styled.div`
border-top: 1px solid #c7d5db; border-top: 1px solid var(--color-aside-divider);
padding: 14px 20px; padding: 14px 20px;
`; `;

View File

@@ -5,17 +5,13 @@
padding-bottom: 60px; padding-bottom: 60px;
} }
.transaction {
}
.matchBar{ .matchBar{
padding: 12px 14px; padding: 12px 14px;
background: #fff; background: var(--color-bank-transaction-matching-aside-header);
border-bottom: 1px solid #E1E2E9; border-bottom: 1px solid var(--color-bank-transaction-matching-divider);
&:not(:first-of-type) { &:not(:first-of-type) {
border-top: 1px solid #E1E2E9; border-top: 1px solid var(--color-bank-transaction-matching-divider);
} }
} }
@@ -25,16 +21,16 @@
} }
.footer { .footer {
background-color: #fff; background-color: var(--color-bank-transaction-matching-aside-footer);
} }
.footerActions { .footerActions {
padding: 14px 16px; padding: 14px 16px;
border-top: 1px solid #d8d9d9; border-top: 1px solid var(--color-bank-transaction-matching-divider);
} }
.footerTotal { .footerTotal {
padding: 8px 16px; padding: 8px 16px;
border-top: 1px solid #d8d9d9; border-top: 1px solid var(--color-bank-transaction-matching-divider);
line-height: 24px; line-height: 24px;
} }

View File

@@ -7,8 +7,8 @@
height: calc(100dvh - 144px); height: calc(100dvh - 144px);
} }
.tabs :global .bp4-tab-list{ .tabs :global .bp4-tab-list{
background: #fff; // background: #fff;
border-bottom: 1px solid #c7d5db; border-bottom: 1px solid var(--color-aside-divider);
padding: 0 22px; padding: 0 22px;
} }

View File

@@ -1,52 +1,66 @@
.root {
.root{ --item-background: #fff;
background: #fff; --item-border: #d6dbe3;
--item-active-border: #88abdb;
--item-label-text: #252a33;
--item-date-text: #5c7080;
:global(.bp4-dark) & {
--item-background: var(--color-dark-gray4);
--item-border: rgba(255, 255, 255, 0.2);
--item-date-text: var(--color-light-gray1);
--item-label-text: var(--color-light-gray4);
}
background: var(--item-background);
border-radius: 5px; border-radius: 5px;
border: 1px solid #D6DBE3; border: 1px solid var(--item-border);
padding: 10px 16px; padding: 10px 16px;
cursor: pointer; cursor: pointer;
&.active{ &.active {
border-color: #88ABDB; border-color: var(--item-active-border);
box-shadow: 0 0 0 2px rgba(136, 171, 219, 0.2); box-shadow: 0 0 0 2px rgba(136, 171, 219, 0.2);
.label, .label,
.date { .date {
color: rgb(21, 82, 200), color: rgb(21, 82, 200);
} }
} }
&:hover:not(.active){ &:hover:not(.active) {
border-color: #c0c0c0; border-color: #c0c0c0;
} }
} }
.checkbox:global(.bp4-control.bp4-checkbox){ .checkbox:global(.bp4-control.bp4-checkbox) {
margin: 0; margin: 0;
} }
.checkbox:global(.bp4-control.bp4-checkbox) :global .bp4-control-indicator{ .checkbox:global(.bp4-control.bp4-checkbox) :global .bp4-control-indicator {
box-shadow: 0 0 0 1px #CBCBCB; box-shadow: 0 0 0 1px #cbcbcb;
} }
.checkbox:global(.bp4-control.bp4-checkbox) :global .bp4-control-indicator{ .checkbox:global(.bp4-control.bp4-checkbox) :global .bp4-control-indicator {
margin-right: 4px; margin-right: 4px;
margin-left: 0; margin-left: 0;
height: 16px; height: 16px;
width: 16px; width: 16px;
} }
.checkbox:global(.bp4-control.bp4-checkbox) :global input:checked ~ .bp4-control-indicator{ .checkbox:global(.bp4-control.bp4-checkbox)
box-shadow: 0 0 0 1px #0069ff; :global
input:checked
~ .bp4-control-indicator {
box-shadow: 0 0 0 1px #0069ff;
} }
.label { .label {
color: #252A33; color: var(--item-label-text);
font-size: 15px; font-size: 15px;
} }
.label :global strong { .label :global strong {
font-weight: 500; font-weight: 500;
font-variant-numeric:tabular-nums; font-variant-numeric: tabular-nums;
} }
.date { .date {
font-size: 12px; font-size: 12px;
color: #5C7080; color: var(--item-date-text);
} }

View File

@@ -11,7 +11,7 @@
.footer { .footer {
padding: 11px 20px; padding: 11px 20px;
border-top: 1px solid #ced4db; border-top: 1px solid var(--color-aside-divider);
} }
.form{ .form{

View File

@@ -1,10 +1,12 @@
// @ts-nocheck // @ts-nocheck
import React from 'react'; import React from 'react';
import { FormGroup, InputGroup, TextArea } from '@blueprintjs/core';
import { Row, Col } from '@/components'; import { Row, Col } from '@/components';
import { FormattedMessage as T } from '@/components'; import {
import { FastField, ErrorMessage } from 'formik'; FormattedMessage as T,
import { inputIntent } from '@/utils'; FFormGroup,
FInputGroup,
FTextArea,
} from '@/components';
const CustomerBillingAddress = ({}) => { const CustomerBillingAddress = ({}) => {
return ( return (
@@ -15,105 +17,65 @@ const CustomerBillingAddress = ({}) => {
<T id={'billing_address'} /> <T id={'billing_address'} />
</h4> </h4>
{/*------------ Billing Address country -----------*/} {/*------------ Billing Address country -----------*/}
<FastField name={'billing_address_country'}> <FFormGroup
{({ field, field: { value }, meta: { error, touched } }) => ( name={'billing_address_country'}
<FormGroup inline={true}
className={'form-group--journal-number'} label={<T id={'country'} />}
intent={inputIntent({ error, touched })} >
inline={true} <FInputGroup name={'billing_address_country'} />
helperText={<ErrorMessage name="billing_address_country" />} </FFormGroup>
label={<T id={'country'} />}
>
<InputGroup {...field} />
</FormGroup>
)}
</FastField>
{/*------------ Billing Address 1 -----------*/} {/*------------ Billing Address 1 -----------*/}
<FastField name={'billing_address_1'}> <FFormGroup
{({ field, field: { value }, meta: { error, touched } }) => ( name={'billing_address_1'}
<FormGroup label={<T id={'address_line_1'} />}
label={<T id={'address_line_1'} />} inline={true}
className={'form-group--address_line_1'} >
intent={inputIntent({ error, touched })} <FTextArea name={'billing_address_1'} />
inline={true} </FFormGroup>
helperText={<ErrorMessage name="billing_address_1" />}
>
<TextArea {...field} />
</FormGroup>
)}
</FastField>
{/*------------ Billing Address 2 -----------*/} {/*------------ Billing Address 2 -----------*/}
<FastField name={'billing_address_2'}> <FFormGroup
{({ field, field: { value }, meta: { error, touched } }) => ( name={'billing_address_2'}
<FormGroup label={<T id={'address_line_2'} />}
label={<T id={'address_line_2'} />} inline={true}
className={'form-group--journal-number'} >
intent={inputIntent({ error, touched })} <FTextArea name={'billing_address_2'} />
inline={true} </FFormGroup>
helperText={<ErrorMessage name="billing_address_2" />}
>
<TextArea {...field} />
</FormGroup>
)}
</FastField>
{/*------------ Billing Address city -----------*/} {/*------------ Billing Address city -----------*/}
<FastField name={'billing_address_city'}> <FFormGroup
{({ field, field: { value }, meta: { error, touched } }) => ( name={'billing_address_city'}
<FormGroup label={<T id={'city_town'} />}
label={<T id={'city_town'} />} inline={true}
className={'form-group--journal-number'} >
intent={inputIntent({ error, touched })} <FInputGroup name={'billing_address_city'} />
inline={true} </FFormGroup>
helperText={<ErrorMessage name="billing_address_city" />}
>
<InputGroup {...field} />
</FormGroup>
)}
</FastField>
{/*------------ Billing Address state -----------*/} {/*------------ Billing Address state -----------*/}
<FastField name={'billing_address_state'}> <FFormGroup
{({ field, field: { value }, meta: { error, touched } }) => ( name={'billing_address_state'}
<FormGroup label={<T id={'state'} />}
label={<T id={'state'} />} inline={true}
className={'form-group--journal-number'} >
intent={inputIntent({ error, touched })} <FInputGroup name={'billing_address_state'} />
inline={true} </FFormGroup>
helperText={<ErrorMessage name="billing_address_state" />}
>
<InputGroup {...field} />
</FormGroup>
)}
</FastField>
{/*------------ Billing Address postcode -----------*/} {/*------------ Billing Address postcode -----------*/}
<FastField name={'billing_address_postcode'}> <FFormGroup
{({ field, field: { value }, meta: { error, touched } }) => ( name={'billing_address_postcode'}
<FormGroup label={<T id={'zip_code'} />}
label={<T id={'zip_code'} />} inline={true}
intent={inputIntent({ error, touched })} >
inline={true} <FInputGroup name={'billing_address_postcode'} />
helperText={<ErrorMessage name="billing_address_postcode" />} </FFormGroup>
>
<InputGroup {...field} />
</FormGroup>
)}
</FastField>
{/*------------ Billing Address phone -----------*/} {/*------------ Billing Address phone -----------*/}
<FastField name={'billing_address_phone'}> <FFormGroup
{({ field, field: { value }, meta: { error, touched } }) => ( name={'billing_address_phone'}
<FormGroup label={<T id={'phone'} />}
label={<T id={'phone'} />} inline={true}
intent={inputIntent({ error, touched })} >
inline={true} <FInputGroup name={'billing_address_phone'} />
helperText={<ErrorMessage name="billing_address_phone" />} </FFormGroup>
>
<InputGroup {...field} />
</FormGroup>
)}
</FastField>
</Col> </Col>
<Col xs={6}> <Col xs={6}>
@@ -121,107 +83,67 @@ const CustomerBillingAddress = ({}) => {
<T id={'shipping_address'} /> <T id={'shipping_address'} />
</h4> </h4>
{/*------------ Shipping Address country -----------*/} {/*------------ Shipping Address country -----------*/}
<FastField name={'shipping_address_country'}> <FFormGroup
{({ field, field: { value }, meta: { error, touched } }) => ( name={'shipping_address_country'}
<FormGroup label={<T id={'country'} />}
label={<T id={'country'} />} inline={true}
className={'form-group--journal-number'} >
intent={inputIntent({ error, touched })} <FInputGroup name={'shipping_address_country'} />
inline={true} </FFormGroup>
helperText={<ErrorMessage name="shipping_address_country" />}
>
<InputGroup {...field} />
</FormGroup>
)}
</FastField>
{/*------------ Shipping Address 1 -----------*/} {/*------------ Shipping Address 1 -----------*/}
<FastField name={'shipping_address_1'}> <FFormGroup
{({ field, field: { value }, meta: { error, touched } }) => ( name={'shipping_address_1'}
<FormGroup label={<T id={'address_line_1'} />}
label={<T id={'address_line_1'} />} inline={true}
className={'form-group--journal-number'} >
intent={inputIntent({ error, touched })} <FTextArea name={'shipping_address_1'} />
inline={true} </FFormGroup>
helperText={<ErrorMessage name="shipping_address_1" />}
>
<TextArea {...field} />
</FormGroup>
)}
</FastField>
{/*------------ Shipping Address 2 -----------*/} {/*------------ Shipping Address 2 -----------*/}
<FastField name={'shipping_address_2'}> <FFormGroup
{({ field, field: { value }, meta: { error, touched } }) => ( name={'shipping_address_2'}
<FormGroup label={<T id={'address_line_2'} />}
label={<T id={'address_line_2'} />} inline={true}
className={'form-group--journal-number'} >
intent={inputIntent({ error, touched })} <FTextArea name={'shipping_address_2'} />
inline={true} </FFormGroup>
helperText={<ErrorMessage name="shipping_address_2" />}
>
<TextArea {...field} />
</FormGroup>
)}
</FastField>
{/*------------ Shipping Address city -----------*/} {/*------------ Shipping Address city -----------*/}
<FastField name={'shipping_address_city'}> <FFormGroup
{({ field, field: { value }, meta: { error, touched } }) => ( name={'shipping_address_city'}
<FormGroup label={<T id={'city_town'} />}
label={<T id={'city_town'} />} inline={true}
className={'form-group--journal-number'} >
intent={inputIntent({ error, touched })} <FInputGroup name={'shipping_address_city'} />
inline={true} </FFormGroup>
helperText={<ErrorMessage name="shipping_address_city" />}
>
<InputGroup {...field} />
</FormGroup>
)}
</FastField>
{/*------------ Shipping Address state -----------*/} {/*------------ Shipping Address state -----------*/}
<FastField name={'shipping_address_state'}> <FFormGroup
{({ field, field: { value }, meta: { error, touched } }) => ( name={'shipping_address_state'}
<FormGroup label={<T id={'state'} />}
label={<T id={'state'} />} inline={true}
className={'form-group--journal-number'} >
intent={inputIntent({ error, touched })} <FInputGroup name={'shipping_address_state'} />
inline={true} </FFormGroup>
helperText={<ErrorMessage name="shipping_address_state" />}
>
<InputGroup {...field} />
</FormGroup>
)}
</FastField>
{/*------------ Shipping Address postcode -----------*/} {/*------------ Shipping Address postcode -----------*/}
<FastField name={'shipping_address_postcode'}> <FFormGroup
{({ field, field: { value }, meta: { error, touched } }) => ( name={'shipping_address_postcode'}
<FormGroup label={<T id={'zip_code'} />}
label={<T id={'zip_code'} />} inline={true}
intent={inputIntent({ error, touched })} >
inline={true} <FInputGroup name={'shipping_address_postcode'} />
helperText={<ErrorMessage name="shipping_address_postcode" />} </FFormGroup>
>
<InputGroup {...field} />
</FormGroup>
)}
</FastField>
{/*------------ Shipping Address phone -----------*/} {/*------------ Shipping Address phone -----------*/}
<FastField name={'shipping_address_phone'}> <FFormGroup
{({ field, field: { value }, meta: { error, touched } }) => ( name={'shipping_address_phone'}
<FormGroup label={<T id={'phone'} />}
label={<T id={'phone'} />} inline={true}
intent={inputIntent({ error, touched })} >
inline={true} <FInputGroup name={'shipping_address_phone'} />
helperText={<ErrorMessage name="shipping_address_phone" />} </FFormGroup>
>
<InputGroup {...field} />
</FormGroup>
)}
</FastField>
</Col> </Col>
</Row> </Row>
</div> </div>

View File

@@ -39,28 +39,18 @@ export default function CustomerFinancialPanel() {
<Row> <Row>
<Col xs={6}> <Col xs={6}>
{/*------------ Currency -----------*/} {/*------------ Currency -----------*/}
<FastField name={'currency_code'}> <FFormGroup
{({ form, field: { value }, meta: { error, touched } }) => ( name={'currency_code'}
<FormGroup label={<T id={'currency'} />}
label={<T id={'currency'} />} fastField
className={classNames( inline
'form-group--select-list', >
'form-group--balance-currency', <CurrencySelectList
Classes.FILL, name="currency_code"
)} items={currencies}
inline={true} disabled={customerId}
> />
<CurrencySelectList </FFormGroup>
currenciesList={currencies}
selectedCurrencyCode={value}
onCurrencySelected={(currency) => {
form.setFieldValue('currency_code', currency.currency_code);
}}
disabled={customerId}
/>
</FormGroup>
)}
</FastField>
{/*------------ Opening balance -----------*/} {/*------------ Opening balance -----------*/}
<CustomerOpeningBalanceField /> <CustomerOpeningBalanceField />

View File

@@ -1,72 +1,40 @@
// @ts-nocheck // @ts-nocheck
import React from 'react'; import React from 'react';
import intl from 'react-intl-universal'; import intl from 'react-intl-universal';
import { FormGroup, InputGroup, ControlGroup } from '@blueprintjs/core'; import { ControlGroup } from '@blueprintjs/core';
import { FastField, ErrorMessage } from 'formik'; import { FormattedMessage as T, FFormGroup, FInputGroup } from '@/components';
import { FormattedMessage as T } from '@/components';
import { inputIntent } from '@/utils';
export default function CustomerFormAfterPrimarySection({}) { export default function CustomerFormAfterPrimarySection({}) {
return ( return (
<div class="customer-form__after-primary-section-content"> <div className={'customer-form__after-primary-section-content'}>
{/*------------ Customer email -----------*/} {/*------------ Customer email -----------*/}
<FastField name={'email'}> <FFormGroup
{({ field, meta: { error, touched } }) => ( name={'email'}
<FormGroup label={<T id={'customer_email'} />}
intent={inputIntent({ error, touched })} inline={true}
helperText={<ErrorMessage name={'email'} />} >
className={'form-group--email'} <FInputGroup name={'email'} />
label={<T id={'customer_email'} />} </FFormGroup>
inline={true}
>
<InputGroup {...field} />
</FormGroup>
)}
</FastField>
{/*------------ Phone number -----------*/} {/*------------ Phone number -----------*/}
<FormGroup <FFormGroup
className={'form-group--phone-number'} name={'personal_phone'}
label={<T id={'phone_number'} />} label={<T id={'phone_number'} />}
inline={true} inline={true}
> >
<ControlGroup> <ControlGroup>
<FastField name={'personal_phone'}> <FInputGroup
{({ field, meta: { error, touched } }) => ( name={'personal_phone'}
<InputGroup placeholder={intl.get('personal')}
intent={inputIntent({ error, touched })} />
placeholder={intl.get('personal')} <FInputGroup name={'work_phone'} placeholder={intl.get('work')} />
{...field}
/>
)}
</FastField>
<FastField name={'work_phone'}>
{({ field, meta: { error, touched } }) => (
<InputGroup
intent={inputIntent({ error, touched })}
placeholder={intl.get('work')}
{...field}
/>
)}
</FastField>
</ControlGroup> </ControlGroup>
</FormGroup> </FFormGroup>
{/*------------ Customer website -----------*/} {/*------------ Customer website -----------*/}
<FastField name={'website'}> <FFormGroup name={'website'} label={<T id={'website'} />} inline={true}>
{({ field, meta: { error, touched } }) => ( <FInputGroup name={'website'} placeholder={'http://'} />
<FormGroup </FFormGroup>
intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name={'website'} />}
className={'form-group--website'}
label={<T id={'website'} />}
inline={true}
>
<InputGroup placeholder={'http://'} {...field} />
</FormGroup>
)}
</FastField>
</div> </div>
); );
} }

View File

@@ -124,10 +124,15 @@ function CustomerFormFormik({
} }
export const CustomerFormHeaderPrimary = styled.div` export const CustomerFormHeaderPrimary = styled.div`
--x-border: #e4e4e4;
.bp4-dark & {
--x-border: var(--color-dark-gray3);
}
padding: 10px 0 0; padding: 10px 0 0;
margin: 0 0 20px; margin: 0 0 20px;
overflow: hidden; overflow: hidden;
border-bottom: 1px solid #e4e4e4; border-bottom: 1px solid var(--x-border);
max-width: 1000px; max-width: 1000px;
`; `;

View File

@@ -10,6 +10,8 @@ import {
SalutationList, SalutationList,
DisplayNameList, DisplayNameList,
FormattedMessage as T, FormattedMessage as T,
FInputGroup,
FFormGroup,
} from '@/components'; } from '@/components';
import CustomerTypeRadioField from './CustomerTypeRadioField'; import CustomerTypeRadioField from './CustomerTypeRadioField';
import { CLASSES } from '@/constants/classes'; import { CLASSES } from '@/constants/classes';
@@ -28,100 +30,51 @@ export default function CustomerFormPrimarySection({}) {
<CustomerTypeRadioField /> <CustomerTypeRadioField />
{/**----------- Contact name -----------*/} {/**----------- Contact name -----------*/}
<FormGroup <FFormGroup
className={classNames('form-group--contact_name')} name={'salutation'}
label={<T id={'contact_name'} />} label={<T id={'contact_name'} />}
inline={true} inline={true}
> >
<ControlGroup> <ControlGroup>
<FastField name={'salutation'}> <SalutationList
{({ form, field: { value }, meta: { error, touched } }) => ( name={'salutation'}
<SalutationList popoverProps={{ minimal: true }}
onItemSelect={(salutation) => { />
form.setFieldValue('salutation', salutation.label); <FInputGroup
}} name={'first_name'}
selectedItem={value} placeholder={intl.get('first_name')}
popoverProps={{ minimal: true }} inputRef={(ref) => (firstNameFieldRef.current = ref)}
className={classNames( />
CLASSES.FORM_GROUP_LIST_SELECT, <FInputGroup name={'last_name'} placeholder={intl.get('last_name')} />
CLASSES.FILL,
'input-group--salutation-list',
'select-list--fill-button',
)}
/>
)}
</FastField>
<FastField name={'first_name'}>
{({ field, meta: { error, touched } }) => (
<InputGroup
placeholder={intl.get('first_name')}
intent={inputIntent({ error, touched })}
className={classNames('input-group--first-name')}
inputRef={(ref) => (firstNameFieldRef.current = ref)}
{...field}
/>
)}
</FastField>
<FastField name={'last_name'}>
{({ field, meta: { error, touched } }) => (
<InputGroup
placeholder={intl.get('last_name')}
intent={inputIntent({ error, touched })}
className={classNames('input-group--last-name')}
{...field}
/>
)}
</FastField>
</ControlGroup> </ControlGroup>
</FormGroup> </FFormGroup>
{/*----------- Company Name -----------*/} {/*----------- Company Name -----------*/}
<FastField name={'company_name'}> <FFormGroup
{({ field, meta: { error, touched } }) => ( name={'company_name'}
<FormGroup label={<T id={'company_name'} />}
className={classNames('form-group--company_name')} inline={true}
label={<T id={'company_name'} />} >
intent={inputIntent({ error, touched })} <InputGroup name={'company_name'} />
helperText={<ErrorMessage name={'company_name'} />} </FFormGroup>
inline={true}
>
<InputGroup {...field} />
</FormGroup>
)}
</FastField>
{/*----------- Display Name -----------*/} {/*----------- Display Name -----------*/}
<Field name={'display_name'}> <FFormGroup
{({ form, field: { value }, meta: { error, touched } }) => ( name={'display_name'}
<FormGroup label={
helperText={<ErrorMessage name={'display_name'} />} <>
intent={inputIntent({ error, touched })} <T id={'display_name'} />
label={ <FieldRequiredHint />
<> <Hint />
<T id={'display_name'} /> </>
<FieldRequiredHint /> }
<Hint /> inline={true}
</> >
} <DisplayNameList
className={classNames(CLASSES.FORM_GROUP_LIST_SELECT, CLASSES.FILL)} name={'display_name'}
inline={true} popoverProps={{ minimal: true }}
> />
<DisplayNameList </FFormGroup>
firstName={form.values.first_name}
lastName={form.values.last_name}
company={form.values.company_name}
salutation={form.values.salutation}
onItemSelect={(displayName) => {
form.setFieldValue('display_name', displayName.label);
}}
selectedItem={value}
popoverProps={{ minimal: true }}
/>
</FormGroup>
)}
</Field>
</div> </div>
); );
} }

View File

@@ -1,26 +1,15 @@
// @ts-nocheck // @ts-nocheck
import React from 'react'; import React from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
import { FormGroup, TextArea, Classes } from '@blueprintjs/core'; import { Classes } from '@blueprintjs/core';
import { FastField, ErrorMessage } from 'formik'; import { FormattedMessage as T, FFormGroup, FTextArea } from '@/components';
import { FormattedMessage as T } from '@/components';
import { inputIntent } from '@/utils';
export default function CustomerNotePanel({ errors, touched, getFieldProps }) { export default function CustomerNotePanel({ errors, touched, getFieldProps }) {
return ( return (
<div className={'tab-panel--note'}> <div className={'tab-panel--note'}>
<FastField name={'note'}> <FFormGroup name={'note'} label={<T id={'note'} />} inline={false}>
{({ field, field: { value }, meta: { error, touched } }) => ( <FTextArea name={'note'} />
<FormGroup </FFormGroup>
label={<T id={'note'} />}
className={classNames('form-group--note', Classes.FILL)}
intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name="payment_date" />}
>
<TextArea {...field} />
</FormGroup>
)}
</FastField>
</div> </div>
); );
} }

View File

@@ -2,43 +2,26 @@
import React from 'react'; import React from 'react';
import intl from 'react-intl-universal'; import intl from 'react-intl-universal';
import classNames from 'classnames'; import classNames from 'classnames';
import { RadioGroup, Radio, FormGroup } from '@blueprintjs/core'; import { Radio } from '@blueprintjs/core';
import { FormattedMessage as T } from '@/components'; import { FormattedMessage as T, FFormGroup, FRadioGroup } from '@/components';
import { FastField } from 'formik';
import { handleStringChange, saveInvoke } from '@/utils'; import { handleStringChange, saveInvoke } from '@/utils';
/** /**
* Customer type radio field. * Customer type radio field.
*/ */
export default function RadioCustomer(props) { export default function RadioCustomer() {
const { onChange, ...rest } = props;
return ( return (
<FastField name={'customer_type'}> <FFormGroup
{({ form, field: { value }, meta: { error, touched } }) => ( name={'customer_type'}
<FormGroup label={<T id={'customer_type'} />}
inline={true} inline
label={<T id={'customer_type'} />} fastField
className={classNames('form-group--customer_type')} >
> <FRadioGroup name={'customer_type'} inline>
<RadioGroup <Radio label={intl.get('business')} value="business" />
inline={true} <Radio label={intl.get('individual')} value="individual" />
onChange={handleStringChange((value) => { </FRadioGroup>
saveInvoke(onChange, value); </FFormGroup>
form.setFieldValue('customer_type', value);
})}
selectedValue={value}
>
<Radio label={intl.get('business')} value="business" />
<Radio
label={intl.get('individual')}
value="individual"
/>
</RadioGroup>
</FormGroup>
)}
</FastField>
); );
} }

View File

@@ -1,6 +1,6 @@
// @ts-nocheck // @ts-nocheck
import React from 'react'; import React from 'react';
import { Menu } from '@blueprintjs/core'; import { Intent, Menu } from '@blueprintjs/core';
import { MenuItem, MenuItemLabel } from '@/components'; import { MenuItem, MenuItemLabel } from '@/components';
import { ISidebarMenuItemType } from '@/containers/Dashboard/Sidebar/interfaces'; import { ISidebarMenuItemType } from '@/containers/Dashboard/Sidebar/interfaces';
@@ -20,10 +20,9 @@ function SidebarMenuItem({ item, index }) {
text={item.text} text={item.text}
disabled={item.disabled} disabled={item.disabled}
dropdownType={item.dropdownType || 'collapse'} dropdownType={item.dropdownType || 'collapse'}
caretIconSize={16}
onClick={item.onClick} onClick={item.onClick}
active={isActive} active={isActive}
hasSubmenu={item.hasChildren} intent={Intent.NONE}
/> />
); );
} }
@@ -43,9 +42,9 @@ function SidebarMenuItemComposer({ item, index }) {
return SidebarMenuItem.ItemTypes.indexOf(item.type) !== -1 ? ( return SidebarMenuItem.ItemTypes.indexOf(item.type) !== -1 ? (
<SidebarMenuItem item={item} index={index} /> <SidebarMenuItem item={item} index={index} />
) : // Group item type. ) : // Group item type.
item.type === ISidebarMenuItemType.Group ? ( item.type === ISidebarMenuItemType.Group ? (
<MenuItemLabel text={item.text} /> <MenuItemLabel text={item.text} />
) : null; ) : null;
} }
/** /**

View File

@@ -1,17 +1,16 @@
// @ts-nocheck // @ts-nocheck
import React from 'react'; import React from 'react';
import { FormGroup, InputGroup, Intent, Button } from '@blueprintjs/core'; import { Intent, Button } from '@blueprintjs/core';
import { FastField, Form, useFormikContext, ErrorMessage } from 'formik'; import { Form, useFormikContext } from 'formik';
import { import {
ListSelect, FSelect,
FieldRequiredHint, FieldRequiredHint,
FormattedMessage as T, FormattedMessage as T,
FFormGroup, FFormGroup,
FInputGroup, FInputGroup,
} from '@/components'; } from '@/components';
import { CLASSES } from '@/constants/classes'; import { CLASSES } from '@/constants/classes';
import classNames from 'classnames'; import { compose } from '@/utils';
import { compose, inputIntent } from '@/utils';
import { useInviteUserFormContext } from './InviteUserFormProvider'; import { useInviteUserFormContext } from './InviteUserFormProvider';
import withDialogActions from '@/containers/Dialog/withDialogActions'; import withDialogActions from '@/containers/Dialog/withDialogActions';
@@ -42,30 +41,19 @@ function InviteUserFormContent({
<FInputGroup name={'email'} /> <FInputGroup name={'email'} />
</FFormGroup> </FFormGroup>
{/* ----------- Role name ----------- */} {/* ----------- Role name ----------- */}
<FastField name={'role_id'}> <FFormGroup
{({ form, field: { value }, meta: { error, touched } }) => ( name={'role_id'}
<FormGroup label={<T id={'invite_user.label.role_name'} />}
label={<T id={'invite_user.label.role_name'} />} labelInfo={<FieldRequiredHint />}
labelInfo={<FieldRequiredHint />} >
helperText={<ErrorMessage name="role_id" />} <FSelect
className={classNames(CLASSES.FILL, 'form-group--role_name')} name={'role_id'}
intent={inputIntent({ error, touched })} items={roles}
> valueAccessor={'id'}
<ListSelect textAccessor={'name'}
items={roles} popoverProps={{ minimal: true }}
onItemSelect={({ id }) => { />
form.setFieldValue('role_id', id); </FFormGroup>
}}
selectedItem={value}
selectedItemProp={'id'}
textProp={'name'}
// labelProp={'id '}
popoverProps={{ minimal: true }}
intent={inputIntent({ error, touched })}
/>
</FormGroup>
)}
</FastField>
</div> </div>
<div className={CLASSES.DIALOG_FOOTER}> <div className={CLASSES.DIALOG_FOOTER}>

View File

@@ -13,10 +13,10 @@ import {
Position, Position,
} from '@blueprintjs/core'; } from '@blueprintjs/core';
import { import {
DashboardActionsBar,
Icon, Icon,
Can, Can,
FormattedMessage as T, FormattedMessage as T,
DrawerActionsBar,
} from '@/components'; } from '@/components';
import { AccountAction, AbilitySubject } from '@/constants/abilityOption'; import { AccountAction, AbilitySubject } from '@/constants/abilityOption';
@@ -72,7 +72,7 @@ function AccountDrawerActionBar({
}; };
return ( return (
<DashboardActionsBar> <DrawerActionsBar>
<NavbarGroup> <NavbarGroup>
<Can I={AccountAction.Edit} a={AbilitySubject.Account}> <Can I={AccountAction.Edit} a={AbilitySubject.Account}>
<Button <Button
@@ -137,7 +137,7 @@ function AccountDrawerActionBar({
</> </>
)} )}
</NavbarGroup> </NavbarGroup>
</DashboardActionsBar> </DrawerActionsBar>
); );
} }
export default compose( export default compose(

View File

@@ -27,6 +27,7 @@ import {
Can, Can,
Icon, Icon,
FormattedMessage as T, FormattedMessage as T,
DrawerActionsBar,
} from '@/components'; } from '@/components';
import { CustomerMoreMenuItem } from './utils'; import { CustomerMoreMenuItem } from './utils';
import { import {
@@ -91,7 +92,7 @@ function CustomerDetailsActionsBar({
}; };
return ( return (
<DashboardActionsBar> <DrawerActionsBar>
<NavbarGroup> <NavbarGroup>
<Popover <Popover
content={ content={
@@ -163,7 +164,7 @@ function CustomerDetailsActionsBar({
}} }}
/> />
</NavbarGroup> </NavbarGroup>
</DashboardActionsBar> </DrawerActionsBar>
); );
} }

View File

@@ -42,4 +42,6 @@ export default function InvoiceGLEntriesTable() {
const InvoiceGLEntriesDatatable = styled(JournalEntriesTable)``; const InvoiceGLEntriesDatatable = styled(JournalEntriesTable)``;
const InvoiceGLEntriesRoot = styled(Card)``; const InvoiceGLEntriesRoot = styled(Card)`
`;

View File

@@ -16,10 +16,10 @@ import withAlertsActions from '@/containers/Alert/withAlertActions';
import withDrawerActions from '@/containers/Drawer/withDrawerActions'; import withDrawerActions from '@/containers/Drawer/withDrawerActions';
import { import {
DashboardActionsBar,
Icon, Icon,
FormattedMessage as T, FormattedMessage as T,
Can, Can,
DrawerActionsBar,
} from '@/components'; } from '@/components';
import { ItemDetailActionsMoreBtn } from './ItemDetailActionsMoreBtn'; import { ItemDetailActionsMoreBtn } from './ItemDetailActionsMoreBtn';
@@ -53,7 +53,7 @@ function ItemDetailActionsBar({
}; };
return ( return (
<DashboardActionsBar> <DrawerActionsBar>
<NavbarGroup> <NavbarGroup>
<Can I={ItemAction.Edit} a={AbilitySubject.Item}> <Can I={ItemAction.Edit} a={AbilitySubject.Item}>
<Button <Button
@@ -75,7 +75,7 @@ function ItemDetailActionsBar({
</Can> </Can>
<ItemDetailActionsMoreBtn /> <ItemDetailActionsMoreBtn />
</NavbarGroup> </NavbarGroup>
</DashboardActionsBar> </DrawerActionsBar>
); );
} }

View File

@@ -30,7 +30,6 @@ export function ItemTransactionsHeader() {
const handleItemChange = (item) => { const handleItemChange = (item) => {
setValue(item); setValue(item);
}; };
return ( return (
<ItemTransactionsHeaderRoot> <ItemTransactionsHeaderRoot>
<ItemManuTransaction onChange={handleItemChange} /> <ItemManuTransaction onChange={handleItemChange} />

View File

@@ -20,11 +20,9 @@ export const ItemManuTransaction = ({ onChange }) => {
if (itemTransactionMenu.length === 0) { if (itemTransactionMenu.length === 0) {
return null; return null;
} }
const handleClickItem = (item) => { const handleClickItem = (item) => {
onChange && onChange(item); onChange && onChange(item);
}; };
const content = itemTransactionMenu.map(({ name, label }) => ( const content = itemTransactionMenu.map(({ name, label }) => (
<MenuItem onClick={() => handleClickItem(name)} text={label} /> <MenuItem onClick={() => handleClickItem(name)} text={label} />
)); ));
@@ -52,15 +50,27 @@ export const ItemManuTransaction = ({ onChange }) => {
); );
}; };
ItemManuTransaction.displayName = 'ItemManuTransaction';
const ItemSwitchButton = styled(Button)` const ItemSwitchButton = styled(Button)`
--button-text-color: #727983;
.bp4-dark & {
--button-text-color: rgba(255, 255, 255, 0.65);
}
.bp4-button-text { .bp4-button-text {
display: flex; display: flex;
color: #727983; color: var(--button-text-color);
} }
`; `;
const ItemSwitchText = styled.span` const ItemSwitchText = styled.span`
--button-text-color: #33304a;
.bp4-dark & {
--button-text-color: rgba(255, 255, 255, 0.85);
}
font-weight: 600; font-weight: 600;
color: #33304a; color: var(--button-text-color);
padding-left: 3px; padding-left: 3px;
`; `;

View File

@@ -17,10 +17,10 @@ import withAlertsActions from '@/containers/Alert/withAlertActions';
import withDrawerActions from '@/containers/Drawer/withDrawerActions'; import withDrawerActions from '@/containers/Drawer/withDrawerActions';
import { import {
DashboardActionsBar,
Can, Can,
Icon, Icon,
FormattedMessage as T, FormattedMessage as T,
DrawerActionsBar,
} from '@/components'; } from '@/components';
import { PaymentMadeAction, AbilitySubject } from '@/constants/abilityOption'; import { PaymentMadeAction, AbilitySubject } from '@/constants/abilityOption';
import { compose } from '@/utils'; import { compose } from '@/utils';
@@ -52,7 +52,7 @@ function PaymentMadeDetailActionsBar({
}; };
return ( return (
<DashboardActionsBar> <DrawerActionsBar>
<NavbarGroup> <NavbarGroup>
<Can I={PaymentMadeAction.Edit} a={AbilitySubject.PaymentMade}> <Can I={PaymentMadeAction.Edit} a={AbilitySubject.PaymentMade}>
<Button <Button
@@ -62,6 +62,7 @@ function PaymentMadeDetailActionsBar({
onClick={handleEditPaymentMade} onClick={handleEditPaymentMade}
/> />
</Can> </Can>
<Can I={PaymentMadeAction.Delete} a={AbilitySubject.PaymentMade}> <Can I={PaymentMadeAction.Delete} a={AbilitySubject.PaymentMade}>
<NavbarDivider /> <NavbarDivider />
<Button <Button
@@ -73,7 +74,7 @@ function PaymentMadeDetailActionsBar({
/> />
</Can> </Can>
</NavbarGroup> </NavbarGroup>
</DashboardActionsBar> </DrawerActionsBar>
); );
} }

View File

@@ -24,8 +24,8 @@ import withDialogActions from '@/containers/Dialog/withDialogActions';
import { import {
Can, Can,
Icon, Icon,
DashboardActionsBar,
FormattedMessage as T, FormattedMessage as T,
DrawerActionsBar,
} from '@/components'; } from '@/components';
import { VendorMoreMenuItem } from './utils'; import { VendorMoreMenuItem } from './utils';
import { import {
@@ -80,7 +80,7 @@ function VendorDetailsActionsBar({
}; };
return ( return (
<DashboardActionsBar> <DrawerActionsBar>
<NavbarGroup> <NavbarGroup>
<Popover <Popover
content={ content={
@@ -135,7 +135,7 @@ function VendorDetailsActionsBar({
}} }}
/> />
</NavbarGroup> </NavbarGroup>
</DashboardActionsBar> </DrawerActionsBar>
); );
} }

View File

@@ -1,5 +1,5 @@
.root { .root {
background: #fff; background: var(--color-element-customize-background);
} }
.mainFields{ .mainFields{
@@ -15,7 +15,7 @@
.footerActions{ .footerActions{
padding: 10px 16px; padding: 10px 16px;
border-top: 1px solid #d9d9d9; border-top: 1px solid var(--color-element-customize-divider);
flex-flow: row-reverse; flex-flow: row-reverse;
} }

View File

@@ -2,13 +2,13 @@
.root { .root {
align-items: center; align-items: center;
border-radius: 0; border-radius: 0;
box-shadow: 0 1px 0 rgba(17, 20, 24, .15); box-shadow: 0 1px 0 var(--color-element-customize-divider);
display: flex; display: flex;
flex: 0 0 auto; flex: 0 0 auto;
min-height: 55px; min-height: 55px;
padding: 5px 5px 5px 20px; padding: 5px 5px 5px 20px;
position: relative; position: relative;
background-color: #fff; background-color: var(--color-element-customize-header-background);
z-index: 1; z-index: 1;
} }
@@ -16,5 +16,5 @@
margin: 0; margin: 0;
font-size: 20px; font-size: 20px;
font-weight: 500; font-weight: 500;
color: #666; color: var(--color-element-customize-header-title-text);
} }

View File

@@ -1,6 +1,7 @@
import { Button, Classes } from '@blueprintjs/core'; import { Button, Classes } from '@blueprintjs/core';
import { Group, Icon } from '@/components'; import { Group, Icon } from '@/components';
import styles from './ElementCustomizeHeader.module.scss'; import styles from './ElementCustomizeHeader.module.scss';
import { useIsDarkMode } from '@/hooks/useDarkMode';
interface ElementCustomizeHeaderProps { interface ElementCustomizeHeaderProps {
label?: string; label?: string;
@@ -15,6 +16,8 @@ export function ElementCustomizeHeader({
onClose, onClose,
children, children,
}: ElementCustomizeHeaderProps) { }: ElementCustomizeHeaderProps) {
const isDarkmode = useIsDarkMode();
const handleClose = () => { const handleClose = () => {
onClose && onClose(); onClose && onClose();
}; };
@@ -25,7 +28,7 @@ export function ElementCustomizeHeader({
<Button <Button
aria-label="Close" aria-label="Close"
className={Classes.DIALOG_CLOSE_BUTTON} className={Classes.DIALOG_CLOSE_BUTTON}
icon={<Icon icon={'smallCross'} color={'#000'} />} icon={<Icon icon={'smallCross'} color={isDarkmode ? '#fff' : '#000'} />}
minimal={true} minimal={true}
onClick={handleClose} onClick={handleClose}
style={{ marginLeft: 'auto' }} style={{ marginLeft: 'auto' }}

View File

@@ -15,7 +15,11 @@ function ElementCustomizePreviewRoot({ closeDrawer }) {
return ( return (
<Stack <Stack
spacing={0} spacing={0}
style={{ borderLeft: '1px solid #D9D9D9', height: '100vh', flex: '1 1' }} style={{
borderLeft: '1px solid var(--color-element-customize-divider)',
height: '100vh',
flex: '1 1',
}}
> >
<ElementCustomizeHeader <ElementCustomizeHeader
label={'Preview'} label={'Preview'}

View File

@@ -5,7 +5,12 @@ export function ElementCustomizePreviewContent() {
const { PaperTemplate } = useElementCustomizeContext(); const { PaperTemplate } = useElementCustomizeContext();
return ( return (
<Stack backgroundColor="#F5F5F5" overflow="auto" flex="1 1 0%" spacing={0}> <Stack
backgroundColor="var(--color-element-customize-preview-background)"
overflow="auto"
flex="1 1 0%"
spacing={0}
>
{PaperTemplate} {PaperTemplate}
</Stack> </Stack>
); );

View File

@@ -8,7 +8,7 @@
.content{ .content{
padding: 5px; padding: 5px;
flex: 1; flex: 1;
border-right: 1px solid #E1E1E1; border-right: 1px solid var(--color-element-customize-divider);
} }
.tabsList{ .tabsList{

View File

@@ -1,10 +1,18 @@
.root { .root {
--x-border-color: #E1E1E1;
--x-color-placeholder-text: #738091;
.bp4-dark & {
--x-border-color: rgba(225, 225, 225, 0.15);
--x-color-placeholder-text: rgba(225, 225, 225, 0.65);
}
min-height: 120px; min-height: 120px;
height: 120px; height: 120px;
padding: 10px; padding: 10px;
border: 1px solid;
display: flex; display: flex;
border: 1px solid #E1E1E1; border-style: solid;
border-color: var(--x-border-color);
border-width: 1px;;
position: relative; position: relative;
display: flex; display: flex;
justify-content: center; justify-content: center;
@@ -25,7 +33,7 @@
} }
.contentPrePreview { .contentPrePreview {
color: #738091; color: var(--x-color-placeholder-text);
font-size: 13px; font-size: 13px;
height: 100%; height: 100%;
justify-content: center; justify-content: center;

View File

@@ -11,11 +11,9 @@ import {
MenuItem, MenuItem,
} from '@blueprintjs/core'; } from '@blueprintjs/core';
import { useFormikContext } from 'formik'; import { useFormikContext } from 'formik';
import { Group, FormattedMessage as T } from '@/components'; import { FormattedMessage as T, PageForm, Group } from '@/components';
import { useHistory } from 'react-router-dom'; import { useHistory } from 'react-router-dom';
import { CLASSES } from '@/constants/classes';
import classNames from 'classnames';
import { Icon, If } from '@/components'; import { Icon, If } from '@/components';
import { useExpenseFormContext } from './ExpenseFormPageProvider'; import { useExpenseFormContext } from './ExpenseFormPageProvider';
@@ -78,121 +76,120 @@ export default function ExpenseFloatingFooter() {
}; };
return ( return (
<Group <PageForm.FooterActions spacing={10} position="apart">
spacing={10} <Group spacing={10}>
className={classNames(CLASSES.PAGE_FORM_FLOATING_ACTIONS)} {/* ----------- Save And Publish ----------- */}
> <If condition={isNewMode}>
{/* ----------- Save And Publish ----------- */} <ButtonGroup>
<If condition={isNewMode}>
<ButtonGroup>
<Button
disabled={isSubmitting}
loading={isSubmitting}
intent={Intent.PRIMARY}
onClick={handleSubmitPublishBtnClick}
text={<T id={'save_publish'} />}
/>
<Popover
content={
<Menu>
<MenuItem
text={<T id={'publish_and_new'} />}
onClick={handleSubmitPublishAndNewBtnClick}
/>
<MenuItem
text={<T id={'publish_continue_editing'} />}
onClick={handleSubmitPublishContinueEditingBtnClick}
/>
</Menu>
}
minimal={true}
interactionKind={PopoverInteractionKind.CLICK}
position={Position.BOTTOM_LEFT}
>
<Button <Button
disabled={isSubmitting} disabled={isSubmitting}
loading={isSubmitting}
intent={Intent.PRIMARY} intent={Intent.PRIMARY}
rightIcon={<Icon icon="arrow-drop-up-16" iconSize={20} />} onClick={handleSubmitPublishBtnClick}
text={<T id={'save_publish'} />}
/> />
</Popover> <Popover
</ButtonGroup> content={
{/* ----------- Save As Draft ----------- */} <Menu>
<ButtonGroup> <MenuItem
<Button text={<T id={'publish_and_new'} />}
disabled={isSubmitting} onClick={handleSubmitPublishAndNewBtnClick}
className={'ml1'} />
onClick={handleSubmitDraftBtnClick} <MenuItem
text={<T id={'save_as_draft'} />} text={<T id={'publish_continue_editing'} />}
/> onClick={handleSubmitPublishContinueEditingBtnClick}
<Popover />
content={ </Menu>
<Menu> }
<MenuItem minimal={true}
text={<T id={'save_and_new'} />} interactionKind={PopoverInteractionKind.CLICK}
onClick={handleSubmitDraftAndNewBtnClick} position={Position.BOTTOM_LEFT}
/> >
<MenuItem <Button
text={<T id={'save_continue_editing'} />} disabled={isSubmitting}
onClick={handleSubmitDraftContinueEditingBtnClick} intent={Intent.PRIMARY}
/> rightIcon={<Icon icon="arrow-drop-up-16" iconSize={20} />}
</Menu> />
} </Popover>
minimal={true} </ButtonGroup>
interactionKind={PopoverInteractionKind.CLICK} {/* ----------- Save As Draft ----------- */}
position={Position.BOTTOM_LEFT} <ButtonGroup>
>
<Button <Button
disabled={isSubmitting} disabled={isSubmitting}
rightIcon={<Icon icon="arrow-drop-up-16" iconSize={20} />} className={'ml1'}
onClick={handleSubmitDraftBtnClick}
text={<T id={'save_as_draft'} />}
/> />
</Popover> <Popover
</ButtonGroup> content={
</If> <Menu>
{/* ----------- Save and New ----------- */} <MenuItem
<If condition={!isNewMode}> text={<T id={'save_and_new'} />}
<ButtonGroup> onClick={handleSubmitDraftAndNewBtnClick}
<Button />
disabled={isSubmitting} <MenuItem
loading={isSubmitting} text={<T id={'save_continue_editing'} />}
intent={Intent.PRIMARY} onClick={handleSubmitDraftContinueEditingBtnClick}
onClick={handleSubmitPublishBtnClick} />
style={{ minWidth: '85px' }} </Menu>
text={<T id={'save'} />} }
/> minimal={true}
<Popover interactionKind={PopoverInteractionKind.CLICK}
content={ position={Position.BOTTOM_LEFT}
<Menu> >
<MenuItem <Button
text={<T id={'save_and_new'} />} disabled={isSubmitting}
onClick={handleSubmitPublishAndNewBtnClick} rightIcon={<Icon icon="arrow-drop-up-16" iconSize={20} />}
/> />
</Menu> </Popover>
} </ButtonGroup>
minimal={true} </If>
interactionKind={PopoverInteractionKind.CLICK} {/* ----------- Save and New ----------- */}
position={Position.BOTTOM_LEFT} <If condition={!isNewMode}>
> <ButtonGroup>
<Button <Button
disabled={isSubmitting} disabled={isSubmitting}
loading={isSubmitting}
intent={Intent.PRIMARY} intent={Intent.PRIMARY}
rightIcon={<Icon icon="arrow-drop-up-16" iconSize={20} />} onClick={handleSubmitPublishBtnClick}
style={{ minWidth: '85px' }}
text={<T id={'save'} />}
/> />
</Popover> <Popover
</ButtonGroup> content={
</If> <Menu>
{/* ----------- Clear & Reset----------- */} <MenuItem
<Button text={<T id={'save_and_new'} />}
className={'ml1'} onClick={handleSubmitPublishAndNewBtnClick}
disabled={isSubmitting} />
onClick={handleClearBtnClick} </Menu>
text={!isNewMode ? <T id={'reset'} /> : <T id={'clear'} />} }
/> minimal={true}
{/* ----------- Cancel ----------- */} interactionKind={PopoverInteractionKind.CLICK}
<Button position={Position.BOTTOM_LEFT}
className={'ml1'} >
onClick={handleCancelBtnClick} <Button
text={<T id={'cancel'} />} disabled={isSubmitting}
/> intent={Intent.PRIMARY}
</Group> rightIcon={<Icon icon="arrow-drop-up-16" iconSize={20} />}
/>
</Popover>
</ButtonGroup>
</If>
{/* ----------- Clear & Reset----------- */}
<Button
className={'ml1'}
disabled={isSubmitting}
onClick={handleClearBtnClick}
text={!isNewMode ? <T id={'reset'} /> : <T id={'clear'} />}
/>
{/* ----------- Cancel ----------- */}
<Button
className={'ml1'}
onClick={handleCancelBtnClick}
text={<T id={'cancel'} />}
/>
</Group>
</PageForm.FooterActions>
); );
} }

View File

@@ -1,12 +1,11 @@
// @ts-nocheck // @ts-nocheck
import React, { useMemo } from 'react'; import React, { useMemo } from 'react';
import intl from 'react-intl-universal'; import intl from 'react-intl-universal';
import classNames from 'classnames';
import { Intent } from '@blueprintjs/core'; import { Intent } from '@blueprintjs/core';
import { defaultTo, sumBy, isEmpty } from 'lodash'; import { defaultTo, sumBy, isEmpty } from 'lodash';
import { Formik, Form } from 'formik'; import { Formik, Form } from 'formik';
import { useHistory } from 'react-router-dom'; import { useHistory } from 'react-router-dom';
import { CLASSES } from '@/constants/classes'; import { css } from '@emotion/css';
import ExpenseFormBody from './ExpenseFormBody'; import ExpenseFormBody from './ExpenseFormBody';
import ExpenseFormHeader from './ExpenseFormHeader'; import ExpenseFormHeader from './ExpenseFormHeader';
@@ -20,7 +19,8 @@ import withDashboardActions from '@/containers/Dashboard/withDashboardActions';
import withSettings from '@/containers/Settings/withSettings'; import withSettings from '@/containers/Settings/withSettings';
import withCurrentOrganization from '@/containers/Organization/withCurrentOrganization'; import withCurrentOrganization from '@/containers/Organization/withCurrentOrganization';
import { AppToaster } from '@/components'; import { AppToaster, Box } from '@/components';
import { PageForm } from '@/components/PageForm';
import { import {
CreateExpenseFormSchema, CreateExpenseFormSchema,
EditExpenseFormSchema, EditExpenseFormSchema,
@@ -129,29 +129,38 @@ function ExpenseForm({
}; };
return ( return (
<div <Formik
className={classNames( validationSchema={
CLASSES.PAGE_FORM, isNewMode ? CreateExpenseFormSchema : EditExpenseFormSchema
CLASSES.PAGE_FORM_STRIP_STYLE, }
CLASSES.PAGE_FORM_EXPENSE, initialValues={initialValues}
)} onSubmit={handleSubmit}
> >
<Formik <Form
validationSchema={ className={css({
isNewMode ? CreateExpenseFormSchema : EditExpenseFormSchema overflow: 'hidden',
} display: 'flex',
initialValues={initialValues} flexDirection: 'column',
onSubmit={handleSubmit} flex: 1,
})}
> >
<Form> <PageForm flex={1}>
<ExpenseFormTopBar /> <PageForm.Body>
<ExpenseFormHeader /> <ExpenseFormTopBar />
<ExpenseFormBody /> <ExpenseFormHeader />
<ExpenseFormFooter />
<ExpenseFloatingFooter /> <Box p="18px 32px 0">
</Form> <ExpenseFormBody />
</Formik> </Box>
</div> <ExpenseFormFooter />
</PageForm.Body>
<PageForm.Footer>
<ExpenseFloatingFooter />
</PageForm.Footer>
</PageForm>
</Form>
</Formik>
); );
} }

View File

@@ -1,13 +1,7 @@
// @ts-nocheck // @ts-nocheck
import React from 'react'; import React from 'react';
import classNames from 'classnames';
import { CLASSES } from '@/constants/classes';
import ExpenseFormEntriesField from './ExpenseFormEntriesField'; import ExpenseFormEntriesField from './ExpenseFormEntriesField';
export default function ExpenseFormBody() { export default function ExpenseFormBody() {
return ( return <ExpenseFormEntriesField />;
<div className={classNames(CLASSES.PAGE_FORM_BODY)}>
<ExpenseFormEntriesField />
</div>
);
} }

View File

@@ -1,8 +1,6 @@
// @ts-nocheck // @ts-nocheck
import React from 'react'; import React from 'react';
import classNames from 'classnames'; import { x } from '@xstyled/emotion';
import { CLASSES } from '@/constants/classes';
import { Row, Col, Paper } from '@/components'; import { Row, Col, Paper } from '@/components';
import { ExpenseFormFooterLeft } from './ExpenseFormFooterLeft'; import { ExpenseFormFooterLeft } from './ExpenseFormFooterLeft';
import { ExpenseFormFooterRight } from './ExpenseFormFooterRight'; import { ExpenseFormFooterRight } from './ExpenseFormFooterRight';
@@ -10,7 +8,7 @@ import { UploadAttachmentButton } from '@/containers/Attachments/UploadAttachmen
export default function ExpenseFormFooter() { export default function ExpenseFormFooter() {
return ( return (
<div className={classNames(CLASSES.PAGE_FORM_FOOTER)}> <x.div mt={'20px'} px={'32px'} pb={'20px'} flex={1}>
<Paper p={'20px'}> <Paper p={'20px'}>
<Row> <Row>
<Col md={8}> <Col md={8}>
@@ -23,6 +21,6 @@ export default function ExpenseFormFooter() {
</Col> </Col>
</Row> </Row>
</Paper> </Paper>
</div> </x.div>
); );
} }

View File

@@ -8,10 +8,7 @@ import {
TotalLineBorderStyle, TotalLineBorderStyle,
TotalLineTextStyle, TotalLineTextStyle,
} from '@/components'; } from '@/components';
import { import { useExpenseSubtotalFormatted, useExpenseTotalFormatted } from './utils';
useExpenseSubtotalFormatted,
useExpenseTotalFormatted,
} from './utils';
export function ExpenseFormFooterRight() { export function ExpenseFormFooterRight() {
const totalFormatted = useExpenseTotalFormatted(); const totalFormatted = useExpenseTotalFormatted();
@@ -34,6 +31,11 @@ export function ExpenseFormFooterRight() {
} }
const ExpensesTotalLines = styled(TotalLines)` const ExpensesTotalLines = styled(TotalLines)`
--x-color-text: #555555;
.bp4-dark & {
--x-color-text: var(--color-light-gray4);
}
width: 100%; width: 100%;
color: #555555; color: var(--x-color-text);
`; `;

View File

@@ -1,11 +1,9 @@
// @ts-nocheck // @ts-nocheck
import React from 'react'; import React from 'react';
import classNames from 'classnames';
import { FormattedMessage as T } from '@/components'; import { FormattedMessage as T } from '@/components';
import { CLASSES } from '@/constants/classes';
import ExpenseFormHeaderFields from './ExpenseFormHeaderFields'; import ExpenseFormHeaderFields from './ExpenseFormHeaderFields';
import { PageFormBigNumber } from '@/components'; import { PageForm, PageFormBigNumber } from '@/components';
import { useExpenseTotalFormatted } from './utils'; import { useExpenseTotalFormatted } from './utils';
// Expense form header. // Expense form header.
@@ -13,12 +11,12 @@ export default function ExpenseFormHeader() {
const totalFormatted = useExpenseTotalFormatted(); const totalFormatted = useExpenseTotalFormatted();
return ( return (
<div className={classNames(CLASSES.PAGE_FORM_HEADER)}> <PageForm.Header>
<ExpenseFormHeaderFields /> <ExpenseFormHeaderFields />
<PageFormBigNumber <PageFormBigNumber
label={<T id={'expense_amount'} />} label={<T id={'expense_amount'} />}
amount={totalFormatted} amount={totalFormatted}
/> />
</div> </PageForm.Header>
); );
} }

View File

@@ -3,8 +3,16 @@ import React from 'react';
import { FormGroup, Position, Classes } from '@blueprintjs/core'; import { FormGroup, Position, Classes } from '@blueprintjs/core';
import { DateInput } from '@blueprintjs/datetime'; import { DateInput } from '@blueprintjs/datetime';
import { FastField, ErrorMessage } from 'formik'; import { FastField, ErrorMessage } from 'formik';
import { CustomersSelect, FInputGroup, FormattedMessage as T } from '@/components'; import { css } from '@emotion/css';
import classNames from 'classnames'; import classNames from 'classnames';
import { useTheme } from '@emotion/react';
import {
CustomersSelect,
FInputGroup,
Stack,
FormattedMessage as T,
} from '@/components';
import { CLASSES } from '@/constants/classes'; import { CLASSES } from '@/constants/classes';
import { import {
momentFormatter, momentFormatter,
@@ -14,8 +22,8 @@ import {
} from '@/utils'; } from '@/utils';
import { customersFieldShouldUpdate, accountsFieldShouldUpdate } from './utils'; import { customersFieldShouldUpdate, accountsFieldShouldUpdate } from './utils';
import { import {
CurrencySelectList,
FFormGroup, FFormGroup,
FSelect,
AccountsSelect, AccountsSelect,
FieldRequiredHint, FieldRequiredHint,
Hint, Hint,
@@ -24,14 +32,33 @@ import { ExpensesExchangeRateInputField } from './components';
import { useExpenseFormContext } from './ExpenseFormPageProvider'; import { useExpenseFormContext } from './ExpenseFormPageProvider';
import { SUPPORTED_EXPENSE_PAYMENT_ACCOUNT_TYPES } from './constants'; import { SUPPORTED_EXPENSE_PAYMENT_ACCOUNT_TYPES } from './constants';
const getFieldsStyle = (theme: Theme) => css`
.${theme.bpPrefix}-form-group {
margin-bottom: 0;
&.${theme.bpPrefix}-inline {
max-width: 450px;
}
.${theme.bpPrefix}-label {
min-width: 150px;
font-weight: 500;
}
.${theme.bpPrefix}-form-content {
width: 100%;
}
}
`;
/** /**
* Expense form header. * Expense form header.
*/ */
export default function ExpenseFormHeader() { export default function ExpenseFormHeader() {
const { currencies, accounts, customers } = useExpenseFormContext(); const { currencies, accounts, customers } = useExpenseFormContext();
const theme = useTheme();
const fieldsClassName = getFieldsStyle(theme);
return ( return (
<div className={classNames(CLASSES.PAGE_FORM_HEADER_FIELDS)}> <Stack spacing={18} flex={1} className={fieldsClassName}>
<FastField name={'payment_date'}> <FastField name={'payment_date'}>
{({ form, field: { value }, meta: { error, touched } }) => ( {({ form, field: { value }, meta: { error, touched } }) => (
<FormGroup <FormGroup
@@ -75,30 +102,24 @@ export default function ExpenseFormHeader() {
/> />
</FFormGroup> </FFormGroup>
<FastField name={'currency_code'}> <FFormGroup
{({ form, field: { value }, meta: { error, touched } }) => ( name={'currency_code'}
<FormGroup label={<T id={'currency'} />}
label={<T id={'currency'} />} className={classNames(Classes.FILL)}
className={classNames( inline={true}
'form-group--select-list', fastField={true}
'form-group--currency', >
Classes.FILL, <FSelect
)} name={'currency_code'}
intent={inputIntent({ error, touched })} items={currencies}
helperText={<ErrorMessage name="currency_code" />} valueAccessor={'currency_code'}
inline={true} textAccessor={'currency_code'}
> labelAccessor={'currency_code'}
<CurrencySelectList popoverProps={{ minimal: true }}
currenciesList={currencies} fill={true}
selectedCurrencyCode={value} fastField={true}
onCurrencySelected={(currencyItem) => { />
form.setFieldValue('currency_code', currencyItem.currency_code); </FFormGroup>
}}
defaultSelectText={value}
/>
</FormGroup>
)}
</FastField>
{/* ----------- Exchange rate ----------- */} {/* ----------- Exchange rate ----------- */}
<ExpensesExchangeRateInputField <ExpensesExchangeRateInputField
@@ -118,7 +139,7 @@ export default function ExpenseFormHeader() {
{/* ----------- Customer ----------- */} {/* ----------- Customer ----------- */}
<ExpenseFormCustomerSelect /> <ExpenseFormCustomerSelect />
</div> </Stack>
); );
} }

View File

@@ -1,9 +1,6 @@
// @ts-nocheck // @ts-nocheck
import React from 'react'; import React from 'react';
import { useParams } from 'react-router-dom'; import { useParams } from 'react-router-dom';
import '@/style/pages/Expense/PageForm.scss';
import ExpenseForm from './ExpenseForm'; import ExpenseForm from './ExpenseForm';
import { ExpenseFormPageProvider } from './ExpenseFormPageProvider'; import { ExpenseFormPageProvider } from './ExpenseFormPageProvider';

View File

@@ -1,5 +1,6 @@
// @ts-nocheck // @ts-nocheck
import React, { createContext } from 'react'; import React, { createContext } from 'react';
import { css } from '@emotion/css';
import { DashboardInsider } from '@/components/Dashboard'; import { DashboardInsider } from '@/components/Dashboard';
import { Features } from '@/constants'; import { Features } from '@/constants';
import { useFeatureCan } from '@/hooks/state'; import { useFeatureCan } from '@/hooks/state';
@@ -98,6 +99,10 @@ function ExpenseFormPageProvider({ query, expenseId, ...props }) {
isProjectsLoading isProjectsLoading
} }
name={'expense-form'} name={'expense-form'}
className={css`
min-height: calc(100vh - var(--top-offset));
max-height: calc(100vh - var(--top-offset));
`}
> >
<ExpenseFormPageContext.Provider value={provider} {...props} /> <ExpenseFormPageContext.Provider value={provider} {...props} />
</DashboardInsider> </DashboardInsider>

View File

@@ -47,16 +47,26 @@ export default function APAgingSummaryTable({
} }
const APAgingSummaryDataTable = styled(ReportDataTable)` const APAgingSummaryDataTable = styled(ReportDataTable)`
--color-table-text-color: #252a31;
--color-table-total-text-color: #000;
--color-table-total-border-top: #bbb;
.bp4-dark & {
--color-table-text-color: var(--color-light-gray1);
--color-table-total-text-color: var(--color-light-gray4);
--color-table-total-border-top: var(--color-dark-gray5);
}
.table { .table {
.tbody .tr { .tbody .tr {
.td { .td {
border-bottom: 0; border-bottom-width: 0;
padding-top: 0.32rem; padding-top: 0.32rem;
padding-bottom: 0.32rem; padding-bottom: 0.32rem;
} }
&:not(.no-results) { &:not(.no-results) {
.td { .td {
border-bottom: 0; border-bottom-width: 0;
padding-top: 0.4rem; padding-top: 0.4rem;
padding-bottom: 0.4rem; padding-bottom: 0.4rem;
} }
@@ -67,8 +77,9 @@ const APAgingSummaryDataTable = styled(ReportDataTable)`
font-weight: 500; font-weight: 500;
.td { .td {
border-top: 1px solid #bbb; border-top: 1px solid var(--color-table-total-border-top);
border-bottom: 3px double #333; border-bottom-width: 3px;
border-bottom-style: double;
} }
} }
} }

Some files were not shown because too many files have changed in this diff Show More