Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
import { useEffect, useMemo, useRef, useState } from 'react'
import { Input, IconButton, Icon, Loader } from '@faststore/ui'
import type { SelectedFacet } from 'src/sdk/search/useMyAccountFilter'
import useShopperSuggestions from 'src/sdk/account/useShopperSuggestions'
import type { Shopper } from 'src/sdk/account/useShopperSuggestions'

export interface MyAccountFilterFacetPlacedByProps {
/**
* Current selected facets from filter context
*/
selected: SelectedFacet[]
/**
* Dispatch from filter context
*/
dispatch: (action: { type: 'toggleFacet' | 'setFacet'; payload: any }) => void
}

function MyAccountFilterFacetPlacedBy({
selected,
dispatch,
}: MyAccountFilterFacetPlacedByProps) {
const inputRef = useRef<HTMLInputElement>(null)
const [query, setQuery] = useState('')
const [selectedShopper, setSelectedShopper] = useState<Shopper | null>(null)
const [isOpen, setIsOpen] = useState(false)

// Use the new hook for shoppers suggestions
const { data, isLoading, findShopperById } = useShopperSuggestions(query)

// Get the filtered shoppers from hook data
const filteredShoppers = data?.shoppers || []

const selectedId = useMemo(
() => selected.find((f) => f.key === 'purchaseAgentId')?.value,
[selected]
)
Comment on lines +33 to +36
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just 1 so far, after we can select multiple.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, i have done as in the figma for now


const clearAll = () => {
setQuery('')
setSelectedShopper(null)
if (inputRef.current) inputRef.current.value = ''
}

useEffect(() => {
if (selectedId && !selectedShopper) {
const found = findShopperById(selectedId)
if (found) setSelectedShopper(found)
} else if (!selectedId) {
clearAll()
}
}, [selectedId, selectedShopper])

function handleSearchOnChange(value: string) {
setQuery(value)
setIsOpen(true)
}

const isSearchEmpty = useMemo(
() => !isLoading && query && filteredShoppers.length === 0,
[isLoading, query, filteredShoppers]
)

function handleSelect(shopper: Shopper) {
setSelectedShopper(shopper)
setIsOpen(false)
dispatch({
type: 'setFacet',
payload: {
facet: { key: 'purchaseAgentId', value: shopper.purchase_agent_id },
unique: true,
},
})
}

function handleClearTag() {
if (selectedShopper) {
// Using toggleFacet here removes the purchaseAgentId from selected facets
// because toggleFacet will remove the facet if it already exists in the selected facets
dispatch({
type: 'toggleFacet',
payload: {
key: 'purchaseAgentId',
value: selectedShopper.purchase_agent_id,
},
})
}
clearAll()
}

return (
<div data-fs-list-orders-filters-placed-by>
<div data-fs-list-orders-filters-placed-by-input>
<Input
id="placed-by-input"
placeholder="Enter the shopper's name..."
ref={inputRef}
value={selectedShopper ? selectedShopper.name : query}
readOnly={Boolean(selectedShopper)}
onFocus={() => {
if (!selectedShopper) setIsOpen(true)
}}
onChange={(e) => {
if (selectedShopper) return
handleSearchOnChange(e.target.value)
}}
onBlur={() => {
// delay close to allow click selection
setTimeout(() => {
setIsOpen(false)
if (!selectedShopper) {
setQuery('')
if (inputRef.current) inputRef.current.value = ''
}
}, 100)
}}
type="text"
inputMode="text"
/>
{isLoading && (
<div data-fs-list-orders-filters-placed-by-loader>
<Loader />
</div>
)}
{selectedShopper && (
<IconButton
size="small"
aria-label="Clear shopper"
data-fs-list-orders-filters-placed-by-clear
icon={<Icon name="X" />}
onClick={handleClearTag}
/>
)}
</div>

{isOpen && isSearchEmpty && (
<div
data-fs-list-orders-filters-placed-by-dropdown
data-fs-list-orders-filters-placed-by-empty
aria-label="No shoppers found with query"
>
<p>No shoppers found with "{query}"</p>
</div>
)}

{isOpen && filteredShoppers.length > 0 && (
<div
data-fs-list-orders-filters-placed-by-dropdown
aria-label="Shopper selection dropdown"
>
<ul>
{filteredShoppers.map((s) => (
<li key={s.purchase_agent_id}>
<button
type="button"
onMouseDown={(e) => e.preventDefault()}
onClick={() => handleSelect(s)}
data-fs-list-orders-filters-placed-by-option
>
<span data-fs-list-orders-filters-placed-by-option-name>
{s.name}
</span>
</button>
</li>
))}
</ul>
</div>
)}
</div>
)
}

