Skip to content

Commit

Permalink
feat(client): add base card list (#233)
Browse files Browse the repository at this point in the history
* feat(client): add base card list

* fix(client): add specific date for fields stories
  • Loading branch information
Jozwiaczek committed Apr 7, 2021
1 parent ae6c905 commit a7979b0
Show file tree
Hide file tree
Showing 16 changed files with 295 additions and 27 deletions.
5 changes: 3 additions & 2 deletions packages/client/src/elements/AppBar/AppBar.styled.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,12 @@ export const TabsWrapper = styled.div<{ orientation?: TabsOrientation }>`
export const TabPageWrapper = styled.div<{ orientation?: TabsOrientation }>`
width: 100%;
height: 100%;
margin-bottom: 90px;
padding-bottom: 90px;
${({ orientation }) =>
orientation === 'vertical' &&
`
margin-left: 160px;
padding-bottom: 0;
padding-left: 160px;
`};
`;

Expand Down
92 changes: 92 additions & 0 deletions packages/client/src/elements/CardList/CardList.styled.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import styled from 'styled-components';

import { IconButton } from '../buttons';
import Card from '../Card';

export const Wrapper = styled.div`
display: flex;
justify-content: center;
align-items: flex-start;
flex-wrap: wrap;
`;

export const StyledCard = styled(Card)`
position: relative;
width: 100%;
max-width: 340px;
display: flex;
justify-content: center;
align-items: flex-start;
flex-direction: column;
padding: 24px;
> * {
display: block;
margin-top: 20px;
}
> *:first-child,
*:nth-child(2) {
margin-top: 0;
}
${({ theme: { down, breakpoints } }) => `
${down(breakpoints.md)} {
max-width: 100%;
}
`};
`;

export const FiltersButton = styled(IconButton)`
svg {
color: ${({ theme }) => theme.palette.primary.light};
}
`;

export const EditButton = styled(IconButton)`
position: absolute;
top: 10px;
right: 10px;
svg {
color: ${({ theme }) => theme.palette.text.primary};
}
`;

export const CardsWrapper = styled.div`
display: flex;
justify-content: center;
align-items: flex-start;
flex-wrap: wrap;
> *:not(:last-child) {
margin-bottom: 40px;
}
${({ theme: { up, breakpoints } }) => `
${up(breakpoints.md)} {
> *:nth-child(2n + 1) {
margin-right: 40px;
}
}
`};
`;

export const TitleWrapper = styled.div`
* {
font-size: 24px;
line-height: 23px;
font-weight: 700;
}
`;

export const FiltersContainer = styled.div`
display: flex;
width: 100%;
padding: 40px 20px;
justify-content: space-between;
align-items: center;
max-width: 740px;
`;

export const CardFieldContainer = styled.div`
display: flex;
`;
6 changes: 6 additions & 0 deletions packages/client/src/elements/CardList/CardList.types.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { ReactNode } from 'react';

interface CardListProps {
children: ReactNode;
resource: string;
}
80 changes: 80 additions & 0 deletions packages/client/src/elements/CardList/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import React, { Children, cloneElement, isValidElement } from 'react';
import { useQuery } from 'react-query';
import { useHistory } from 'react-router-dom';

import { routes } from '../../constants';
import { EditIcon, FiltersIcon } from '../../icons';
import { ApiList } from '../../interfaces/api.types';
import { getLabelFromSource } from '../../utils';
import { BaseFieldProps, BaseRecordField } from '../fields/Fields.types';
import {
CardFieldContainer,
CardsWrapper,
EditButton,
FiltersButton,
FiltersContainer,
StyledCard,
TitleWrapper,
Wrapper,
} from './CardList.styled';
import { CardListProps } from './CardList.types';

const CardList = ({ children, resource }: CardListProps) => {
const queryResult = useQuery<ApiList<BaseRecordField>>(`/${resource}`);
const records = queryResult.data?.data;
const history = useHistory();

const onClickEdit = (id: string) => {
// TODO: move to user details
console.log(id);
history.push(routes.authorized.appBar.admin.USERS);
};

return (
<Wrapper data-testid="cardList">
<FiltersContainer>
{/* TODO: add search input */}
<p>Search</p>
<FiltersButton>
<FiltersIcon />
</FiltersButton>
</FiltersContainer>
<CardsWrapper>
{records?.map((record) => {
const { id } = record;
return (
<StyledCard key={id}>
<EditButton onClick={() => onClickEdit(id)}>
<EditIcon />
</EditButton>
{Children.map(children, (child) => {
if (!isValidElement(child)) {
return null;
}

const { source, asTitle, label, noLabel } = child.props as BaseFieldProps<unknown>;

if (asTitle) {
return <TitleWrapper>{cloneElement(child, { record })}</TitleWrapper>;
}

const internalLabel = label || getLabelFromSource(source || '');

return (
<CardFieldContainer key={`${id}-${source}`}>
{!noLabel && <p>{internalLabel}:&nbsp;</p>}
{cloneElement(child, { record })}
</CardFieldContainer>
);
})}
</StyledCard>
);
})}
</CardsWrapper>
</Wrapper>
);
};

CardList.displayName = 'CardList';

export default CardList;
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ Default.args = {
source: 'createdAt',
record: {
id: 'z1s234sd',
createdAt: new Date(),
updatedAt: new Date(),
createdAt: new Date('04.03.2021'),
updatedAt: new Date('04.03.2021'),
},
};
2 changes: 2 additions & 0 deletions packages/client/src/elements/fields/Fields.types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ interface BaseFieldProps<T> {
label?: string;
source: keyof T;
record?: T;
asTitle?: boolean;
noLabel?: boolean;
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ Default.args = {
id: 'z1s234sd',
firstName: 'Joe',
lastName: 'Doe',
createdAt: new Date(),
updatedAt: new Date(),
createdAt: new Date('04.03.2021'),
updatedAt: new Date('04.03.2021'),
},
render: ({ firstName, lastName }) => `${firstName} ${lastName}`,
};
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ Default.args = {
record: {
id: 'z1s234sd',
email: 'joe.doe@email.com',
createdAt: new Date(),
updatedAt: new Date(),
createdAt: new Date('04.03.2021'),
updatedAt: new Date('04.03.2021'),
},
};
1 change: 1 addition & 0 deletions packages/client/src/elements/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export {
export { default as BackgroundSideLogo } from './BackgroundSideLogo';
export { BackButton, Button, IconButton } from './buttons';
export { default as Card } from './Card';
export { default as CardList } from './CardList';
export { default as Copyright } from './Copyright';
export { DateField, FunctionField, TextField } from './fields';
export { default as Form } from './Form';
Expand Down
32 changes: 32 additions & 0 deletions packages/client/src/icons/EditIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import React, { forwardRef, memo, Ref, SVGProps } from 'react';
import { useTheme } from 'styled-components';

const EditIcon = (props: SVGProps<SVGSVGElement>, svgRef?: Ref<SVGSVGElement>) => {
const { palette } = useTheme();
return (
<svg
width="32"
height="33"
viewBox="0 0 32 33"
fill="none"
xmlns="http://www.w3.org/2000/svg"
ref={svgRef}
{...props}
>
<path
d="M27.4367 2.04214L30.3368 4.94231C31.1179 5.72335 31.1179 6.98969 30.3368 7.77073L12.3687 25.7389L5.2849 28.3805C4.48208 28.6798 3.69915 27.8969 3.99853 27.0941L6.64007 20.0103L24.6082 2.04214C25.3893 1.26109 26.6556 1.26109 27.4367 2.04214Z"
fill="currentColor"
/>
<rect
x="22.1641"
y="3.24976"
width="10"
height="3.06086"
transform="rotate(45 22.1641 3.24976)"
fill={palette.background.paper}
/>
</svg>
);
};

export default memo(forwardRef(EditIcon));
20 changes: 20 additions & 0 deletions packages/client/src/icons/FiltersIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import React, { forwardRef, memo, Ref, SVGProps } from 'react';

const FiltersIcon = (props: SVGProps<SVGSVGElement>, svgRef?: Ref<SVGSVGElement>) => (
<svg
width="29"
height="31"
viewBox="0 0 24 26"
fill="none"
xmlns="http://www.w3.org/2000/svg"
ref={svgRef}
{...props}
>
<path
d="M22.6667 0H1.33333C0.596 0 0 0.596 0 1.33333V4.78667C0 5.484 0.284 6.16933 0.777333 6.66267L8 13.8853V24C8 24.4627 8.24 24.8907 8.63333 25.1347C8.84667 25.2667 9.08933 25.3333 9.33333 25.3333C9.53733 25.3333 9.74133 25.2867 9.92933 25.1933L15.2627 22.5267C15.7147 22.3 16 21.8387 16 21.3333V13.8853L23.2227 6.66267C23.716 6.16933 24 5.484 24 4.78667V1.33333C24 0.596 23.404 0 22.6667 0ZM13.724 12.3907C13.4733 12.64 13.3333 12.9787 13.3333 13.3333V20.5093L10.6667 21.8427V13.3333C10.6667 12.9787 10.5267 12.64 10.276 12.3907L2.66667 4.78667V2.66667H21.3347L21.3373 4.77733L13.724 12.3907Z"
fill="currentColor"
/>
</svg>
);

export default memo(forwardRef(FiltersIcon));
2 changes: 2 additions & 0 deletions packages/client/src/icons/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ export { default as ChevronDownIcon } from './ChevronDownIcon';
export { default as ConfirmLockIcon } from './ConfirmLockIcon';
export { default as DashboardIcon } from './DashboardIcon';
export { default as DeviceIcon } from './DeviceIcon';
export { default as EditIcon } from './EditIcon';
export { default as EmailIcon } from './EmailIcon';
export { default as FiltersIcon } from './FiltersIcon';
export { default as HistoryIcon } from './HistoryIcon';
export { default as InvitationIcon } from './InvitationIcon';
export { default as LockIcon } from './LockIcon';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@ import { Button } from '../../../../elements';
export const CardsWrapper = styled.div(
({ theme: { breakpoints, up } }) => `
display: grid;
gap: 60px;
width: 100%;
margin-top: 60px;
grid-template-columns: repeat(auto-fill,minmax(250px,1fr));
row-gap: 60px;
column-gap: 60px;
${up(breakpoints.md)} {
max-width: 800px;
Expand Down Expand Up @@ -76,7 +77,12 @@ export const RouteWrapper = styled.div`
export const RouteTopContainer = styled.div`
display: flex;
align-items: center;
margin-bottom: 60px;
flex-wrap: wrap;
`;

export const TitleWrapper = styled.div`
display: flex;
align-items: center;
`;

export const RouteIconWrapper = styled.div`
Expand All @@ -86,5 +92,5 @@ export const RouteIconWrapper = styled.div`
`;

export const BackButtonWrapper = styled.div`
margin-right: 70px;
margin-right: 50px;
`;
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
RouteTopContainer,
RouteWrapper,
Title,
TitleWrapper,
} from './AdminDashboard.styled';
import { AdminRoute } from './AdminDashboard.typed';

Expand Down Expand Up @@ -108,8 +109,10 @@ const AdminDashboard = () => {
<BackButtonWrapper>
<BackButton />
</BackButtonWrapper>
<h1>{t(title as never)}</h1>
<RouteIconWrapper>{icon}</RouteIconWrapper>
<TitleWrapper>
<h2>{t(title as never)}</h2>
<RouteIconWrapper>{icon}</RouteIconWrapper>
</TitleWrapper>
</RouteTopContainer>
<Component {...routeProps} />
</RouteWrapper>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,7 @@ export const Wrapper = styled.div`
height: 100%;
width: 100%;
`;

export const ListContainer = styled.div`
margin-top: 60px;
`;
Loading

0 comments on commit a7979b0

Please sign in to comment.