Closed sterlinghirsh closed 1 year ago
@sterlinghirsh I'd like to prioritize this. What spec(s) need to be added for @dhmacs to take over?
@jeffsnyder I think what @sterlinghirsh has written is very clear and detailed, so it's only a matter of prioritizing this over other work. Also if you're expecting me or Federico to do it it should be on the iOP backlog since we first look into that column when taking new tasks. My current focus in on getting the caching stuff merged, but I'm happy to fill in voids with this. I'll let you and Sterling assess the priority, just let me know.
@ifixitmaxb and I were chatting through the FAQ plan. Question: will we have FAQ as a manually definable section on ProductList pages? Or will we only be assigning FAQs based on what we build in Assigning ProductList and ProductDetail Segments to Many Pages https://github.com/iFixit/react-commerce/issues/1746 ?
On the one hand, I'm fine using a bulk assignment tool to assign FAQs to single ProductLists. On the other hand, it feels like the bulk assignment tool is much more work and potentially we might want to get FAQs available on ProductLists before our bulk tool is done.
@jeffsnyder I think we can do both. Right now I'm experimenting with the bulk assignment, I'm trying to implement an MVP a assess the impact on performance of these additional queries
Hey @sterlinghirsh I have a draft of this almost ready but I need to figure out this:
- Product List Filter (string?)
- A facet filter similar to an algolia filer that indicates whether we should display a certain FAQ.
- e.g. item_type="Batteries" AND part_or_kit="Fix Kit"
How complex do we want this to be? Having this be an Algolia-like filter syntax could result in a complex implementation, requiring a parser and code to compare parsed filters against user selected filters. What use cases are we looking to support? Would support for item type filter be enough? If we can narrow this a bit we could come up with a simpler implementation
I'd rather not get into a complex parsing situation, and I don't think we're going to be able to do something as complex as Algolia's filtering. The requested filters mostly break down to Device (or ancestor) and Facet (mostly Item Type). But the item type doesn't mean that the FAQ has to be just on a page filtered to that item type.
For example, one requested scope is Laptop Batteries. I take this to mean it should display on any ProductList with:
So MacBook Parts would include the Laptop Batteries FAQ since MacBook is under Mac Laptop and some of the parts are Batteries.
The facet filter is the hardest to implement since it depends on inspecting the Algolia result, but I think we can make this work smoothly if these conditions are matched against the returned facets. I think we can query Strapi for a larger set of FAQs (hopefully not all of them, but we'll see) and then whittle them down after we get the Algolia result. So for Batteries, we'd get the result, then check the facet result for facet_tags.Item Type
includes Batteries.
There are some other requested filters like ProductLists with Kits. These can similarly be implemented by inspecting the facets (facet_tags.Part or Kit
). So then the question is how do we specify the filter? One option is to accept a json string with a hash of facets to a value or an array of values:
{
"facet_tags.Item Type": ["Batteries", "Screens"],
"facet_tags.Part or Kit": "Fix Kit"
}
I think this would work with a minimum of dev effort but is probably too complex to expect ProductList editors to get right.
Another option is to use an off-the-shelf expression parser. I found this one: https://github.com/NimitzDEV/logical-expression-parser which looks fairly minimal but could work. I haven't spent too much time looking so there are probably better options out there, but this might do it. The syntax is extremely simple, consisting of just |&!()
. Here's the example from the site:
const LEP = require('logical-expression-parser');
const REQUIREMENTS = 'REGISTED&(SPECIAL|INVITED)';
const LIST_A = ['REGISTED', 'INVITED'];
const LIST_B = ['SPECIAL', 'EXPERT'];
const RESULT_A = LEP.parse(REQUIREMENTS, t => LIST_A.indexOf(t) > -1);
const RESULT_B = LEP.parse(REQUIREMENTS, t => LIST_B.indexOf(t) > -1);
// RESULT_A: true
// RESULT_B: false
So in our case, we'd use requirements like:
(facet_tags.Item Type=Batteries|facet_tags.Item Type=Screens)&facet_tags.Part or Kit=Fix Kit
Our evaluator function would accept an argument like facet_tags.Item Type=Batteries
, split on the =
, then use the left half to look up the facet with that name and check if the resulting list contains the value in the right half.
This is still a little more complex than I'd like, and it would be nice if we could use the same type of expression like Algolia allows with whitespace, quotes, and spelled out "AND/OR". I found this algolia filter validator https://github.com/algolia/algolia-filters-js-syntax-validator but it doesn't seem to be able to evaluate an expression as far as I could see, just parse and validate the syntax.
If we're ok with limiting ourselves a little more, we could drop support for nested expressions and have a facet on each line with a list of possible values like:
facet_tags.Item Type: Batteries, Screens
facet_tags.Part or Kit: Fix Kit
One downside to this is that we've started using some Item Types that include commas, so we'd probably have to pick some other character to separate them. Let me know what you think and if you have any other ideas.
I'm gonna close this since the first implementation is shipped. We can track new feature requests separately
We want to add an FAQ section on product lists, but we don't want to have to make thousands of copies of the same questions and answers. We'd like to do this in a way that allows us to use inheritance to reuse the same FAQs down the collection tree.
Examples: https://docs.google.com/spreadsheets/d/1gJiMZnz6pmzzlItFBGM-YJSWIJRNJ7QgpI0XXvdeQFk/edit#gid=0