@servicetitan/mpa-components 1.10.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/lib/components/brands/brand-card/actions-button-section.d.ts +6 -0
  3. package/lib/components/brands/brand-card/actions-button-section.d.ts.map +1 -0
  4. package/lib/components/brands/brand-card/actions-button-section.js +26 -0
  5. package/lib/components/brands/brand-card/actions-button-section.js.map +1 -0
  6. package/lib/components/brands/brand-card/brand-card.d.ts +4 -0
  7. package/lib/components/brands/brand-card/brand-card.d.ts.map +1 -0
  8. package/lib/components/brands/brand-card/brand-card.js +16 -0
  9. package/lib/components/brands/brand-card/brand-card.js.map +1 -0
  10. package/lib/components/brands/brand-card/brand-logo.d.ts +6 -0
  11. package/lib/components/brands/brand-card/brand-logo.d.ts.map +1 -0
  12. package/lib/components/brands/brand-card/brand-logo.js +8 -0
  13. package/lib/components/brands/brand-card/brand-logo.js.map +1 -0
  14. package/lib/components/brands/brand-card/cart-tags.d.ts +6 -0
  15. package/lib/components/brands/brand-card/cart-tags.d.ts.map +1 -0
  16. package/lib/components/brands/brand-card/cart-tags.js +10 -0
  17. package/lib/components/brands/brand-card/cart-tags.js.map +1 -0
  18. package/lib/components/brands/brand-card/name-and-mail-section.d.ts +7 -0
  19. package/lib/components/brands/brand-card/name-and-mail-section.d.ts.map +1 -0
  20. package/lib/components/brands/brand-card/name-and-mail-section.js +7 -0
  21. package/lib/components/brands/brand-card/name-and-mail-section.js.map +1 -0
  22. package/lib/components/brands/brand-card/single-action-button.d.ts +6 -0
  23. package/lib/components/brands/brand-card/single-action-button.d.ts.map +1 -0
  24. package/lib/components/brands/brand-card/single-action-button.js +34 -0
  25. package/lib/components/brands/brand-card/single-action-button.js.map +1 -0
  26. package/lib/components/brands/cards-grid/cards-grid.d.ts +7 -0
  27. package/lib/components/brands/cards-grid/cards-grid.d.ts.map +1 -0
  28. package/lib/components/brands/cards-grid/cards-grid.js +7 -0
  29. package/lib/components/brands/cards-grid/cards-grid.js.map +1 -0
  30. package/lib/components/brands/index.d.ts +2 -0
  31. package/lib/components/brands/index.d.ts.map +1 -0
  32. package/lib/components/brands/index.js +2 -0
  33. package/lib/components/brands/index.js.map +1 -0
  34. package/lib/components/brands/styles.module.less +59 -0
  35. package/lib/enums/brands.d.ts +6 -0
  36. package/lib/enums/brands.d.ts.map +1 -0
  37. package/lib/enums/brands.js +7 -0
  38. package/lib/enums/brands.js.map +1 -0
  39. package/lib/index.d.ts +3 -0
  40. package/lib/index.d.ts.map +1 -1
  41. package/lib/index.js +3 -0
  42. package/lib/index.js.map +1 -1
  43. package/lib/utils/interfaces.d.ts +22 -0
  44. package/lib/utils/interfaces.d.ts.map +1 -0
  45. package/lib/utils/interfaces.js +2 -0
  46. package/lib/utils/interfaces.js.map +1 -0
  47. package/lib/utils/mappers.d.ts +4 -0
  48. package/lib/utils/mappers.d.ts.map +1 -0
  49. package/lib/utils/mappers.js +13 -0
  50. package/lib/utils/mappers.js.map +1 -0
  51. package/package.json +15 -11
  52. package/src/components/brands/brand-card/actions-button-section.tsx +62 -0
  53. package/src/components/brands/brand-card/brand-card.tsx +55 -0
  54. package/src/components/brands/brand-card/brand-logo.tsx +21 -0
  55. package/src/components/brands/brand-card/cart-tags.tsx +20 -0
  56. package/src/components/brands/brand-card/name-and-mail-section.tsx +28 -0
  57. package/src/components/brands/brand-card/single-action-button.tsx +84 -0
  58. package/src/components/brands/cards-grid/cards-grid.tsx +20 -0
  59. package/src/components/brands/index.ts +1 -0
  60. package/src/components/brands/styles.module.less +59 -0
  61. package/src/components/brands/styles.module.less.d.ts +10 -0
  62. package/src/enums/brands.ts +5 -0
  63. package/src/index.ts +3 -1
  64. package/src/utils/interfaces.ts +23 -0
  65. package/src/utils/mappers.ts +14 -0
  66. package/tsconfig.tsbuildinfo +1 -1
