1
0
Fork 0

Prototype search bar for the backlog

Signed-off-by: Egor Savkin <es@m-labs.hk>
This commit is contained in:
Egor Savkin 2024-02-22 17:26:07 +08:00
parent 2ba10dd2e8
commit 4bc6f6a3ee
5 changed files with 104 additions and 35 deletions

View File

@ -1,9 +1,11 @@
import React from 'react';
import {Droppable} from "@hello-pangea/dnd";
import {ProductItem} from "./ProductItem";
import {useShopStore} from "./shop_store";
// #!render_count
import {useRenderCount} from "@uidotdev/usehooks";
import {BacklogGroups} from "./BacklogGroups";
import {SearchBar} from "./SearchBar";
import {BacklogSearchResult} from "./BacklogSearchResult";
/**
* Component that renders the backlog in the aside
@ -14,43 +16,13 @@ export function Backlog() {
const data = useShopStore((state) => state.groups);
const items = useShopStore((state) => state.cards);
const onClickToggleMobileSideMenu = useShopStore((state) => state.switchSideMenu);
const isMobile = useShopStore((state) => state.isMobile);
// #!render_count
console.log("Backlog renders: ", renderCount)
const ordered_groups = data.categories.map(groupItem => ({
name: groupItem.name,
items: groupItem.itemIds.map(itemId => items[itemId])
}));
let item_index = -1;
const groups = ordered_groups.map((group, g_index) => {
return (
<div className="accordion-item" key={`${group.name}`}>
<h2 className="accordion-header">
<button className="accordion-button collapsed" type="button" data-bs-toggle="collapse"
data-bs-target={`#collapse${g_index}`} aria-expanded="true"
aria-controls={`collapse${g_index}`}>
{group.name}
</button>
</h2>
<div id={`collapse${g_index}`} className="accordion-collapse collapse" aria-labelledby="headingOne"
data-bs-parent="#accordion_categories">
<div className="accordion-body">
{group.items.map(item => {
item_index++;
return (
<ProductItem card_index={item_index} key={item.id} />
)
})}
</div>
</div>
</div>
);
}
);
return (
<Droppable
droppableId={data.id}
@ -70,9 +42,11 @@ export function Backlog() {
</div>
) : null}
<div className="accordion accordion-flush" id="accordion_categories">
{groups}
</div>
<SearchBar/>
<BacklogSearchResult/>
<BacklogGroups/>
{provided.placeholder && (
<div style={{display: 'none'}}>

View File

@ -0,0 +1,44 @@
import {ProductItem} from "./ProductItem";
import React from "react";
import {useShopStore} from "./shop_store";
export function BacklogGroups() {
const data = useShopStore((state) => state.groups);
const items = useShopStore((state) => state.cards);
const ordered_groups = data.categories.map(groupItem => ({
name: groupItem.name,
items: groupItem.itemIds.map(itemId => items[itemId])
}));
let item_index = -1;
const groups = ordered_groups.map((group, g_index) => {
return (
<div className="accordion-item" key={`${group.name}`}>
<h2 className="accordion-header">
<button className="accordion-button collapsed" type="button" data-bs-toggle="collapse"
data-bs-target={`#collapse${g_index}`} aria-expanded="true"
aria-controls={`collapse${g_index}`}>
{group.name}
</button>
</h2>
<div id={`collapse${g_index}`} className="accordion-collapse collapse" aria-labelledby="headingOne"
data-bs-parent="#accordion_categories">
<div className="accordion-body">
{group.items.map(item => {
item_index++;
return (
<ProductItem card_index={item_index} key={item.id} />
)
})}
</div>
</div>
</div>
);
}
);
return (
<div className="accordion accordion-flush" id="accordion_categories">
{groups}
</div>
)
}

View File

@ -0,0 +1,16 @@
import React from 'react';
import {useShopStore} from "./shop_store";
import {ProductItem} from "./ProductItem";
export function BacklogSearchResult() {
const cards_to_display = useShopStore((state) => state.listed_cards);
return ( <>
{cards_to_display.map((item, _) => {
return (
<ProductItem card_index={item} key={"searched_" + item} />
)
})}
</>
)
}

View File

@ -0,0 +1,19 @@
import React from 'react';
import {useShopStore} from "./shop_store";
export function SearchBar() {
const search_bar_value = useShopStore((state) => state.search_bar_value);
const updateSearchBar = useShopStore((state) => state.updateSearchBar);
return (
<div className="form-outline">
<input type="search"
id="search_bar"
className="form-control"
placeholder="Search through cards"
value={search_bar_value}
onChange={event => updateSearchBar(event.target.value)}
aria-label="Search"/>
</div>
)
}

View File

@ -29,6 +29,21 @@ const useBacklog = ((set, get) => ({
cardIndexById: card_id => get().cards_list.findIndex((element) => (card_id === element))
}));
const useSearch = ((set, get) => ({
search_index: Array.from(Object.values(shared_data.items)
.map((card, _) => (
[(card.name + " " + card.name_number + " " + card.name_codename).toLowerCase(), card.id]
))),
search_bar_value: "",
listed_cards: [],
updateSearchBar: text => set(state => ({
search_bar_value: text,
listed_cards: text.length > 0 ? Array.from(get().search_index
.filter((card, _) => card[0].includes(text.toLowerCase()))
.map(([index, card_id], _) => get().cards_list.findIndex(elem => elem === card_id))) : []
}))
}));
const useCrateModes = ((set, get) => ({
crate_modes: shared_data.crateModes,
modes_order: shared_data.crateModeOrder,
@ -569,6 +584,7 @@ const useCart = ((set, get) => ({
export const useShopStore = createWithEqualityFn((...params) => ({
...useBacklog(...params),
...useSearch(...params),
...useCrateModes(...params),
...useCart(...params),
...useSubmitForm(...params),