feat(search): add comprehensive keyword coverage and intelligent phrase matching

- Added 10+ new keyword categories (task, cluster, billing, invoice, payment, plan, usage, schedule, wordpress, writing, picture, user, ai)
- Implemented smart phrase normalization to strip filler words (how, to, what, is, etc.)
- Added duplicate prevention using Set to avoid showing same question multiple times
- Enhanced matching logic to check: direct keyword match, normalized term match, and question text match
- Supports basic stemming (plurals -> singular: tasks -> task)
- Now searches: 'how to import keywords' correctly matches 'import' in knowledge base
- Fixed duplicate keywords field in Team Management navigation item

This ensures all common search terms trigger relevant help suggestions with natural language support.
This commit is contained in:
IGNY8 VPS (Salman)
2026-01-09 16:37:34 +00:00
parent 264c720e3e
commit f04eb0a900
4 changed files with 1524 additions and 116 deletions

View File

@@ -1,4 +1,4 @@
import { useState, useRef } from "react";
import { useState, useRef, useEffect } from "react";
import PageMeta from "../../components/common/PageMeta";
import PageHeader from "../../components/common/PageHeader";
import { Accordion, AccordionItem } from "../../components/ui/accordion";
@@ -13,6 +13,7 @@ import {
GroupIcon,
HelpCircleIcon
} from "../../icons";
import { useLocation } from "react-router-dom";
interface TableOfContentsItem {
id: string;
@@ -143,7 +144,40 @@ function ModuleCard({ title, icon, color, children }: { title: string; icon: Rea
export default function Help() {
const [activeSection, setActiveSection] = useState<string | null>(null);
const [openAccordions, setOpenAccordions] = useState<Set<string>>(new Set());
const sectionRefs = useRef<Record<string, HTMLDivElement | null>>({});
const location = useLocation();
// Handle URL hash navigation and auto-expand accordions
useEffect(() => {
const hash = location.hash.replace('#', '');
if (hash) {
// Small delay to ensure DOM is ready
setTimeout(() => {
scrollToSection(hash, true);
}, 100);
}
}, [location.hash]);
const scrollToSection = (id: string, fromHash = false) => {
const element = sectionRefs.current[id];
if (element) {
// Open the accordion if the section is inside one
if (fromHash) {
setOpenAccordions(prev => new Set([...prev, id]));
}
const offset = 100;
const elementPosition = element.getBoundingClientRect().top;
const offsetPosition = elementPosition + window.pageYOffset - offset;
window.scrollTo({
top: offsetPosition,
behavior: "smooth"
});
setActiveSection(id);
}
};
const tableOfContents: TableOfContentsItem[] = [
{ id: "getting-started", title: "Getting Started", level: 1 },
@@ -177,21 +211,6 @@ export default function Help() {
{ id: "faq", title: "Frequently Asked Questions", level: 1 },
];
const scrollToSection = (id: string) => {
const element = sectionRefs.current[id];
if (element) {
const offset = 100;
const elementPosition = element.getBoundingClientRect().top;
const offsetPosition = elementPosition + window.pageYOffset - offset;
window.scrollTo({
top: offsetPosition,
behavior: "smooth"
});
setActiveSection(id);
}
};
const faqItems = [
{
question: "How do I add keywords to my workflow?",
@@ -551,8 +570,8 @@ export default function Help() {
</div>
</AccordionItem>
<AccordionItem title="Add Keywords">
<div className="space-y-4">
<AccordionItem title="Add Keywords" forceOpen={openAccordions.has('importing-keywords')}>
<div id="importing-keywords" ref={(el) => (sectionRefs.current["importing-keywords"] = el)} className="space-y-4 scroll-mt-24">
<p className="text-gray-700 dark:text-gray-300">
Browse and add keywords from our curated database organized by 100+ industry sectors.
</p>
@@ -578,8 +597,8 @@ export default function Help() {
</div>
</AccordionItem>
<AccordionItem title="Content Settings">
<div className="space-y-4">
<AccordionItem title="Content Settings" forceOpen={openAccordions.has('content-settings')}>
<div id="content-settings" ref={(el) => (sectionRefs.current["content-settings"] = el)} className="space-y-4 scroll-mt-24">
<p className="text-gray-700 dark:text-gray-300">
Configure how AI generates and publishes your content.
</p>
@@ -669,8 +688,8 @@ export default function Help() {
</h2>
<Accordion>
<AccordionItem title="Keywords Management" defaultOpen>
<div className="space-y-4">
<AccordionItem title="Keywords Management" defaultOpen forceOpen={openAccordions.has('managing-keywords')}>
<div id="managing-keywords" ref={(el) => (sectionRefs.current["managing-keywords"] = el)} className="space-y-4 scroll-mt-24">
<p className="text-gray-700 dark:text-gray-300">
Keywords are the foundation of your content strategy. Manage, filter, and organize your keywords here.
</p>
@@ -709,8 +728,8 @@ export default function Help() {
</div>
</AccordionItem>
<AccordionItem title="Keyword Clusters">
<div className="space-y-4">
<AccordionItem title="Keyword Clusters" forceOpen={openAccordions.has('keyword-clustering')}>
<div id="keyword-clustering" ref={(el) => (sectionRefs.current["keyword-clustering"] = el)} className="space-y-4 scroll-mt-24">
<p className="text-gray-700 dark:text-gray-300">
Clusters group related keywords for comprehensive content planning and topical authority building.
</p>
@@ -779,8 +798,8 @@ export default function Help() {
</h2>
<Accordion>
<AccordionItem title="Tasks Management" defaultOpen>
<div className="space-y-4">
<AccordionItem title="Tasks Management" defaultOpen forceOpen={openAccordions.has('editing-content')}>
<div id="editing-content" ref={(el) => (sectionRefs.current["editing-content"] = el)} className="space-y-4 scroll-mt-24">
<p className="text-gray-700 dark:text-gray-300">
Tasks are content ideas converted into actionable writing assignments with status tracking.
</p>
@@ -808,8 +827,8 @@ export default function Help() {
</div>
</AccordionItem>
<AccordionItem title="Content Generation">
<div className="space-y-4">
<AccordionItem title="Content Generation" forceOpen={openAccordions.has('content-generation')}>
<div id="content-generation" ref={(el) => (sectionRefs.current["content-generation"] = el)} className="space-y-4 scroll-mt-24">
<p className="text-gray-700 dark:text-gray-300">
Generate, edit, and manage your AI-created content.
</p>
@@ -858,8 +877,10 @@ export default function Help() {
</div>
</AccordionItem>
<AccordionItem title="Image Generation">
<div className="space-y-4">
<AccordionItem title="Image Generation" forceOpen={openAccordions.has('image-generation') || openAccordions.has('image-settings') || openAccordions.has('managing-images')}>
<div id="image-generation" ref={(el) => (sectionRefs.current["image-generation"] = el)} className="space-y-4 scroll-mt-24">
<div id="image-settings" ref={(el) => (sectionRefs.current["image-settings"] = el)}></div>
<div id="managing-images" ref={(el) => (sectionRefs.current["managing-images"] = el)}></div>
<p className="text-gray-700 dark:text-gray-300">
Generate AI images for your content using DALL-E 3 (premium) or Runware (basic).
</p>
@@ -892,8 +913,8 @@ export default function Help() {
</div>
</AccordionItem>
<AccordionItem title="Review & Publish">
<div className="space-y-4">
<AccordionItem title="Review & Publish" forceOpen={openAccordions.has('content-workflow')}>
<div id="content-workflow" ref={(el) => (sectionRefs.current["content-workflow"] = el)} className="space-y-4 scroll-mt-24">
<p className="text-gray-700 dark:text-gray-300">
Final review stage before publishing to WordPress.
</p>
@@ -932,6 +953,8 @@ export default function Help() {
{/* Automation Section */}
<div ref={(el) => (sectionRefs.current["automation"] = el)} className="mb-12 scroll-mt-24">
<div id="automation-setup" ref={(el) => (sectionRefs.current["automation-setup"] = el)}></div>
<div id="auto-publishing" ref={(el) => (sectionRefs.current["auto-publishing"] = el)}></div>
<h2 className="text-3xl font-bold text-gray-900 dark:text-white mb-6 flex items-center gap-3">
<BoltIcon className="size-8 text-warning-600 dark:text-warning-400" />
Automation Pipeline
@@ -1022,8 +1045,9 @@ export default function Help() {
</h2>
<Accordion>
<AccordionItem title="WordPress Integration" defaultOpen>
<div className="space-y-4">
<AccordionItem title="WordPress Integration" defaultOpen forceOpen={openAccordions.has('publishing-wordpress') || openAccordions.has('wordpress-integration')}>
<div id="publishing-wordpress" ref={(el) => (sectionRefs.current["publishing-wordpress"] = el)} className="space-y-4 scroll-mt-24">
<div id="wordpress-integration" ref={(el) => (sectionRefs.current["wordpress-integration"] = el)}></div>
<p className="text-gray-700 dark:text-gray-300">
Connect your WordPress site for seamless content publishing.
</p>
@@ -1063,8 +1087,9 @@ export default function Help() {
</div>
</AccordionItem>
<AccordionItem title="AI Providers">
<div className="space-y-4">
<AccordionItem title="AI Providers" forceOpen={openAccordions.has('prompt-management') || openAccordions.has('author-profiles')}>
<div id="prompt-management" ref={(el) => (sectionRefs.current["prompt-management"] = el)} className="space-y-4 scroll-mt-24">
<div id="author-profiles" ref={(el) => (sectionRefs.current["author-profiles"] = el)}></div>
<p className="text-gray-700 dark:text-gray-300">
IGNY8 integrates with multiple AI providers for content and image generation.
</p>
@@ -1100,8 +1125,10 @@ export default function Help() {
</h2>
<Accordion>
<AccordionItem title="Credits System" defaultOpen>
<div className="space-y-4">
<AccordionItem title="Credits System" defaultOpen forceOpen={openAccordions.has('credit-system') || openAccordions.has('purchasing-credits') || openAccordions.has('usage-tracking')}>
<div id="credit-system" ref={(el) => (sectionRefs.current["credit-system"] = el)} className="space-y-4 scroll-mt-24">
<div id="purchasing-credits" ref={(el) => (sectionRefs.current["purchasing-credits"] = el)}></div>
<div id="usage-tracking" ref={(el) => (sectionRefs.current["usage-tracking"] = el)}></div>
<p className="text-gray-700 dark:text-gray-300">
Credits are your currency for AI operations. Understand how credits work:
</p>
@@ -1212,8 +1239,9 @@ export default function Help() {
</div>
</AccordionItem>
<AccordionItem title="Team Management">
<div className="space-y-4">
<AccordionItem title="Team Management" forceOpen={openAccordions.has('team-collaboration') || openAccordions.has('user-roles')}>
<div id="team-collaboration" ref={(el) => (sectionRefs.current["team-collaboration"] = el)} className="space-y-4 scroll-mt-24">
<div id="user-roles" ref={(el) => (sectionRefs.current["user-roles"] = el)}></div>
<p className="text-gray-700 dark:text-gray-300">
Invite team members and manage roles in Account Settings Team.
</p>