@beyondcorp/beyond-ui 1.2.51 → 1.2.55
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/Blog/AllBlogsView.d.ts +8 -0
- package/dist/components/Blog/AllBlogsView.js +70 -0
- package/dist/components/Blog/AllBlogsView.js.map +1 -0
- package/dist/components/Blog/BlogCommentSection.d.ts +7 -0
- package/dist/components/Blog/BlogCommentSection.js +66 -0
- package/dist/components/Blog/BlogCommentSection.js.map +1 -0
- package/dist/components/Blog/BlogLayout.d.ts +11 -0
- package/dist/components/Blog/BlogLayout.js +29 -0
- package/dist/components/Blog/BlogLayout.js.map +1 -0
- package/dist/components/Blog/BlogShowcase.d.ts +2 -0
- package/dist/components/Blog/BlogShowcase.js +74 -0
- package/dist/components/Blog/BlogShowcase.js.map +1 -0
- package/dist/components/Blog/BlogSidebar.d.ts +10 -0
- package/dist/components/Blog/BlogSidebar.js +47 -0
- package/dist/components/Blog/BlogSidebar.js.map +1 -0
- package/dist/components/Blog/SingleBlogView.d.ts +8 -0
- package/dist/components/Blog/SingleBlogView.js +78 -0
- package/dist/components/Blog/SingleBlogView.js.map +1 -0
- package/dist/components/Blog/data/sampleData.d.ts +4 -0
- package/dist/components/Blog/data/sampleData.js +388 -0
- package/dist/components/Blog/data/sampleData.js.map +1 -0
- package/dist/components/Blog/hooks/index.d.ts +3 -0
- package/dist/components/Blog/hooks/useBlog.d.ts +22 -0
- package/dist/components/Blog/hooks/useBlog.js +148 -0
- package/dist/components/Blog/hooks/useBlog.js.map +1 -0
- package/dist/components/Blog/hooks/useBlogNavigation.d.ts +12 -0
- package/dist/components/Blog/hooks/useBlogNavigation.js +75 -0
- package/dist/components/Blog/hooks/useBlogNavigation.js.map +1 -0
- package/dist/components/Blog/hooks/useComments.d.ts +20 -0
- package/dist/components/Blog/hooks/useComments.js +108 -0
- package/dist/components/Blog/hooks/useComments.js.map +1 -0
- package/dist/components/Blog/index.d.ts +8 -0
- package/dist/components/Blog/types.d.ts +82 -0
- package/dist/components/CodeHighlight/CodeHighlight.d.ts +7 -0
- package/dist/components/CodeHighlight/CodeHighlight.js +18 -0
- package/dist/components/CodeHighlight/CodeHighlight.js.map +1 -0
- package/dist/components/CodeHighlight/index.d.ts +1 -0
- package/dist/components/Marketplace/AllProductsView.d.ts +6 -1
- package/dist/components/Marketplace/AllProductsView.js +42 -65
- package/dist/components/Marketplace/AllProductsView.js.map +1 -1
- package/dist/components/Marketplace/CheckoutCompact.d.ts +1 -0
- package/dist/components/Marketplace/CheckoutCompact.js +3 -3
- package/dist/components/Marketplace/CheckoutCompact.js.map +1 -1
- package/dist/components/Marketplace/CheckoutComponent.js +1 -1
- package/dist/components/Marketplace/CheckoutComponent.js.map +1 -1
- package/dist/components/Marketplace/MarketplaceComponent.js +31 -2
- package/dist/components/Marketplace/MarketplaceComponent.js.map +1 -1
- package/dist/components/Marketplace/MarketplaceSidebar.js +32 -32
- package/dist/components/Marketplace/MarketplaceSidebar.js.map +1 -1
- package/dist/components/Marketplace/SingleProductView.js +3 -0
- package/dist/components/Marketplace/SingleProductView.js.map +1 -1
- package/dist/components/Marketplace/components/MarketplaceControls.d.ts +17 -0
- package/dist/components/Marketplace/components/MarketplaceControls.js +22 -0
- package/dist/components/Marketplace/components/MarketplaceControls.js.map +1 -0
- package/dist/components/Marketplace/components/MarketplaceDashboard.d.ts +3 -0
- package/dist/components/Marketplace/components/MarketplaceDashboard.js +20 -10
- package/dist/components/Marketplace/components/MarketplaceDashboard.js.map +1 -1
- package/dist/components/Marketplace/components/MarketplaceHeader.js +2 -3
- package/dist/components/Marketplace/components/MarketplaceHeader.js.map +1 -1
- package/dist/components/Marketplace/components/ProductCard.js +9 -2
- package/dist/components/Marketplace/components/ProductCard.js.map +1 -1
- package/dist/components/Marketplace/hooks/useScrollToTop.d.ts +10 -0
- package/dist/components/Marketplace/hooks/useScrollToTop.js +22 -0
- package/dist/components/Marketplace/hooks/useScrollToTop.js.map +1 -0
- package/dist/index.d.ts +2 -4
- package/dist/index.js +10 -4
- package/dist/styles.css +1 -1
- package/package.json +6 -1
- package/dist/components/AllProductsView/AllProductsView.d.ts +0 -14
- package/dist/components/AllProductsView/AllProductsView.js +0 -61
- package/dist/components/AllProductsView/AllProductsView.js.map +0 -1
- package/dist/components/AllProductsView/CardGroup.d.ts +0 -6
- package/dist/components/AllProductsView/CardGroup.js +0 -11
- package/dist/components/AllProductsView/CardGroup.js.map +0 -1
- package/dist/components/AllProductsView/ProductCard.d.ts +0 -11
- package/dist/components/AllProductsView/ProductCard.js +0 -13
- package/dist/components/AllProductsView/ProductCard.js.map +0 -1
- package/dist/components/AllProductsView/index.d.ts +0 -2
- package/dist/components/BlogFeedView/BlogFeedView.d.ts +0 -22
- package/dist/components/BlogFeedView/BlogFeedView.js +0 -29
- package/dist/components/BlogFeedView/BlogFeedView.js.map +0 -1
- package/dist/components/BlogFeedView/index.d.ts +0 -1
- package/dist/components/BlogLayout/BlogLayout.d.ts +0 -13
- package/dist/components/BlogLayout/BlogLayout.js +0 -20
- package/dist/components/BlogLayout/BlogLayout.js.map +0 -1
- package/dist/components/BlogLayout/index.d.ts +0 -1
- package/dist/components/BlogSidebar/BlogSidebar.d.ts +0 -19
- package/dist/components/BlogSidebar/BlogSidebar.js +0 -10
- package/dist/components/BlogSidebar/BlogSidebar.js.map +0 -1
- package/dist/components/BlogSidebar/index.d.ts +0 -1
- package/dist/components/Checkout/CheckoutPage.d.ts +0 -16
- package/dist/components/Checkout/CheckoutPage.js +0 -44
- package/dist/components/Checkout/CheckoutPage.js.map +0 -1
- package/dist/components/Checkout/CheckoutSidebar.d.ts +0 -15
- package/dist/components/Checkout/CheckoutSidebar.js +0 -25
- package/dist/components/Checkout/CheckoutSidebar.js.map +0 -1
- package/dist/components/Checkout/index.d.ts +0 -3
- package/dist/components/Checkout/types.d.ts +0 -21
- package/dist/components/CommerceSidebar/CommerceSidebar.d.ts +0 -20
- package/dist/components/CommerceSidebar/CommerceSidebar.js +0 -14
- package/dist/components/CommerceSidebar/CommerceSidebar.js.map +0 -1
- package/dist/components/CommerceSidebar/index.d.ts +0 -1
- package/dist/components/MarketplaceLayout/MarketplaceLayout.d.ts +0 -17
- package/dist/components/MarketplaceLayout/MarketplaceLayout.js +0 -22
- package/dist/components/MarketplaceLayout/MarketplaceLayout.js.map +0 -1
- package/dist/components/MarketplaceLayout/index.d.ts +0 -1
- package/dist/components/ProfileManagement/ProfileManagementPage.d.ts +0 -16
- package/dist/components/ProfileManagement/ProfileManagementPage.js +0 -65
- package/dist/components/ProfileManagement/ProfileManagementPage.js.map +0 -1
- package/dist/components/SingleBlogView/SingleBlogView.d.ts +0 -26
- package/dist/components/SingleBlogView/SingleBlogView.js +0 -17
- package/dist/components/SingleBlogView/SingleBlogView.js.map +0 -1
- package/dist/components/SingleBlogView/index.d.ts +0 -1
- package/dist/components/SingleProductView/SingleProductView.d.ts +0 -31
- package/dist/components/SingleProductView/SingleProductView.js +0 -34
- package/dist/components/SingleProductView/SingleProductView.js.map +0 -1
- package/dist/components/SingleProductView/index.d.ts +0 -1
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { useState, useCallback, useEffect } from 'react';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Custom hook for blog navigation and table of contents
|
|
5
|
+
* Handles smooth scrolling and active section tracking
|
|
6
|
+
*/
|
|
7
|
+
const useBlogNavigation = () => {
|
|
8
|
+
const [tableOfContents, setTableOfContents] = useState([]);
|
|
9
|
+
const [activeSection, setActiveSection] = useState('');
|
|
10
|
+
// Generate table of contents from markdown content
|
|
11
|
+
const generateTableOfContents = useCallback((content) => {
|
|
12
|
+
const headingRegex = /^(#{1,6})\s+(.+)$/gm;
|
|
13
|
+
const toc = [];
|
|
14
|
+
let match;
|
|
15
|
+
while ((match = headingRegex.exec(content)) !== null) {
|
|
16
|
+
const level = match[1].length;
|
|
17
|
+
const title = match[2].trim();
|
|
18
|
+
const anchor = title
|
|
19
|
+
.toLowerCase()
|
|
20
|
+
.replace(/[^a-z0-9\s-]/g, '')
|
|
21
|
+
.replace(/\s+/g, '-');
|
|
22
|
+
toc.push({
|
|
23
|
+
id: `toc-${toc.length}`,
|
|
24
|
+
title,
|
|
25
|
+
level,
|
|
26
|
+
anchor,
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
setTableOfContents(toc);
|
|
30
|
+
}, []);
|
|
31
|
+
// Smooth scroll to section
|
|
32
|
+
const scrollToSection = useCallback((anchor) => {
|
|
33
|
+
const element = document.getElementById(anchor);
|
|
34
|
+
if (element) {
|
|
35
|
+
element.scrollIntoView({
|
|
36
|
+
behavior: 'smooth',
|
|
37
|
+
block: 'start',
|
|
38
|
+
});
|
|
39
|
+
setActiveSection(anchor);
|
|
40
|
+
}
|
|
41
|
+
}, []);
|
|
42
|
+
// Track active section on scroll
|
|
43
|
+
useEffect(() => {
|
|
44
|
+
const handleScroll = () => {
|
|
45
|
+
const headings = tableOfContents.map(item => ({
|
|
46
|
+
anchor: item.anchor,
|
|
47
|
+
element: document.getElementById(item.anchor),
|
|
48
|
+
})).filter(item => item.element);
|
|
49
|
+
let currentActive = '';
|
|
50
|
+
for (const heading of headings) {
|
|
51
|
+
const rect = heading.element.getBoundingClientRect();
|
|
52
|
+
if (rect.top <= 100) {
|
|
53
|
+
currentActive = heading.anchor;
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
break;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
if (currentActive !== activeSection) {
|
|
60
|
+
setActiveSection(currentActive);
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
window.addEventListener('scroll', handleScroll, { passive: true });
|
|
64
|
+
return () => window.removeEventListener('scroll', handleScroll);
|
|
65
|
+
}, [tableOfContents, activeSection]);
|
|
66
|
+
return {
|
|
67
|
+
tableOfContents,
|
|
68
|
+
activeSection,
|
|
69
|
+
scrollToSection,
|
|
70
|
+
generateTableOfContents,
|
|
71
|
+
};
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
export { useBlogNavigation };
|
|
75
|
+
//# sourceMappingURL=useBlogNavigation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useBlogNavigation.js","sources":["../../../../src/components/Blog/hooks/useBlogNavigation.ts"],"sourcesContent":["import { useState, useCallback, useEffect } from 'react';\nimport type { TableOfContentsItem } from '../types';\n\nexport interface UseBlogNavigationReturn {\n tableOfContents: TableOfContentsItem[];\n activeSection: string;\n scrollToSection: (anchor: string) => void;\n generateTableOfContents: (content: string) => void;\n}\n\n/**\n * Custom hook for blog navigation and table of contents\n * Handles smooth scrolling and active section tracking\n */\nexport const useBlogNavigation = (): UseBlogNavigationReturn => {\n const [tableOfContents, setTableOfContents] = useState<TableOfContentsItem[]>([]);\n const [activeSection, setActiveSection] = useState('');\n\n // Generate table of contents from markdown content\n const generateTableOfContents = useCallback((content: string) => {\n const headingRegex = /^(#{1,6})\\s+(.+)$/gm;\n const toc: TableOfContentsItem[] = [];\n let match;\n\n while ((match = headingRegex.exec(content)) !== null) {\n const level = match[1].length;\n const title = match[2].trim();\n const anchor = title\n .toLowerCase()\n .replace(/[^a-z0-9\\s-]/g, '')\n .replace(/\\s+/g, '-');\n\n toc.push({\n id: `toc-${toc.length}`,\n title,\n level,\n anchor,\n });\n }\n\n setTableOfContents(toc);\n }, []);\n\n // Smooth scroll to section\n const scrollToSection = useCallback((anchor: string) => {\n const element = document.getElementById(anchor);\n if (element) {\n element.scrollIntoView({\n behavior: 'smooth',\n block: 'start',\n });\n setActiveSection(anchor);\n }\n }, []);\n\n // Track active section on scroll\n useEffect(() => {\n const handleScroll = () => {\n const headings = tableOfContents.map(item => ({\n anchor: item.anchor,\n element: document.getElementById(item.anchor),\n })).filter(item => item.element);\n\n let currentActive = '';\n \n for (const heading of headings) {\n const rect = heading.element!.getBoundingClientRect();\n if (rect.top <= 100) {\n currentActive = heading.anchor;\n } else {\n break;\n }\n }\n\n if (currentActive !== activeSection) {\n setActiveSection(currentActive);\n }\n };\n\n window.addEventListener('scroll', handleScroll, { passive: true });\n return () => window.removeEventListener('scroll', handleScroll);\n }, [tableOfContents, activeSection]);\n\n return {\n tableOfContents,\n activeSection,\n scrollToSection,\n generateTableOfContents,\n };\n};"],"names":[],"mappings":";;AAUA;;;AAGG;AACI,MAAM,iBAAiB,GAAG,MAA8B;IAC7D,MAAM,CAAC,eAAe,EAAE,kBAAkB,CAAC,GAAG,QAAQ,CAAwB,EAAE,CAAC;IACjF,MAAM,CAAC,aAAa,EAAE,gBAAgB,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC;;AAGtD,IAAA,MAAM,uBAAuB,GAAG,WAAW,CAAC,CAAC,OAAe,KAAI;QAC9D,MAAM,YAAY,GAAG,qBAAqB;QAC1C,MAAM,GAAG,GAA0B,EAAE;AACrC,QAAA,IAAI,KAAK;AAET,QAAA,OAAO,CAAC,KAAK,GAAG,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,IAAI,EAAE;YACpD,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM;YAC7B,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE;YAC7B,MAAM,MAAM,GAAG;AACZ,iBAAA,WAAW;AACX,iBAAA,OAAO,CAAC,eAAe,EAAE,EAAE;AAC3B,iBAAA,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC;YAEvB,GAAG,CAAC,IAAI,CAAC;AACP,gBAAA,EAAE,EAAE,CAAA,IAAA,EAAO,GAAG,CAAC,MAAM,CAAA,CAAE;gBACvB,KAAK;gBACL,KAAK;gBACL,MAAM;AACP,aAAA,CAAC;QACJ;QAEA,kBAAkB,CAAC,GAAG,CAAC;IACzB,CAAC,EAAE,EAAE,CAAC;;AAGN,IAAA,MAAM,eAAe,GAAG,WAAW,CAAC,CAAC,MAAc,KAAI;QACrD,MAAM,OAAO,GAAG,QAAQ,CAAC,cAAc,CAAC,MAAM,CAAC;QAC/C,IAAI,OAAO,EAAE;YACX,OAAO,CAAC,cAAc,CAAC;AACrB,gBAAA,QAAQ,EAAE,QAAQ;AAClB,gBAAA,KAAK,EAAE,OAAO;AACf,aAAA,CAAC;YACF,gBAAgB,CAAC,MAAM,CAAC;QAC1B;IACF,CAAC,EAAE,EAAE,CAAC;;IAGN,SAAS,CAAC,MAAK;QACb,MAAM,YAAY,GAAG,MAAK;YACxB,MAAM,QAAQ,GAAG,eAAe,CAAC,GAAG,CAAC,IAAI,KAAK;gBAC5C,MAAM,EAAE,IAAI,CAAC,MAAM;gBACnB,OAAO,EAAE,QAAQ,CAAC,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC;AAC9C,aAAA,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,IAAI,IAAI,CAAC,OAAO,CAAC;YAEhC,IAAI,aAAa,GAAG,EAAE;AAEtB,YAAA,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE;gBAC9B,MAAM,IAAI,GAAG,OAAO,CAAC,OAAQ,CAAC,qBAAqB,EAAE;AACrD,gBAAA,IAAI,IAAI,CAAC,GAAG,IAAI,GAAG,EAAE;AACnB,oBAAA,aAAa,GAAG,OAAO,CAAC,MAAM;gBAChC;qBAAO;oBACL;gBACF;YACF;AAEA,YAAA,IAAI,aAAa,KAAK,aAAa,EAAE;gBACnC,gBAAgB,CAAC,aAAa,CAAC;YACjC;AACF,QAAA,CAAC;AAED,QAAA,MAAM,CAAC,gBAAgB,CAAC,QAAQ,EAAE,YAAY,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;QAClE,OAAO,MAAM,MAAM,CAAC,mBAAmB,CAAC,QAAQ,EAAE,YAAY,CAAC;AACjE,IAAA,CAAC,EAAE,CAAC,eAAe,EAAE,aAAa,CAAC,CAAC;IAEpC,OAAO;QACL,eAAe;QACf,aAAa;QACb,eAAe;QACf,uBAAuB;KACxB;AACH;;;;"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { BlogComment } from '../types';
|
|
2
|
+
export interface UseCommentsProps {
|
|
3
|
+
postId: string;
|
|
4
|
+
}
|
|
5
|
+
export interface UseCommentsReturn {
|
|
6
|
+
comments: BlogComment[];
|
|
7
|
+
loading: boolean;
|
|
8
|
+
error: string | null;
|
|
9
|
+
addComment: (content: string, parentId?: string) => Promise<void>;
|
|
10
|
+
likeComment: (commentId: string) => void;
|
|
11
|
+
dislikeComment: (commentId: string) => void;
|
|
12
|
+
reportComment: (commentId: string) => void;
|
|
13
|
+
deleteComment: (commentId: string) => void;
|
|
14
|
+
getCommentCount: () => number;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Custom hook for managing blog comments
|
|
18
|
+
* Handles comment CRUD operations, moderation, and nested replies
|
|
19
|
+
*/
|
|
20
|
+
export declare const useComments: ({ postId }: UseCommentsProps) => UseCommentsReturn;
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { useState, useMemo, useCallback } from 'react';
|
|
2
|
+
import { sampleBlogComments } from '../data/sampleData.js';
|
|
3
|
+
import { showToast } from '../../Toast/Toast.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Custom hook for managing blog comments
|
|
7
|
+
* Handles comment CRUD operations, moderation, and nested replies
|
|
8
|
+
*/
|
|
9
|
+
const useComments = ({ postId }) => {
|
|
10
|
+
const [comments, setComments] = useState(sampleBlogComments.filter(comment => comment.postId === postId));
|
|
11
|
+
const [loading, setLoading] = useState(false);
|
|
12
|
+
const [error, setError] = useState(null);
|
|
13
|
+
// Organize comments into tree structure
|
|
14
|
+
const organizedComments = useMemo(() => {
|
|
15
|
+
const commentMap = new Map();
|
|
16
|
+
const rootComments = [];
|
|
17
|
+
// First pass: create map of all comments
|
|
18
|
+
comments.forEach(comment => {
|
|
19
|
+
commentMap.set(comment.id, { ...comment, replies: [] });
|
|
20
|
+
});
|
|
21
|
+
// Second pass: organize into tree structure
|
|
22
|
+
comments.forEach(comment => {
|
|
23
|
+
const commentWithReplies = commentMap.get(comment.id);
|
|
24
|
+
if (comment.parentId) {
|
|
25
|
+
const parent = commentMap.get(comment.parentId);
|
|
26
|
+
if (parent) {
|
|
27
|
+
parent.replies = parent.replies || [];
|
|
28
|
+
parent.replies.push(commentWithReplies);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
rootComments.push(commentWithReplies);
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
return rootComments;
|
|
36
|
+
}, [comments]);
|
|
37
|
+
const addComment = useCallback(async (content, parentId) => {
|
|
38
|
+
setLoading(true);
|
|
39
|
+
setError(null);
|
|
40
|
+
try {
|
|
41
|
+
// Simulate API call
|
|
42
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
43
|
+
const newComment = {
|
|
44
|
+
id: `c${Date.now()}`,
|
|
45
|
+
postId,
|
|
46
|
+
parentId,
|
|
47
|
+
author: {
|
|
48
|
+
id: 'current-user',
|
|
49
|
+
name: 'Current User',
|
|
50
|
+
avatar: 'https://images.pexels.com/photos/774909/pexels-photo-774909.jpeg?auto=compress&cs=tinysrgb&w=64',
|
|
51
|
+
},
|
|
52
|
+
content,
|
|
53
|
+
createdAt: new Date().toISOString(),
|
|
54
|
+
likes: 0,
|
|
55
|
+
dislikes: 0,
|
|
56
|
+
isModerated: false,
|
|
57
|
+
isReported: false,
|
|
58
|
+
};
|
|
59
|
+
setComments(prev => [...prev, newComment]);
|
|
60
|
+
showToast.success('Comment added successfully!');
|
|
61
|
+
}
|
|
62
|
+
catch (err) {
|
|
63
|
+
setError('Failed to add comment');
|
|
64
|
+
showToast.error('Failed to add comment');
|
|
65
|
+
}
|
|
66
|
+
finally {
|
|
67
|
+
setLoading(false);
|
|
68
|
+
}
|
|
69
|
+
}, [postId]);
|
|
70
|
+
const likeComment = useCallback((commentId) => {
|
|
71
|
+
setComments(prev => prev.map(comment => comment.id === commentId
|
|
72
|
+
? { ...comment, likes: comment.likes + 1 }
|
|
73
|
+
: comment));
|
|
74
|
+
showToast.success('Comment liked!');
|
|
75
|
+
}, []);
|
|
76
|
+
const dislikeComment = useCallback((commentId) => {
|
|
77
|
+
setComments(prev => prev.map(comment => comment.id === commentId
|
|
78
|
+
? { ...comment, dislikes: comment.dislikes + 1 }
|
|
79
|
+
: comment));
|
|
80
|
+
}, []);
|
|
81
|
+
const reportComment = useCallback((commentId) => {
|
|
82
|
+
setComments(prev => prev.map(comment => comment.id === commentId
|
|
83
|
+
? { ...comment, isReported: true }
|
|
84
|
+
: comment));
|
|
85
|
+
showToast.info('Comment reported for moderation');
|
|
86
|
+
}, []);
|
|
87
|
+
const deleteComment = useCallback((commentId) => {
|
|
88
|
+
setComments(prev => prev.filter(comment => comment.id !== commentId));
|
|
89
|
+
showToast.info('Comment deleted');
|
|
90
|
+
}, []);
|
|
91
|
+
const getCommentCount = useCallback(() => {
|
|
92
|
+
return comments.length;
|
|
93
|
+
}, [comments.length]);
|
|
94
|
+
return {
|
|
95
|
+
comments: organizedComments,
|
|
96
|
+
loading,
|
|
97
|
+
error,
|
|
98
|
+
addComment,
|
|
99
|
+
likeComment,
|
|
100
|
+
dislikeComment,
|
|
101
|
+
reportComment,
|
|
102
|
+
deleteComment,
|
|
103
|
+
getCommentCount,
|
|
104
|
+
};
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
export { useComments };
|
|
108
|
+
//# sourceMappingURL=useComments.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useComments.js","sources":["../../../../src/components/Blog/hooks/useComments.ts"],"sourcesContent":["import { useState, useCallback, useMemo } from 'react';\nimport type { BlogComment } from '../types';\nimport { sampleBlogComments } from '../data/sampleData';\nimport { showToast } from '../../Toast';\n\nexport interface UseCommentsProps {\n postId: string;\n}\n\nexport interface UseCommentsReturn {\n comments: BlogComment[];\n loading: boolean;\n error: string | null;\n addComment: (content: string, parentId?: string) => Promise<void>;\n likeComment: (commentId: string) => void;\n dislikeComment: (commentId: string) => void;\n reportComment: (commentId: string) => void;\n deleteComment: (commentId: string) => void;\n getCommentCount: () => number;\n}\n\n/**\n * Custom hook for managing blog comments\n * Handles comment CRUD operations, moderation, and nested replies\n */\nexport const useComments = ({ postId }: UseCommentsProps): UseCommentsReturn => {\n const [comments, setComments] = useState<BlogComment[]>(\n sampleBlogComments.filter(comment => comment.postId === postId)\n );\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n // Organize comments into tree structure\n const organizedComments = useMemo(() => {\n const commentMap = new Map<string, BlogComment>();\n const rootComments: BlogComment[] = [];\n\n // First pass: create map of all comments\n comments.forEach(comment => {\n commentMap.set(comment.id, { ...comment, replies: [] });\n });\n\n // Second pass: organize into tree structure\n comments.forEach(comment => {\n const commentWithReplies = commentMap.get(comment.id)!;\n \n if (comment.parentId) {\n const parent = commentMap.get(comment.parentId);\n if (parent) {\n parent.replies = parent.replies || [];\n parent.replies.push(commentWithReplies);\n }\n } else {\n rootComments.push(commentWithReplies);\n }\n });\n\n return rootComments;\n }, [comments]);\n\n const addComment = useCallback(async (content: string, parentId?: string) => {\n setLoading(true);\n setError(null);\n\n try {\n // Simulate API call\n await new Promise(resolve => setTimeout(resolve, 1000));\n\n const newComment: BlogComment = {\n id: `c${Date.now()}`,\n postId,\n parentId,\n author: {\n id: 'current-user',\n name: 'Current User',\n avatar: 'https://images.pexels.com/photos/774909/pexels-photo-774909.jpeg?auto=compress&cs=tinysrgb&w=64',\n },\n content,\n createdAt: new Date().toISOString(),\n likes: 0,\n dislikes: 0,\n isModerated: false,\n isReported: false,\n };\n\n setComments(prev => [...prev, newComment]);\n showToast.success('Comment added successfully!');\n } catch (err) {\n setError('Failed to add comment');\n showToast.error('Failed to add comment');\n } finally {\n setLoading(false);\n }\n }, [postId]);\n\n const likeComment = useCallback((commentId: string) => {\n setComments(prev =>\n prev.map(comment =>\n comment.id === commentId\n ? { ...comment, likes: comment.likes + 1 }\n : comment\n )\n );\n showToast.success('Comment liked!');\n }, []);\n\n const dislikeComment = useCallback((commentId: string) => {\n setComments(prev =>\n prev.map(comment =>\n comment.id === commentId\n ? { ...comment, dislikes: comment.dislikes + 1 }\n : comment\n )\n );\n }, []);\n\n const reportComment = useCallback((commentId: string) => {\n setComments(prev =>\n prev.map(comment =>\n comment.id === commentId\n ? { ...comment, isReported: true }\n : comment\n )\n );\n showToast.info('Comment reported for moderation');\n }, []);\n\n const deleteComment = useCallback((commentId: string) => {\n setComments(prev => prev.filter(comment => comment.id !== commentId));\n showToast.info('Comment deleted');\n }, []);\n\n const getCommentCount = useCallback(() => {\n return comments.length;\n }, [comments.length]);\n\n return {\n comments: organizedComments,\n loading,\n error,\n addComment,\n likeComment,\n dislikeComment,\n reportComment,\n deleteComment,\n getCommentCount,\n };\n};"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
export interface BlogPost {
|
|
2
|
+
id: string;
|
|
3
|
+
title: string;
|
|
4
|
+
slug: string;
|
|
5
|
+
content: string;
|
|
6
|
+
excerpt: string;
|
|
7
|
+
author: {
|
|
8
|
+
id: string;
|
|
9
|
+
name: string;
|
|
10
|
+
avatar?: string;
|
|
11
|
+
bio?: string;
|
|
12
|
+
};
|
|
13
|
+
publishedAt: string;
|
|
14
|
+
updatedAt?: string;
|
|
15
|
+
tags: string[];
|
|
16
|
+
category: string;
|
|
17
|
+
readingTime: number;
|
|
18
|
+
featured: boolean;
|
|
19
|
+
status: 'draft' | 'published' | 'archived';
|
|
20
|
+
seoMeta: {
|
|
21
|
+
title?: string;
|
|
22
|
+
description?: string;
|
|
23
|
+
keywords?: string[];
|
|
24
|
+
ogImage?: string;
|
|
25
|
+
};
|
|
26
|
+
stats: {
|
|
27
|
+
views: number;
|
|
28
|
+
likes: number;
|
|
29
|
+
comments: number;
|
|
30
|
+
shares: number;
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
export interface BlogComment {
|
|
34
|
+
id: string;
|
|
35
|
+
postId: string;
|
|
36
|
+
author: {
|
|
37
|
+
id: string;
|
|
38
|
+
name: string;
|
|
39
|
+
avatar?: string;
|
|
40
|
+
};
|
|
41
|
+
content: string;
|
|
42
|
+
createdAt: string;
|
|
43
|
+
updatedAt?: string;
|
|
44
|
+
parentId?: string;
|
|
45
|
+
likes: number;
|
|
46
|
+
dislikes: number;
|
|
47
|
+
isModerated: boolean;
|
|
48
|
+
isReported: boolean;
|
|
49
|
+
replies?: BlogComment[];
|
|
50
|
+
}
|
|
51
|
+
export interface BlogCategory {
|
|
52
|
+
id: string;
|
|
53
|
+
name: string;
|
|
54
|
+
slug: string;
|
|
55
|
+
description?: string;
|
|
56
|
+
postCount: number;
|
|
57
|
+
color?: string;
|
|
58
|
+
}
|
|
59
|
+
export interface BlogFilters {
|
|
60
|
+
search: string;
|
|
61
|
+
tags: string[];
|
|
62
|
+
categories: string[];
|
|
63
|
+
authors: string[];
|
|
64
|
+
dateRange: {
|
|
65
|
+
start?: string;
|
|
66
|
+
end?: string;
|
|
67
|
+
};
|
|
68
|
+
sortBy: 'newest' | 'oldest' | 'popular' | 'trending';
|
|
69
|
+
}
|
|
70
|
+
export interface BlogPagination {
|
|
71
|
+
page: number;
|
|
72
|
+
limit: number;
|
|
73
|
+
total: number;
|
|
74
|
+
hasNext: boolean;
|
|
75
|
+
hasPrev: boolean;
|
|
76
|
+
}
|
|
77
|
+
export interface TableOfContentsItem {
|
|
78
|
+
id: string;
|
|
79
|
+
title: string;
|
|
80
|
+
level: number;
|
|
81
|
+
anchor: string;
|
|
82
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { jsx } from 'react/jsx-runtime';
|
|
2
|
+
import highlighter from '../../node_modules/react-syntax-highlighter/dist/esm/prism.js';
|
|
3
|
+
import vscDarkPlus from '../../node_modules/react-syntax-highlighter/dist/esm/styles/prism/vsc-dark-plus.js';
|
|
4
|
+
|
|
5
|
+
const CodeHighlight = ({ code, language = "javascript", className = "", }) => {
|
|
6
|
+
return (jsx(highlighter, { language: language, style: vscDarkPlus, customStyle: {
|
|
7
|
+
borderRadius: "0.5rem",
|
|
8
|
+
padding: "1rem",
|
|
9
|
+
fontFamily: "monospace",
|
|
10
|
+
background: "var(--color-primary-50, #2d2d2d)",
|
|
11
|
+
color: "var(--color-primary-700, #f8f8f2)",
|
|
12
|
+
overflowX: "auto",
|
|
13
|
+
}, className: className, showLineNumbers: false, wrapLongLines: true, children: code }));
|
|
14
|
+
};
|
|
15
|
+
CodeHighlight.displayName = "CodeHighlight";
|
|
16
|
+
|
|
17
|
+
export { CodeHighlight };
|
|
18
|
+
//# sourceMappingURL=CodeHighlight.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CodeHighlight.js","sources":["../../../src/components/CodeHighlight/CodeHighlight.tsx"],"sourcesContent":["import React from \"react\";\r\nimport { Prism as SyntaxHighlighter } from \"react-syntax-highlighter\";\r\nimport { vscDarkPlus } from \"react-syntax-highlighter/dist/esm/styles/prism\";\r\n\r\nexport interface CodeHighlightProps {\r\n code: string;\r\n language?: string;\r\n className?: string;\r\n}\r\n\r\nexport const CodeHighlight: React.FC<CodeHighlightProps> = ({\r\n code,\r\n language = \"javascript\",\r\n className = \"\",\r\n}) => {\r\n return (\r\n <SyntaxHighlighter\r\n language={language}\r\n style={vscDarkPlus}\r\n customStyle={{\r\n borderRadius: \"0.5rem\",\r\n padding: \"1rem\",\r\n fontFamily: \"monospace\",\r\n background: \"var(--color-primary-50, #2d2d2d)\",\r\n color: \"var(--color-primary-700, #f8f8f2)\",\r\n overflowX: \"auto\",\r\n }}\r\n className={className}\r\n showLineNumbers={false}\r\n wrapLongLines={true}\r\n >\r\n {code}\r\n </SyntaxHighlighter>\r\n );\r\n};\r\n\r\nCodeHighlight.displayName = \"CodeHighlight\";"],"names":["_jsx","SyntaxHighlighter"],"mappings":";;;;AAUO,MAAM,aAAa,GAAiC,CAAC,EAC1D,IAAI,EACJ,QAAQ,GAAG,YAAY,EACvB,SAAS,GAAG,EAAE,GACf,KAAI;AACH,IAAA,QACEA,GAAA,CAACC,WAAiB,EAAA,EAChB,QAAQ,EAAE,QAAQ,EAClB,KAAK,EAAE,WAAW,EAClB,WAAW,EAAE;AACX,YAAA,YAAY,EAAE,QAAQ;AACtB,YAAA,OAAO,EAAE,MAAM;AACf,YAAA,UAAU,EAAE,WAAW;AACvB,YAAA,UAAU,EAAE,kCAAkC;AAC9C,YAAA,KAAK,EAAE,mCAAmC;AAC1C,YAAA,SAAS,EAAE,MAAM;AAClB,SAAA,EACD,SAAS,EAAE,SAAS,EACpB,eAAe,EAAE,KAAK,EACtB,aAAa,EAAE,IAAI,EAAA,QAAA,EAElB,IAAI,EAAA,CACa;AAExB;AAEA,aAAa,CAAC,WAAW,GAAG,eAAe;;;;"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './CodeHighlight';
|
|
@@ -2,9 +2,14 @@ import React from 'react';
|
|
|
2
2
|
import type { Product, FilterOptions } from './types';
|
|
3
3
|
interface AllProductsViewProps {
|
|
4
4
|
products?: Product[];
|
|
5
|
-
filters
|
|
5
|
+
filters: FilterOptions;
|
|
6
|
+
searchQuery: string;
|
|
7
|
+
setSearchQuery?: (query: string) => void;
|
|
8
|
+
shouldFocusSearch?: boolean;
|
|
6
9
|
onProductClick?: (product: Product) => void;
|
|
7
10
|
onAddToCart?: (product: Product) => void;
|
|
11
|
+
onFiltersChange: (filters: FilterOptions) => void;
|
|
12
|
+
onClearFilters: () => void;
|
|
8
13
|
}
|
|
9
14
|
export declare const AllProductsView: React.FC<AllProductsViewProps>;
|
|
10
15
|
export {};
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
2
2
|
import { useState, useMemo } from 'react';
|
|
3
|
-
import { Search,
|
|
3
|
+
import { Search, Star, ShoppingCart } from 'lucide-react';
|
|
4
|
+
import { MarketplaceControls } from './components/MarketplaceControls.js';
|
|
4
5
|
import { Button } from '../Button/Button.js';
|
|
5
|
-
import { Input } from '../Input/Input.js';
|
|
6
|
-
import { Card, CardContent } from '../Card/Card.js';
|
|
7
6
|
import { Badge } from '../Badge/Badge.js';
|
|
8
7
|
import { Modal, ModalHeader, ModalTitle, ModalContent, ModalFooter } from '../Modal/Modal.js';
|
|
9
8
|
import { Checkbox } from '../Checkbox/Checkbox.js';
|
|
10
9
|
import { showToast } from '../Toast/Toast.js';
|
|
11
10
|
import { sampleProducts } from './data/sampleData.js';
|
|
11
|
+
import { ProductCard } from './components/ProductCard.js';
|
|
12
12
|
|
|
13
13
|
const sortOptions = [
|
|
14
14
|
{ value: 'relevance', label: 'Most Relevant' },
|
|
@@ -18,24 +18,16 @@ const sortOptions = [
|
|
|
18
18
|
{ value: 'newest', label: 'Newest First' },
|
|
19
19
|
{ value: 'popular', label: 'Most Popular' },
|
|
20
20
|
];
|
|
21
|
-
const AllProductsView = ({ products, filters: filtersProp, onProductClick, onAddToCart, }) => {
|
|
21
|
+
const AllProductsView = ({ products, filters: filtersProp, searchQuery, setSearchQuery, shouldFocusSearch, onProductClick, onAddToCart, onFiltersChange, onClearFilters, }) => {
|
|
22
22
|
const productsData = products ?? sampleProducts;
|
|
23
|
-
const [searchQuery, setSearchQuery] = useState('');
|
|
24
23
|
const [sortBy, setSortBy] = useState('relevance');
|
|
25
24
|
const [viewMode, setViewMode] = useState('grid');
|
|
26
25
|
const [currentPage, setCurrentPage] = useState(1);
|
|
27
26
|
const [showFilters, setShowFilters] = useState(false);
|
|
28
27
|
const [quickViewProduct, setQuickViewProduct] = useState(null);
|
|
29
28
|
const [wishlist, setWishlist] = useState(new Set());
|
|
30
|
-
// Use
|
|
31
|
-
const
|
|
32
|
-
categories: [],
|
|
33
|
-
brands: [],
|
|
34
|
-
priceRange: [0, 1000],
|
|
35
|
-
rating: 0,
|
|
36
|
-
inStock: false,
|
|
37
|
-
vendors: [],
|
|
38
|
-
});
|
|
29
|
+
// Use filters and handlers from props only
|
|
30
|
+
const filters = filtersProp;
|
|
39
31
|
const itemsPerPage = 12;
|
|
40
32
|
// Get unique filter options from products
|
|
41
33
|
const filterOptions = useMemo(() => {
|
|
@@ -106,22 +98,15 @@ const AllProductsView = ({ products, filters: filtersProp, onProductClick, onAdd
|
|
|
106
98
|
}, [filteredProducts, currentPage]);
|
|
107
99
|
const totalPages = Math.ceil(filteredProducts.length / itemsPerPage);
|
|
108
100
|
const handleFilterChange = (filterType, value) => {
|
|
109
|
-
|
|
110
|
-
...
|
|
101
|
+
const newFilters = {
|
|
102
|
+
...filters,
|
|
111
103
|
[filterType]: value,
|
|
112
|
-
}
|
|
104
|
+
};
|
|
105
|
+
onFiltersChange(newFilters);
|
|
113
106
|
setCurrentPage(1); // Reset to first page when filters change
|
|
114
107
|
};
|
|
115
108
|
const handleClearFilters = () => {
|
|
116
|
-
|
|
117
|
-
categories: [],
|
|
118
|
-
brands: [],
|
|
119
|
-
priceRange: [0, 1000],
|
|
120
|
-
rating: 0,
|
|
121
|
-
inStock: false,
|
|
122
|
-
vendors: [],
|
|
123
|
-
});
|
|
124
|
-
setSearchQuery('');
|
|
109
|
+
onClearFilters();
|
|
125
110
|
setCurrentPage(1);
|
|
126
111
|
};
|
|
127
112
|
const toggleWishlist = (productId) => {
|
|
@@ -142,45 +127,37 @@ const AllProductsView = ({ products, filters: filtersProp, onProductClick, onAdd
|
|
|
142
127
|
onAddToCart?.(product);
|
|
143
128
|
showToast.success(`${product.name} added to cart!`);
|
|
144
129
|
};
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
const page = i + 1;
|
|
177
|
-
return (jsx(Button, { variant: currentPage === page ? 'primary' : 'outline', onClick: () => setCurrentPage(page), children: page }, page));
|
|
178
|
-
}), jsx(Button, { variant: "outline", onClick: () => setCurrentPage(prev => Math.min(totalPages, prev + 1)), disabled: currentPage === totalPages, children: "Next" })] }))] })) })] }), jsxs(Modal, { open: showFilters, onOpenChange: setShowFilters, children: [jsx(ModalHeader, { children: jsx(ModalTitle, { children: "Filters" }) }), jsx(ModalContent, { children: jsx("div", { className: "space-y-6", children: jsxs("div", { children: [jsx("h4", { className: "font-medium text-gray-900 mb-3", children: "Categories" }), jsx("div", { className: "space-y-2", children: filterOptions.categories.map((category, idx) => (jsxs("label", { className: "flex items-center space-x-2", children: [jsx(Checkbox, { checked: filters.categories.includes(category), onChange: (e) => {
|
|
179
|
-
const newCategories = e.target.checked
|
|
180
|
-
? [...filters.categories, category]
|
|
181
|
-
: filters.categories.filter((c) => c !== category);
|
|
182
|
-
handleFilterChange('categories', newCategories);
|
|
183
|
-
} }), jsx("span", { className: "text-sm text-gray-700", children: category })] }, category))) })] }) }) }), jsxs(ModalFooter, { children: [jsx(Button, { variant: "outline", onClick: handleClearFilters, children: "Clear All" }), jsx(Button, { variant: "primary", onClick: () => setShowFilters(false), children: "Apply Filters" })] })] }), jsx(Modal, { open: !!quickViewProduct, onOpenChange: () => setQuickViewProduct(null), size: "lg", children: quickViewProduct && (jsxs(Fragment, { children: [jsx(ModalHeader, { children: jsx(ModalTitle, { children: quickViewProduct.name }) }), jsx(ModalContent, { children: jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-6", children: [jsx("div", { className: "aspect-square bg-gray-100 rounded-lg overflow-hidden", children: jsx("img", { src: quickViewProduct.images[0], alt: quickViewProduct.name, className: "w-full h-full object-cover" }) }), jsxs("div", { children: [jsxs("div", { className: "flex items-center space-x-1 mb-2", children: [jsx(Star, { className: "h-4 w-4 text-yellow-400 fill-current" }), jsxs("span", { className: "text-sm text-gray-600", children: [quickViewProduct.rating, " (", quickViewProduct.reviewCount, " reviews)"] })] }), jsxs("div", { className: "flex items-center space-x-2 mb-4", children: [jsxs("span", { className: "text-2xl font-bold text-gray-900", children: ["$", quickViewProduct.price.toFixed(2)] }), quickViewProduct.originalPrice && (jsxs("span", { className: "text-lg text-gray-500 line-through", children: ["$", quickViewProduct.originalPrice.toFixed(2)] }))] }), jsx("p", { className: "text-gray-600 mb-4", children: quickViewProduct.description }), jsx(Badge, { variant: quickViewProduct.inStock ? 'success' : 'danger', className: "mb-4", children: quickViewProduct.inStock ? 'In Stock' : 'Out of Stock' })] })] }) }), jsxs(ModalFooter, { children: [jsx(Button, { variant: "outline", onClick: () => onProductClick?.(quickViewProduct), children: "View Details" }), jsxs(Button, { variant: "primary", onClick: () => handleAddToCart(quickViewProduct), disabled: !quickViewProduct.inStock, children: [jsx(ShoppingCart, { className: "mr-2 h-4 w-4" }), "Add to Cart"] })] })] })) })] }));
|
|
130
|
+
// Remove local ProductCard in favor of reusable ProductCard
|
|
131
|
+
return (jsxs("div", { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8", children: [jsxs("div", { className: "flex flex-col gap-4 lg:flex-row lg:items-center lg:justify-between mb-8", children: [jsxs("div", { children: [jsx("h1", { className: "text-3xl font-bold text-gray-900 mb-2", children: "All Products" }), jsxs("p", { className: "text-gray-600", children: ["Showing ", filteredProducts.length, " of ", productsData.length, " products"] })] }), jsx(MarketplaceControls, { searchQuery: searchQuery, onSearchChange: setSearchQuery ? setSearchQuery : () => { }, shouldFocusSearch: shouldFocusSearch, sortBy: sortBy, onSortChange: setSortBy, viewMode: viewMode, onViewModeChange: setViewMode, onShowFilters: () => setShowFilters(true), sortOptions: sortOptions })] }), jsx("div", { className: "flex gap-8", children: jsx("div", { className: "flex-1", children: paginatedProducts.length === 0 ? (jsxs("div", { className: "text-center py-12", children: [jsx("div", { className: "text-gray-400 mb-4", children: jsx(Search, { className: "h-16 w-16 mx-auto" }) }), jsx("h3", { className: "text-lg font-medium text-gray-900 mb-2", children: "No products found" }), jsx("p", { className: "text-gray-600 mb-4", children: "Try adjusting your search or filter criteria" }), jsx(Button, { variant: "outline", onClick: handleClearFilters, children: "Clear Filters" })] })) : (jsxs(Fragment, { children: [jsx("div", { className: `grid gap-3 sm:gap-6 ${viewMode === 'grid'
|
|
132
|
+
? 'grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4'
|
|
133
|
+
: 'grid-cols-1'}`, children: paginatedProducts.map((product) => (jsx("div", { className: "w-full max-w-xs mx-auto sm:max-w-none", children: jsx(ProductCard, { product: product, onProductClick: onProductClick, onAddToCart: handleAddToCart, onQuickView: () => setQuickViewProduct(product), onToggleWishlist: toggleWishlist, isWishlisted: wishlist.has(product.id), showQuickActions: true }) }, product.id))) }), totalPages > 1 && (jsxs("div", { className: "flex flex-wrap items-center justify-center gap-2 mt-8 sm:mt-12", children: [jsx(Button, { variant: "outline", onClick: () => setCurrentPage(prev => Math.max(1, prev - 1)), disabled: currentPage === 1, children: "Previous" }), Array.from({ length: Math.min(5, totalPages) }, (_, i) => {
|
|
134
|
+
const page = i + 1;
|
|
135
|
+
return (jsx(Button, { variant: currentPage === page ? 'primary' : 'outline', onClick: () => setCurrentPage(page), children: page }, page));
|
|
136
|
+
}), jsx(Button, { variant: "outline", onClick: () => setCurrentPage(prev => Math.min(totalPages, prev + 1)), disabled: currentPage === totalPages, children: "Next" })] }))] })) }) }), jsxs(Modal, { open: showFilters, onOpenChange: setShowFilters, children: [jsx(ModalHeader, { children: jsx(ModalTitle, { children: "Filters" }) }), jsx(ModalContent, { children: jsxs("div", { className: "space-y-6", children: [jsxs("div", { children: [jsx("h4", { className: "font-medium text-gray-900 mb-3", children: "Categories" }), jsx("div", { className: "space-y-2", children: filterOptions.categories.map((category, idx) => (jsxs("label", { className: "flex items-center space-x-2", children: [jsx(Checkbox, { checked: filters.categories.includes(category), onChange: (e) => {
|
|
137
|
+
const alreadyChecked = filters.categories.includes(category);
|
|
138
|
+
const newCategories = e.target.checked
|
|
139
|
+
? alreadyChecked
|
|
140
|
+
? filters.categories
|
|
141
|
+
: [...filters.categories, category]
|
|
142
|
+
: filters.categories.filter((c) => c !== category);
|
|
143
|
+
handleFilterChange('categories', newCategories);
|
|
144
|
+
} }), jsx("span", { className: "text-sm text-gray-700", children: category })] }, category))) })] }), jsxs("div", { children: [jsx("h4", { className: "font-medium text-gray-900 mb-3", children: "Brands" }), jsx("div", { className: "space-y-2", children: filterOptions.brands.map((brand, idx) => (jsxs("label", { className: "flex items-center space-x-2", children: [jsx(Checkbox, { checked: filters.brands.includes(brand), onChange: (e) => {
|
|
145
|
+
const alreadyChecked = filters.brands.includes(brand);
|
|
146
|
+
const newBrands = e.target.checked
|
|
147
|
+
? alreadyChecked
|
|
148
|
+
? filters.brands
|
|
149
|
+
: [...filters.brands, brand]
|
|
150
|
+
: filters.brands.filter((b) => b !== brand);
|
|
151
|
+
handleFilterChange('brands', newBrands);
|
|
152
|
+
} }), jsx("span", { className: "text-sm text-gray-700", children: brand })] }, brand))) })] }), jsxs("div", { children: [jsx("h4", { className: "font-medium text-gray-900 mb-3", children: "Vendors" }), jsx("div", { className: "space-y-2", children: filterOptions.vendors.map((vendor, idx) => (jsxs("label", { className: "flex items-center space-x-2", children: [jsx(Checkbox, { checked: filters.vendors.includes(vendor), onChange: (e) => {
|
|
153
|
+
const alreadyChecked = filters.vendors.includes(vendor);
|
|
154
|
+
const newVendors = e.target.checked
|
|
155
|
+
? alreadyChecked
|
|
156
|
+
? filters.vendors
|
|
157
|
+
: [...filters.vendors, vendor]
|
|
158
|
+
: filters.vendors.filter((v) => v !== vendor);
|
|
159
|
+
handleFilterChange('vendors', newVendors);
|
|
160
|
+
} }), jsx("span", { className: "text-sm text-gray-700", children: vendor })] }, vendor))) })] })] }) }), jsxs(ModalFooter, { children: [jsx(Button, { variant: "outline", onClick: handleClearFilters, children: "Clear All" }), jsx(Button, { variant: "primary", onClick: () => setShowFilters(false), children: "Apply Filters" })] })] }), jsx(Modal, { open: !!quickViewProduct, onOpenChange: () => setQuickViewProduct(null), size: "lg", children: quickViewProduct && (jsxs(Fragment, { children: [jsx(ModalHeader, { children: jsx(ModalTitle, { children: quickViewProduct.name }) }), jsx(ModalContent, { children: jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-6", children: [jsx("div", { className: "aspect-square bg-gray-100 rounded-lg overflow-hidden", children: jsx("img", { src: quickViewProduct.images[0], alt: quickViewProduct.name, className: "w-full h-full object-cover" }) }), jsxs("div", { children: [jsxs("div", { className: "flex items-center space-x-1 mb-2", children: [jsx(Star, { className: "h-4 w-4 text-yellow-400 fill-current" }), jsxs("span", { className: "text-sm text-gray-600", children: [quickViewProduct.rating, " (", quickViewProduct.reviewCount, " reviews)"] })] }), jsxs("div", { className: "flex items-center space-x-2 mb-4", children: [jsxs("span", { className: "text-2xl font-bold text-gray-900", children: ["$", quickViewProduct.price.toFixed(2)] }), quickViewProduct.originalPrice && (jsxs("span", { className: "text-lg text-gray-500 line-through", children: ["$", quickViewProduct.originalPrice.toFixed(2)] }))] }), jsx("p", { className: "text-gray-600 mb-4", children: quickViewProduct.description }), jsx(Badge, { variant: quickViewProduct.inStock ? 'success' : 'danger', className: "mb-4", children: quickViewProduct.inStock ? 'In Stock' : 'Out of Stock' })] })] }) }), jsxs(ModalFooter, { children: [jsx(Button, { variant: "outline", onClick: () => onProductClick?.(quickViewProduct), children: "View Details" }), jsxs(Button, { variant: "primary", onClick: () => handleAddToCart(quickViewProduct), disabled: !quickViewProduct.inStock, children: [jsx(ShoppingCart, { className: "mr-2 h-4 w-4" }), "Add to Cart"] })] })] })) })] }));
|
|
184
161
|
};
|
|
185
162
|
|
|
186
163
|
export { AllProductsView };
|