@@ -0,0 +1,55 @@
1
+ import { FC } from 'react';
2
+ import classNames from 'classnames';
3
+
4
+ import { Flex, Card } from '@servicetitan/anvil2';
5
+
6
+ import { NameAndMailSection } from './name-and-mail-section';
7
+ import { BrandCardProps } from '../../../utils/interfaces';
8
+ import { ActionsButtonSection } from './actions-button-section';
9
+ import { CardTags } from './cart-tags';
10
+ import { BrandLogo } from './brand-logo';
11
+
12
+ import * as Styles from '../styles.module.less';
13
+
14
+ const BRAND_NAME_PLACEHOLDER = 'Assign Brand Name';
15
+
16
+ export const BrandCard: FC<BrandCardProps> = ({
17
+ actions,
18
+ email,
19
+ isDefault,
20
+ isShared,
21
+ logo,
22
+ name,
23
+ hasError,
24
+ }) => {
25
+ const nameToShow = name || BRAND_NAME_PLACEHOLDER;
26
+
27
+ return (
28
+ <Card
29
+ className={classNames(
30
+ {
31
+ [Styles.cardWithError]: hasError,
32
+ },
33
+ Styles.brandCard,
34
+ 'qa-brand-card',
35
+ )}
36
+ padding="large"
37
+ >
38
+ <Flex className={Styles.cardContent} justifyContent="space-between" direction="column">
39
+ <Flex
40
+ justifyContent="space-between"
41
+ alignItems="flex-start"
42
+ className="qa-brand-card-left-section"
43
+ >
44
+ <BrandLogo logo={logo} alt={nameToShow} />
45
+ <ActionsButtonSection actions={actions} />
46
+ </Flex>
47
+
48
+ <Flex justifyContent="space-between">
49
+ <NameAndMailSection name={name} nameToShow={nameToShow} email={email} />
50
+ <CardTags isDefault={isDefault} isShared={isShared} />
51
+ </Flex>
52
+ </Flex>
53
+ </Card>
54
+ );
55
+ };
@@ -0,0 +1,21 @@
1
+ import { FC } from 'react';
2
+ import classNames from 'classnames';
3
+
4
+ import { Flex, Icon } from '@servicetitan/anvil2';
5
+ import ImageIcon from '@servicetitan/anvil2/assets/icons/material/round/image.svg';
6
+ import { tokens } from '@servicetitan/tokens/core/index';
7
+
8
+ import * as Styles from '../styles.module.less';
9
+
10
+ export const BrandLogo: FC<{ logo?: string; alt?: string }> = ({ logo, alt }) =>
11
+ logo ? (
12
+ <img className={classNames(Styles.brandImg, 'qa-brand-logo')} src={logo} alt={alt} />
13
+ ) : (
14
+ <Flex
15
+ className={classNames(Styles.brandImgPlaceholder, 'qa-brand-logo-placeholder')}
16
+ alignItems="center"
17
+ justifyContent="center"
18
+ >
19
+ <Icon svg={ImageIcon} size="large" color={tokens.colorNeutral90} />
20
+ </Flex>
21
+ );
@@ -0,0 +1,20 @@
1
+ import { FC } from 'react';
2
+
3
+ import { Chip, Flex } from '@servicetitan/anvil2';
4
+ import { tokens } from '@servicetitan/tokens/core/index';
5
+
6
+ export const CardTags: FC<{ isDefault?: boolean; isShared?: boolean }> = ({
7
+ isDefault,
8
+ isShared,
9
+ }) => {
10
+ if (!isDefault && !isShared) {
11
+ return null;
12
+ }
13
+
14
+ return (
15
+ <Flex direction="column" alignItems="flex-end" className="qa-brand-card-tags" gap="1">
16
+ {isShared && <Chip color={tokens.colorPurple100} label="Corporate HQ" size="small" />}
17
+ {isDefault && <Chip label="Default" color={tokens.colorNeutral50} size="small" />}
18
+ </Flex>
19
+ );
20
+ };
@@ -0,0 +1,28 @@
1
+ import { FC } from 'react';
2
+ import classNames from 'classnames';
3
+
4
+ import { BodyText, Headline } from '@servicetitan/design-system';
5
+ import { Flex } from '@servicetitan/anvil2';
6
+
7
+ import * as Styles from '../styles.module.less';
8
+
9
+ export const NameAndMailSection: FC<{ name?: string; nameToShow: string; email?: string }> = ({
10
+ name,
11
+ email,
12
+ nameToShow,
13
+ }) => (
14
+ <Flex
15
+ justifyContent="space-between"
16
+ direction="column"
17
+ className={classNames(Styles.cardLeftSectionTexts, 'qa-brand-card-name-and-mail')}
18
+ >
19
+ <Headline el="p" subdued={!name} className="t-truncate-i m-0" title={nameToShow}>
20
+ {nameToShow}
21
+ </Headline>
22
+ {email && (
23
+ <BodyText subdued title={email} className="t-truncate-i">
24
+ {email}
25
+ </BodyText>
26
+ )}
27
+ </Flex>
28
+ );
@@ -0,0 +1,84 @@
1
+ import { FC, PropsWithChildren } from 'react';
2
+ import { useHistory } from 'react-router-dom';
3
+
4
+ import HelpIcon from '@servicetitan/anvil2/assets/icons/material/round/help.svg';
5
+ import { Chip, Flex, Tooltip as TooltipA2, Button } from '@servicetitan/anvil2';
6
+ import { ButtonAppearance } from '@servicetitan/hammer-react/dist/types/props';
7
+
8
+ import { BrandAction } from '../../../utils/interfaces';
9
+ import { BrandActionChipColor, BrandActionChipLabel } from '../../../utils/mappers';
10
+ import { ActionStatus } from '../../../enums/brands';
11
+
12
+ export const SingleActionButtonSection: FC<{
13
+ action: BrandAction;
14
+ }> = ({ action }) => {
15
+ const history = useHistory();
16
+ const handleClick = () => {
17
+ if (action.action) {
18
+ action.action();
19
+ }
20
+
21
+ if (action.href) {
22
+ history.push(action.href);
23
+ }
24
+ };
25
+
26
+ let buttonAppearance: ButtonAppearance | undefined;
27
+ if (action.status === undefined) {
28
+ buttonAppearance = 'primary';
29
+ } else if (!action.disabled) {
30
+ buttonAppearance = 'secondary';
31
+ }
32
+
33
+ return (
34
+ <Flex gap="2" alignItems="center" className="qa-brand-card-single-action">
35
+ <ActionChip status={action.status} statusTooltip={action.statusTooltip} />
36
+ <Button
37
+ size="small"
38
+ onClick={handleClick}
39
+ disabled={action.disabled}
40
+ appearance={buttonAppearance}
41
+ >
42
+ {action.name}
43
+ </Button>
44
+ {action.disabled && (
45
+ <DisabledActionHelper>{action.disableTooltipContent?.()}</DisabledActionHelper>
46
+ )}
47
+ </Flex>
48
+ );
49
+ };
50
+
51
+ const ActionChip: FC<{ status?: ActionStatus; statusTooltip?: string }> = ({
52
+ status,
53
+ statusTooltip,
54
+ }) => {
55
+ if (status === undefined) {
56
+ return null;
57
+ }
58
+
59
+ const chip = (
60
+ <Chip
61
+ label={BrandActionChipLabel[status]}
62
+ color={BrandActionChipColor[status]}
63
+ size="small"
64
+ />
65
+ );
66
+
67
+ return statusTooltip ? (
68
+ <TooltipA2>
69
+ <TooltipA2.Trigger>{chip}</TooltipA2.Trigger>
70
+ <TooltipA2.Content>{statusTooltip}</TooltipA2.Content>
71
+ </TooltipA2>
72
+ ) : (
73
+ chip
74
+ );
75
+ };
76
+
77
+ const DisabledActionHelper: FC<PropsWithChildren> = ({ children }) => (
78
+ <TooltipA2>
79
+ <TooltipA2.Trigger>
80
+ <Button icon={HelpIcon} size="small" />
81
+ </TooltipA2.Trigger>
82
+ <TooltipA2.Content>{children}</TooltipA2.Content>
83
+ </TooltipA2>
84
+ );
@@ -0,0 +1,20 @@
1
+ import { FC } from 'react';
2
+ import classNames from 'classnames';
3
+
4
+ import { Grid } from '@servicetitan/anvil2';
5
+
6
+ import { BrandCard } from '../brand-card/brand-card';
7
+ import { BrandCardProps } from '../../../utils/interfaces';
8
+
9
+ import * as Styles from '../styles.module.less';
10
+
11
+ export const CardsGrid: FC<{
12
+ brands: BrandCardProps[];
13
+ qaIdentifier: string;
14
+ }> = ({ brands, qaIdentifier }) => (
15
+ <Grid className={classNames(Styles.grid, `qa-${qaIdentifier}-cards-grid`)} gap="6">
16
+ {brands.map(brand => (
17
+ <BrandCard key={brand.id} {...brand} />
18
+ ))}
19
+ </Grid>
20
+ );
@@ -0,0 +1 @@
1
+ export * from './cards-grid/cards-grid';
@@ -0,0 +1,59 @@
1
+ @import (reference) '@servicetitan/tokens/dist/tokens.less';
2
+
3
+ @action-menu-item-padding: 12px;
4
+ @card-min-width: 330px;
5
+ @card-max-width: 700px;
6
+ @max-number-of-cards: 3;
7
+
8
+ .delete-tooltip {
9
+ min-width: 327px;
10
+ }
11
+
12
+ .grid {
13
+ grid-template-columns: repeat(auto-fill, minmax(@card-min-width, 1fr));
14
+ max-width: calc(@card-max-width * @max-number-of-cards + @spacing-3 * 2);
15
+ }
16
+
17
+ @media (min-width: 1120px) {
18
+ .grid {
19
+ grid-template-columns: repeat(@max-number-of-cards - 1, 1fr);
20
+ }
21
+ }
22
+
23
+ @media (min-width: 1620px) {
24
+ .grid {
25
+ grid-template-columns: repeat(@max-number-of-cards, 1fr);
26
+ }
27
+ }
28
+
29
+ .brand-card {
30
+ height: 200px;
31
+ min-width: @card-min-width;
32
+ max-width: @card-max-width;
33
+ }
34
+
35
+ .card-content {
36
+ width: 100%;
37
+ }
38
+
39
+ .card-left-section-texts {
40
+ min-width: 0;
41
+ }
42
+
43
+ .brand-img {
44
+ width: @spacing-6;
45
+ height: @spacing-6;
46
+ min-width: @spacing-6;
47
+ min-height: @spacing-6;
48
+ border-radius: @border-radius-circular;
49
+ border: solid 1px @color-neutral-60;
50
+ }
51
+
52
+ .brand-img-placeholder {
53
+ .brand-img();
54
+ background-color: @color-neutral-60;
55
+ }
56
+
57
+ .card-with-error {
58
+ border-color: @color-red-500;
59
+ }
@@ -0,0 +1,10 @@
1
+ export const __esModule: true;
2
+ export const brandCard: string;
3
+ export const brandImg: string;
4
+ export const brandImgPlaceholder: string;
5
+ export const cardContent: string;
6
+ export const cardLeftSectionTexts: string;
7
+ export const cardWithError: string;
8
+ export const deleteTooltip: string;
9
+ export const grid: string;
10
+
@@ -0,0 +1,5 @@
1
+ export enum ActionStatus {
2
+ Error,
3
+ Pending,
4
+ Approved,
5
+ }
package/src/index.ts CHANGED
@@ -1,4 +1,6 @@
1
1
  export * from './components/settings';
