From f9a7021f554816767e8e27a758f53933c97a6b97 Mon Sep 17 00:00:00 2001 From: "a.bouhuolia" Date: Tue, 4 Oct 2022 00:29:48 +0200 Subject: [PATCH] feat: Add Box, Group and Stack layout components. --- src/components/Layout/Box/Box.tsx | 11 ++ src/components/Layout/Box/index.ts | 1 + src/components/Layout/Group/Group.tsx | 56 +++++++ src/components/Layout/Group/_utils.ts | 5 + src/components/Layout/Group/index.ts | 1 + src/components/Layout/Stack/Stack.tsx | 36 +++++ src/components/Layout/Stack/index.ts | 1 + src/components/Layout/index.ts | 3 + src/components/index.tsx | 1 + src/constants/sidebarMenu.tsx | 2 +- .../EstimatedExpenseFormFields.tsx | 2 - .../ProjectBillableEntriesProvider.tsx | 2 +- .../ProjectFormDialog/ProjectFormFields.tsx | 150 +++++++++--------- .../ProjectFormFloatingActions.tsx | 13 +- .../containers/ProjectFormDialog/index.tsx | 3 +- .../ProjectsLanding/ProjectsActionsBar.tsx | 3 +- .../ProjectsLanding/ProjectsDataTable.tsx | 15 +- 17 files changed, 204 insertions(+), 101 deletions(-) create mode 100644 src/components/Layout/Box/Box.tsx create mode 100644 src/components/Layout/Box/index.ts create mode 100644 src/components/Layout/Group/Group.tsx create mode 100644 src/components/Layout/Group/_utils.ts create mode 100644 src/components/Layout/Group/index.ts create mode 100644 src/components/Layout/Stack/Stack.tsx create mode 100644 src/components/Layout/Stack/index.ts create mode 100644 src/components/Layout/index.ts diff --git a/src/components/Layout/Box/Box.tsx b/src/components/Layout/Box/Box.tsx new file mode 100644 index 000000000..fdc7fd949 --- /dev/null +++ b/src/components/Layout/Box/Box.tsx @@ -0,0 +1,11 @@ +import React from 'react'; + +export interface BoxProps { + className?: string; +} + +export function Box({ className, ...rest }: BoxProps) { + const Element = 'div'; + + return ; +} diff --git a/src/components/Layout/Box/index.ts b/src/components/Layout/Box/index.ts new file mode 100644 index 000000000..687e0bbff --- /dev/null +++ b/src/components/Layout/Box/index.ts @@ -0,0 +1 @@ +export * from './Box'; \ No newline at end of file diff --git a/src/components/Layout/Group/Group.tsx b/src/components/Layout/Group/Group.tsx new file mode 100644 index 000000000..205f68da1 --- /dev/null +++ b/src/components/Layout/Group/Group.tsx @@ -0,0 +1,56 @@ +import React from 'react'; +import styled from 'styled-components'; +import { Box } from '../Box'; +import { filterFalsyChildren } from './_utils'; + +export type GroupPosition = 'right' | 'center' | 'left' | 'apart'; + +export const GROUP_POSITIONS = { + left: 'flex-start', + center: 'center', + right: 'flex-end', + apart: 'space-between', +}; + +export interface GroupProps extends React.ComponentPropsWithoutRef<'div'> { + /** Defines justify-content property */ + position?: GroupPosition; + + /** Defined flex-wrap property */ + noWrap?: boolean; + + /** Defines flex-grow property for each element, true -> 1, false -> 0 */ + grow?: boolean; + + /** Space between elements */ + spacing?: number; + + /** Defines align-items css property */ + align?: React.CSSProperties['alignItems']; +} + +const defaultProps: Partial = { + position: 'left', + spacing: 20, +}; + +export function Group({ children, ...props }: GroupProps) { + const groupProps = { + ...defaultProps, + ...props, + }; + const filteredChildren = filterFalsyChildren(children); + + return {filteredChildren}; +} + +const GroupStyled = styled(Box)` + box-sizing: border-box; + display: flex; + flex-direction: row; + align-items: center; + flex-wrap: ${(props: GroupProps) => (props.noWrap ? 'nowrap' : 'wrap')}; + justify-content: ${(props: GroupProps) => + GROUP_POSITIONS[props.position || 'left']}; + gap: ${(props: GroupProps) => props.spacing}px; +`; diff --git a/src/components/Layout/Group/_utils.ts b/src/components/Layout/Group/_utils.ts new file mode 100644 index 000000000..927695750 --- /dev/null +++ b/src/components/Layout/Group/_utils.ts @@ -0,0 +1,5 @@ +import { Children, ReactElement, ReactNode } from 'react'; + +export function filterFalsyChildren(children: ReactNode) { + return (Children.toArray(children) as ReactElement[]).filter(Boolean); +} diff --git a/src/components/Layout/Group/index.ts b/src/components/Layout/Group/index.ts new file mode 100644 index 000000000..d8cf38332 --- /dev/null +++ b/src/components/Layout/Group/index.ts @@ -0,0 +1 @@ +export * from './Group'; \ No newline at end of file diff --git a/src/components/Layout/Stack/Stack.tsx b/src/components/Layout/Stack/Stack.tsx new file mode 100644 index 000000000..da1a9af6c --- /dev/null +++ b/src/components/Layout/Stack/Stack.tsx @@ -0,0 +1,36 @@ +import React from 'react'; +import styled from 'styled-components'; +import { Box } from '../Box'; + +export interface StackProps extends React.ComponentPropsWithoutRef<'div'> { + /** Key of theme.spacing or number to set gap in px */ + spacing?: number; + + /** align-items CSS property */ + align?: React.CSSProperties['alignItems']; + + /** justify-content CSS property */ + justify?: React.CSSProperties['justifyContent']; +} + +const defaultProps: Partial = { + spacing: 20, + align: 'stretch', + justify: 'top', +}; + +export function Stack(props: StackProps) { + const stackProps = { + ...defaultProps, + ...props, + }; + return ; +} + +const StackStyled = styled(Box)` + display: flex; + flex-direction: column; + align-items: align; + justify-content: justify; + gap: ${(props: StackProps) => props.spacing}px; +`; diff --git a/src/components/Layout/Stack/index.ts b/src/components/Layout/Stack/index.ts new file mode 100644 index 000000000..31e62b8b7 --- /dev/null +++ b/src/components/Layout/Stack/index.ts @@ -0,0 +1 @@ +export * from './Stack'; \ No newline at end of file diff --git a/src/components/Layout/index.ts b/src/components/Layout/index.ts new file mode 100644 index 000000000..4924faddb --- /dev/null +++ b/src/components/Layout/index.ts @@ -0,0 +1,3 @@ +export * from './Box'; +export * from './Group'; +export * from './Stack'; \ No newline at end of file diff --git a/src/components/index.tsx b/src/components/index.tsx index b8940553b..79efd3148 100644 --- a/src/components/index.tsx +++ b/src/components/index.tsx @@ -63,5 +63,6 @@ export * from './Indicator'; export * from './EmptyStatus'; export * from './Postbox'; export * from './AppToaster'; +export * from './Layout'; export { MODIFIER, ContextMenu, AvaterCell }; diff --git a/src/constants/sidebarMenu.tsx b/src/constants/sidebarMenu.tsx index 4b66906a9..48e3146d8 100644 --- a/src/constants/sidebarMenu.tsx +++ b/src/constants/sidebarMenu.tsx @@ -549,7 +549,7 @@ export const SidebarMenu = [ overlayId: ISidebarMenuOverlayIds.Projects, children: [ { - text: 'Projects Management', + text: 'Projects', type: ISidebarMenuItemType.Group, children: [ { diff --git a/src/containers/Projects/containers/EstimatedExpenseFormDialog/EstimatedExpenseFormFields.tsx b/src/containers/Projects/containers/EstimatedExpenseFormDialog/EstimatedExpenseFormFields.tsx index b94f78e5f..eb5ac44e5 100644 --- a/src/containers/Projects/containers/EstimatedExpenseFormDialog/EstimatedExpenseFormFields.tsx +++ b/src/containers/Projects/containers/EstimatedExpenseFormDialog/EstimatedExpenseFormFields.tsx @@ -8,7 +8,6 @@ import { FFormGroup, FInputGroup, FormattedMessage as T, - FieldRequiredHint, } from '@/components'; import { ExpenseSelect, @@ -100,7 +99,6 @@ const MetaLineLabel = styled.div` font-weight: 500; margin-bottom: 8px; `; - const EstimatedAmountWrap = styled.div` display: block; text-align: right; diff --git a/src/containers/Projects/containers/ProjectBillableEntries/ProjectBillableEntriesProvider.tsx b/src/containers/Projects/containers/ProjectBillableEntries/ProjectBillableEntriesProvider.tsx index 243a2170f..88397765a 100644 --- a/src/containers/Projects/containers/ProjectBillableEntries/ProjectBillableEntriesProvider.tsx +++ b/src/containers/Projects/containers/ProjectBillableEntries/ProjectBillableEntriesProvider.tsx @@ -1,6 +1,6 @@ // @ts-nocheck -import React, { useState } from 'react'; +import React from 'react'; import { useProjectBillableEntries } from '../../hooks'; import { DialogContent } from '@/components'; diff --git a/src/containers/Projects/containers/ProjectFormDialog/ProjectFormFields.tsx b/src/containers/Projects/containers/ProjectFormDialog/ProjectFormFields.tsx index 006d57f58..d4877d4d5 100644 --- a/src/containers/Projects/containers/ProjectFormDialog/ProjectFormFields.tsx +++ b/src/containers/Projects/containers/ProjectFormDialog/ProjectFormFields.tsx @@ -17,13 +17,9 @@ import { FormattedMessage as T, FieldRequiredHint, CustomerSelectField, + Stack, } from '@/components'; -import { - inputIntent, - momentFormatter, - tansformDateValue, - handleDateChange, -} from '@/utils'; +import { inputIntent, momentFormatter } from '@/utils'; import { useProjectFormContext } from './ProjectFormProvider'; /** @@ -39,76 +35,80 @@ function ProjectFormFields() { return (
- {/*------------ Contact -----------*/} - - {({ form, field: { value }, meta: { error, touched } }) => ( - } - className={classNames('form-group--select-list', Classes.FILL)} - intent={inputIntent({ error, touched })} - > - { - form.setFieldValue('contact_id', customer.id); - }} - allowCreate={true} - popoverFill={true} - /> - - )} - - {/*------------ Project Name -----------*/} - } - > - - - {/*------------ DeadLine -----------*/} - - date.toLocaleString()} - popoverProps={{ - position: Position.BOTTOM, - minimal: true, - }} - /> - + + {/*------------ Contact -----------*/} + + {({ form, field: { value }, meta: { error, touched } }) => ( + + { + form.setFieldValue('contact_id', customer.id); + }} + allowCreate={true} + popoverFill={true} + /> + + )} + - {/*------------ CheckBox -----------*/} - - - - {/*------------ Cost Estimate -----------*/} - } - > - - - - - + {/*------------ Project Name -----------*/} + + + + + + {/*------------ DeadLine -----------*/} + + date.toLocaleString()} + popoverProps={{ + position: Position.BOTTOM, + minimal: true, + }} + /> + + + {/*------------ CheckBox -----------*/} + + + + + + {/*------------ Cost Estimate -----------*/} + + + + + + +
); } diff --git a/src/containers/Projects/containers/ProjectFormDialog/ProjectFormFloatingActions.tsx b/src/containers/Projects/containers/ProjectFormDialog/ProjectFormFloatingActions.tsx index 9384ae986..51577b2e3 100644 --- a/src/containers/Projects/containers/ProjectFormDialog/ProjectFormFloatingActions.tsx +++ b/src/containers/Projects/containers/ProjectFormDialog/ProjectFormFloatingActions.tsx @@ -18,24 +18,13 @@ function ProjectFormFloatingActions({ // Formik context. const { isSubmitting } = useFormikContext(); - // project form dialog context. - const { dialogName } = useProjectFormContext(); - - // Handle close button click. - const handleCancelBtnClick = () => { - closeDialog(dialogName); - }; - return (
-