export default MyAccountFilterFacetPlacedBy
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { default } from './MyAccountFilterFacetPlacedBy'
export type { MyAccountFilterFacetPlacedByProps } from './MyAccountFilterFacetPlacedBy'
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
[data-fs-list-orders-filters-placed-by] {
--fs-list-orders-filters-placed-by-dropdown-bkg : var(--fs-color-neutral-0);
--fs-list-orders-filters-placed-by-dropdown-border : 1px solid var(--fs-border-color-light);
--fs-list-orders-filters-placed-by-dropdown-radius : var(--fs-border-radius);
--fs-list-orders-filters-placed-by-option-padding : var(--fs-spacing-2) var(--fs-spacing-3);
--fs-list-orders-filters-placed-by-selected-height : var(--fs-control-height);
--fs-list-orders-filters-placed-by-selected-padding : 0 var(--fs-spacing-3);
--fs-list-orders-filters-placed-by-selected-border : var(--fs-input-border-width) solid var(--fs-input-border-color);
--fs-list-orders-filters-placed-by-selected-radius : var(--fs-input-border-radius);
--fs-list-orders-filters-placed-by-empty-text-color : var(--fs-color-text-light);
--fs-list-orders-filters-placed-by-loader-size : 1.25rem;
--fs-list-orders-filters-placed-by-dropdown-shadow : 0 2px 8px rgb(0 0 0 / 10%);

position: relative;

// Clear icon inside input when actionable
[data-fs-list-orders-filters-placed-by-input] {
position: relative;

[data-fs-input] {
width: 100%;
}

[data-fs-icon-button] {
position: absolute;
top: 50%;
right: var(--fs-spacing-2);
transform: translateY(-50%);
}

[data-fs-list-orders-filters-placed-by-loader] {
position: absolute;
top: 50%;
right: var(--fs-spacing-2);
display: flex;
align-items: center;
justify-content: center;
transform: translateY(-50%);

[data-fs-loader] {
width: var(--fs-list-orders-filters-placed-by-loader-size);
height: var(--fs-list-orders-filters-placed-by-loader-size);
}
}
}

[data-fs-list-orders-filters-placed-by-dropdown] {
position: absolute;
z-index: 10;
width: 100%;
margin-top: var(--fs-spacing-1);
background: var(--fs-list-orders-filters-placed-by-dropdown-bkg);
border: var(--fs-list-orders-filters-placed-by-dropdown-border);
border-radius: var(--fs-list-orders-filters-placed-by-dropdown-radius);
box-shadow: var(--fs-list-orders-filters-placed-by-dropdown-shadow);

&[data-fs-list-orders-filters-placed-by-empty] {
padding: var(--fs-spacing-3);

p {
margin: 0;
font-size: var(--fs-text-size-body);
font-style: italic;
color: var(--fs-list-orders-filters-placed-by-empty-text-color);
text-align: center;
}
}

ul {
max-height: 220px;
padding: 0;
margin: 0;
overflow: auto;
list-style: none;
}

[data-fs-list-orders-filters-placed-by-option] {
display: flex;
justify-content: flex-start;
width: 100%;
padding: var(--fs-list-orders-filters-placed-by-option-padding);
text-align: left;
cursor: pointer;
background: transparent;
border: 0;

&:hover, &:focus {
background: var(--fs-color-neutral-bkg);
}

[data-fs-list-orders-filters-placed-by-option-name] {
font-weight: var(--fs-text-weight-regular);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import type {
useMyAccountFilter,
} from 'src/sdk/search/useMyAccountFilter'
import FilterFacetDateRange from './MyAccountFilterFacetDateRange'
import FilterFacetPlacedBy from './MyAccountFilterFacetPlacedBy'
import styles from './section.module.scss'

export interface FilterSliderProps {
Expand Down Expand Up @@ -91,6 +92,10 @@ function MyAccountFilterSlider({
: [value]
}

if (key === 'purchaseAgentId') {
acc['purchaseAgentId'] = value
}

return acc
},
{} as Record<string, string | string[]>
Expand Down Expand Up @@ -197,6 +202,9 @@ function MyAccountFilterSlider({
))}
</UIFilterFacetBoolean>
)}
{type === 'StoreFacetPlacedBy' && isExpanded && (
<FilterFacetPlacedBy selected={selected} dispatch={dispatch} />
)}
{type === 'StoreFacetRange' && isExpanded && (
<FilterFacetDateRange
ref={dateRangeInputRef}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
.section {
@import "@faststore/ui/src/components/atoms/Button/styles.scss";
@import "@faststore/ui/src/components/atoms/Loader/styles.scss";
@import "@faststore/ui/src/components/atoms/Badge/styles.scss";
@import "@faststore/ui/src/components/atoms/Checkbox/styles.scss";
@import "@faststore/ui/src/components/atoms/Icon/styles.scss";
Expand All @@ -16,6 +17,7 @@
@import "@faststore/ui/src/components/organisms/FilterSlider/styles.scss";
@import "@faststore/ui/src/components/organisms/SlideOver/styles.scss";
@import "./MyAccountFilterFacetDateRange/styles.scss";
@import "./MyAccountFilterFacetPlacedBy/styles.scss";

[data-fs-badge] {
display: none;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export type MyAccountListOrdersProps = {
dateFinal: string
text: string
clientEmail: string
purchaseAgentId?: string
}
}

Expand Down Expand Up @@ -73,6 +74,11 @@ function getSelectedFacets({
key: 'dateFinal',
value: String(value),
})
} else if (filter === 'purchaseAgentId' && value) {
acc.push({
key: 'purchaseAgentId',
value: String(value),
})
}

return acc
Expand All @@ -96,6 +102,11 @@ function getAllFacets({
value: status.toLowerCase(),
})),
},
{
__typename: 'StoreFacetPlacedBy',
key: 'purchaseAgentId',
label: 'Placed by',
} as any,
{
__typename: 'StoreFacetRange',
key: 'dateRange',
Expand Down Expand Up @@ -233,6 +244,7 @@ export default function MyAccountListOrders({
status: filters.status,
dateInitial: filters.dateInitial,
dateFinal: filters.dateFinal,
purchaseAgentId: filters.purchaseAgentId,
}}
onClearAll={() => {
window.location.href = '/account/orders'
Expand All @@ -247,6 +259,8 @@ export default function MyAccountListOrders({
} else if (key === 'dateInitial' || key === 'dateFinal') {
delete updatedFilters.dateInitial
delete updatedFilters.dateFinal
} else if (key === 'purchaseAgentId') {
delete updatedFilters.purchaseAgentId
} else {
delete updatedFilters[key]
}
Expand All @@ -258,6 +272,8 @@ export default function MyAccountListOrders({
} else if (key === 'dateInitial' || key === 'dateFinal') {
delete updatedFilters.dateInitial
delete updatedFilters.dateFinal
} else if (key === 'purchaseAgentId') {
delete updatedFilters.purchaseAgentId
} else {
delete updatedFilters[key]
}
Expand Down
Loading
Loading