2
2
  export * from './components/campaign-actions';
3
-
3
+ export * from './components/settings';
4
4
  export * from './utils/helpers';
5
+ export * from './utils/interfaces';
6
+ export * from './enums/brands';
@@ -0,0 +1,23 @@
1
+ import { JSX } from 'react';
2
+ import { ActionStatus } from '../enums/brands';
3
+
4
+ export interface BrandAction {
5
+ name: string;
6
+ disabled?: boolean;
7
+ disableTooltipContent?: () => JSX.Element | string;
8
+ href?: string;
9
+ status?: ActionStatus;
10
+ statusTooltip?: string;
11
+ action?: () => void;
12
+ }
13
+
14
+ export interface BrandCardProps {
15
+ id: string;
16
+ hasError?: boolean;
17
+ actions: BrandAction | BrandAction[];
18
+ logo?: string;
19
+ name?: string;
20
+ isDefault: boolean;
21
+ email?: string;
22
+ isShared?: boolean;
23
+ }
@@ -0,0 +1,14 @@
1
+ import { ActionStatus } from '../enums/brands';
2
+ import { tokens } from '@servicetitan/tokens/core';
3
+
4
+ export const BrandActionChipLabel: Record<ActionStatus, string> = {
5
+ [ActionStatus.Pending]: 'Pending',
6
+ [ActionStatus.Error]: 'Error',
7
+ [ActionStatus.Approved]: 'Complete',
8
+ };
9
+
10
+ export const BrandActionChipColor: Record<ActionStatus, string> = {
11
+ [ActionStatus.Pending]: tokens.colorOrange200,
12
+ [ActionStatus.Error]: tokens.colorRed500,
13
+ [ActionStatus.Approved]: tokens.colorGreen200,
14
+ };