Skip to content

Commit

Permalink
feat: make SkuPicker search placeholder and help text configurable [I…
Browse files Browse the repository at this point in the history
…NTEG-2017] (#7337)

* feat: add function to create placeholder text

* feat: add function help text and update styles

* chore: update SkuPicker tests and docs

* chore: update function type
  • Loading branch information
whitelisab committed Apr 19, 2024
1 parent ed8cfdd commit 460be1b
Show file tree
Hide file tree
Showing 6 changed files with 147 additions and 16 deletions.
46 changes: 46 additions & 0 deletions packages/ecommerce-app-base/docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
- [Integration](README.md#integration)
- [MakeCTAFn](README.md#makectafn)
- [MakeSaveBtnTextFn](README.md#makesavebtntextfn)
- [MakeSearchHelpText](README.md#makesearchhelptext)
- [MakeSearchPlaceholderText](README.md#makesearchplaceholdertext)
- [OpenDialogFn](README.md#opendialogfn)
- [Pagination](README.md#pagination)
- [ParameterDefinition](README.md#parameterdefinition)
Expand Down Expand Up @@ -214,6 +216,50 @@ Text that should be displayed on the button

___

### MakeSearchHelpText

Ƭ **MakeSearchHelpText**: (`skuType?`: `string`) => `string`

Returns the text that is used as the help text for the SkuPicker search.

#### Type declaration

▸ (`skuType?`): `string`

##### Parameters

| Name | Type | Description |
| :--------- | :------- | :------------------------------------------------------------------------------------------ |
| `skuType?` | `string` | SKU type of the current field. Undefined if only a single SKU type is supported by the app. |

##### Returns

`string`

---

### MakeSearchPlaceholderText

Ƭ **MakeSearchPlaceholderText**: (`skuType?`: `string`) => `string`

Returns the text that is used as the placeholder for the SkuPicker search.

#### Type declaration

▸ (`skuType?`): `string`

##### Parameters

| Name | Type | Description |
| :--------- | :------- | :------------------------------------------------------------------------------------------ |
| `skuType?` | `string` | SKU type of the current field. Undefined if only a single SKU type is supported by the app. |

##### Returns

`string`

---

### OpenDialogFn

Ƭ **OpenDialogFn**: (`sdk`: `FieldAppSDK`, `currentValue`: `string`[] \| `string`, `config`: [`Config`](README.md#config)) => `Promise`<`string`[]\>
Expand Down
18 changes: 18 additions & 0 deletions packages/ecommerce-app-base/src/SkuPicker/SkuPicker.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,24 @@ describe('SkuPicker', () => {
expect(getByTestId('search-by-sku')).toBeInTheDocument();
});

it('should render custom placeholder text in search box when makeSearchPlaceholderText exists', async () => {
const makeSearchPlaceholderText = jest.fn(() => 'My custom placeholder text');
const { getByPlaceholderText } = await renderComponent({
...defaultProps,
makeSearchPlaceholderText,
});
expect(getByPlaceholderText('My custom placeholder text')).toBeInTheDocument();
});

it('should render custom help text under search box when makeSearchHelpText exists', async () => {
const makeSearchHelpText = jest.fn(() => 'My custom help text');
const { getByText } = await renderComponent({
...defaultProps,
makeSearchHelpText,
});
expect(getByText('My custom help text')).toBeInTheDocument();
});

describe('when it has infinite scrolling mode pagination', () => {
it('should render the "Load more" text link if there is a next page', async () => {
const { findByTestId } = await renderComponent({
Expand Down
58 changes: 48 additions & 10 deletions packages/ecommerce-app-base/src/SkuPicker/SkuPicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,20 @@ import debounce from 'lodash/debounce';
import { DialogAppSDK } from '@contentful/app-sdk';
import { ProductList } from './ProductList';
import { Paginator } from './Paginator';
import { MakeSaveBtnTextFn, Pagination, Product, ProductPreviewsFn, ProductsFn } from '../types';
import {
MakeSaveBtnTextFn,
MakeSearchPlaceholderText,
MakeSearchHelpText,
Pagination,
Product,
ProductPreviewsFn,
ProductsFn,
} from '../types';
import { ProductSelectionList } from './ProductSelectionList';
import { styles } from './styles';
import { mapSort } from '../utils';

import { Button, Checkbox, Text, TextInput } from '@contentful/f36-components';
import { Button, Checkbox, Flex, Text, TextInput } from '@contentful/f36-components';

import { SearchIcon } from '@contentful/f36-icons';

Expand All @@ -21,6 +29,8 @@ export interface Props {
searchDelay?: number;
skuType?: string;
makeSaveBtnText?: MakeSaveBtnTextFn;
makeSearchPlaceholderText?: MakeSearchPlaceholderText;
makeSearchHelpText?: MakeSearchHelpText;
hideSearch?: boolean;
showSearchBySkuOption?: boolean;
}
Expand Down Expand Up @@ -48,6 +58,10 @@ function defaultGetSaveBtnText(selectedSKUs: string[]): string {
}
}

const defaultMakeSearchPlaceholderText: MakeSearchPlaceholderText = (_skuType) => {
return 'Search for a product...';
};

export class SkuPicker extends Component<Props, State> {
state: State = {
activePage: 1,
Expand Down Expand Up @@ -154,11 +168,37 @@ export class SkuPicker extends Component<Props, State> {
}
};

constructSearchAdditionalInfo = (
makeSearchHelpText: MakeSearchHelpText | undefined,
skuType: string | undefined,
paginationTotal: number
) => {
const helpText = makeSearchHelpText ? makeSearchHelpText(skuType) : '';
const totalResults = !!paginationTotal
? `${paginationTotal.toLocaleString()} total results`
: '';

if (helpText && totalResults) {
return (
<Flex justifyContent="space-between">
<Text marginRight="spacingXl" className={styles.helpText}>
{helpText}
</Text>
<Text className={styles.helpText}>{totalResults}</Text>
</Flex>
);
} else {
return <Text className={styles.helpText}>{helpText || totalResults}</Text>;
}
};

render() {
const { search, pagination, products, selectedProducts, selectedSKUs, searchBySku } =
this.state;
const {
makeSaveBtnText = defaultGetSaveBtnText,
makeSearchPlaceholderText = defaultMakeSearchPlaceholderText,
makeSearchHelpText,
skuType,
hideSearch = false,
showSearchBySkuOption,
Expand All @@ -174,16 +214,20 @@ export class SkuPicker extends Component<Props, State> {
<div className={styles.searchWrapper}>
<div className={styles.leftSideControls}>
<TextInput
placeholder="Search for a product..."
placeholder={makeSearchPlaceholderText(skuType)}
type="search"
name="sku-search"
id="sku-search"
testId="sku-search"
value={search}
onChange={(event) => this.setSearch((event.target as HTMLInputElement).value)}
/>

<SearchIcon variant="muted" />
{this.constructSearchAdditionalInfo(
makeSearchHelpText,
skuType,
pagination.total
)}
</div>

{showSearchBySkuOption && (
Expand All @@ -200,12 +244,6 @@ export class SkuPicker extends Component<Props, State> {
)}
</div>
)}

{!!pagination.total && (
<Text className={styles.total}>
{pagination.total.toLocaleString()} total results
</Text>
)}
</div>

<div className={styles.rightSideControls}>
Expand Down
14 changes: 13 additions & 1 deletion packages/ecommerce-app-base/src/SkuPicker/renderSkuPicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,13 @@ import * as React from 'react';
import { DialogAppSDK } from '@contentful/app-sdk';
import { render } from 'react-dom';
import { SkuPicker } from './SkuPicker';
import { MakeSaveBtnTextFn, ProductPreviewsFn, ProductsFn } from '../types';
import {
MakeSaveBtnTextFn,
MakeSearchPlaceholderText,
MakeSearchHelpText,
ProductPreviewsFn,
ProductsFn,
} from '../types';

interface Props<> {
sdk: DialogAppSDK;
Expand All @@ -11,6 +17,8 @@ interface Props<> {
searchDelay?: number;
skuType?: string;
makeSaveBtnText?: MakeSaveBtnTextFn;
makeSearchPlaceholderText?: MakeSearchPlaceholderText;
makeSearchHelpText?: MakeSearchHelpText;
hideSearch?: boolean;
showSearchBySkuOption?: boolean;
}
Expand All @@ -24,6 +32,8 @@ export function renderSkuPicker(
searchDelay,
skuType,
makeSaveBtnText,
makeSearchPlaceholderText,
makeSearchHelpText,
hideSearch,
showSearchBySkuOption,
}: Props
Expand All @@ -38,6 +48,8 @@ export function renderSkuPicker(
searchDelay={searchDelay}
skuType={skuType}
makeSaveBtnText={makeSaveBtnText}
makeSearchPlaceholderText={makeSearchPlaceholderText}
makeSearchHelpText={makeSearchHelpText}
hideSearch={hideSearch}
showSearchBySkuOption={showSearchBySkuOption}
/>,
Expand Down
11 changes: 6 additions & 5 deletions packages/ecommerce-app-base/src/SkuPicker/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,10 @@ export const styles = {
},
}),
body: makeBodyStyle(),
total: css({
fontSize: tokens.fontSizeS,
color: tokens.gray600,
helpText: css({
color: tokens.gray500,
display: 'block',
marginTop: tokens.spacingS,
marginTop: tokens.spacingXs,
}),
saveBtn: css({
marginRight: tokens.spacingM,
Expand All @@ -55,6 +54,7 @@ export const styles = {
leftSideControls: css({
position: 'relative',
zIndex: 0,
minWidth: '320px',
svg: css({
zIndex: 1,
position: 'absolute',
Expand All @@ -80,7 +80,8 @@ export const styles = {
}),
skuSearch: css({
display: 'flex',
alignItems: 'center',
alignSelf: 'flex-start',
marginTop: tokens.spacingXs,
marginLeft: tokens.spacingM,
marginRight: tokens.spacingXs,
}),
Expand Down
16 changes: 16 additions & 0 deletions packages/ecommerce-app-base/src/types/ui.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,22 @@ export type MakeCTAFn = (fieldType: string, skuType?: string) => string;
*/
export type MakeSaveBtnTextFn = (selectedSKUs: string[], skuType?: string) => string;

/**
* Returns the text that is used as the placeholder for the SkuPicker search.
*
* @param skuType SKU type of the current field. Undefined if only a single SKU type is supported by the app.
* @returns Text that should be displayed as the placeholder
*/
export type MakeSearchPlaceholderText = (skuType?: string) => string;

/**
* Returns the text that is used as the help text for the SkuPicker search.
*
* @param skuType SKU type of the current field. Undefined if only a single SKU type is supported by the app.
* @returns Text that should be displayed as the help text
*/
export type MakeSearchHelpText = (skuType?: string) => string;

/**
* Custom code that validates installation parameters that is run before saving.
*
Expand Down

0 comments on commit 460be1b

Please sign in to comment.