From 152423b65aefd44e204edc1bc4d2738d95d2a654 Mon Sep 17 00:00:00 2001 From: Sam Chau Date: Thu, 9 Jan 2025 01:47:56 +1030 Subject: [PATCH] feat: refactor data actions into new DataBar component --- frontend/src/components/format/FormatPage.jsx | 65 ++----- .../src/components/profile/ProfilePage.jsx | 164 ++++++++---------- .../components/profile/ProfileScoringTab.jsx | 2 +- frontend/src/components/regex/RegexPage.jsx | 66 ++----- .../components/settings/arrs/ArrContainer.jsx | 2 +- frontend/src/components/ui/AddButton.jsx | 42 ----- .../src/components/ui/DataBar/AddButton.jsx | 16 ++ .../src/components/ui/DataBar/DataBar.jsx | 102 +++++++++++ .../ui/{ => DataBar}/FilterMenu.jsx | 0 .../components/ui/{ => DataBar}/SearchBar.jsx | 0 .../ui/{ => DataBar}/SortDropdown.jsx | 0 .../ui/DataBar/ToggleSelectButton.jsx | 24 +++ 12 files changed, 255 insertions(+), 228 deletions(-) delete mode 100644 frontend/src/components/ui/AddButton.jsx create mode 100644 frontend/src/components/ui/DataBar/AddButton.jsx create mode 100644 frontend/src/components/ui/DataBar/DataBar.jsx rename frontend/src/components/ui/{ => DataBar}/FilterMenu.jsx (100%) rename frontend/src/components/ui/{ => DataBar}/SearchBar.jsx (100%) rename frontend/src/components/ui/{ => DataBar}/SortDropdown.jsx (100%) create mode 100644 frontend/src/components/ui/DataBar/ToggleSelectButton.jsx diff --git a/frontend/src/components/format/FormatPage.jsx b/frontend/src/components/format/FormatPage.jsx index 7586628..d3d7358 100644 --- a/frontend/src/components/format/FormatPage.jsx +++ b/frontend/src/components/format/FormatPage.jsx @@ -2,27 +2,24 @@ import React, {useState, useEffect} from 'react'; import {useNavigate} from 'react-router-dom'; import FormatCard from './FormatCard'; import FormatModal from './FormatModal'; -import AddButton from '@ui/AddButton'; import {getGitStatus} from '@api/api'; import {CustomFormats} from '@api/data'; -import FilterMenu from '@ui/FilterMenu'; -import SortMenu from '@ui/SortMenu'; -import {Loader, CheckSquare} from 'lucide-react'; +import {Loader} from 'lucide-react'; import Alert from '@ui/Alert'; -import SearchBar from '@ui/SearchBar'; import {useFormatModal} from '@hooks/useFormatModal'; import {useMassSelection} from '@hooks/useMassSelection'; import {useKeyboardShortcut} from '@hooks/useKeyboardShortcut'; import MassActionsBar from '@ui/MassActionsBar'; import ImportModal from '@ui/ImportModal'; import {importFormats} from '@api/import'; +import DataBar from '@ui/DataBar/DataBar'; function FormatPage() { // Basic state management const [formats, setFormats] = useState([]); const [isModalOpen, setIsModalOpen] = useState(false); const [selectedFormat, setSelectedFormat] = useState(null); - const [sortBy, setSortBy] = useState('title'); + const [sortBy, setSortBy] = useState('name'); const [filterType, setFilterType] = useState('none'); const [filterValue, setFilterValue] = useState(''); const [allTags, setAllTags] = useState([]); @@ -213,7 +210,6 @@ function FormatPage() { ); } - // Rest of the sorting logic remains the same... return filtered.sort((a, b) => { switch (sortBy) { case 'dateModified': @@ -276,37 +272,21 @@ function FormatPage() { return (
-
- -
- -
-
- -
-
- -
-
+ handleOpenModal()} + addButtonLabel='Add New Format' + />
{filteredFormats.map((format, index) => ( @@ -330,15 +310,6 @@ function FormatPage() { ))}
- {!isSelectionMode && ( - handleOpenModal()} - label='Add New Format' - top='5vh' - left='75vw' - /> - )} - {isSelectionMode && ( ({ - id: item.content.name, // Use name as ID + id: item.content.name, name: item.content.name, description: item.content.description || '', tags: item.content.tags || [] @@ -175,7 +172,6 @@ function ProfilePage() { const handleMassImport = async arr => { try { - // Use the identifier to find the correct profile const selectedProfiles = Array.from(selectedItems).map(identifier => profiles.find(p => p.content.name === identifier) ); @@ -193,48 +189,61 @@ function ProfilePage() { } }; + const getFilteredAndSortedProfiles = () => { + return profiles + .filter(profile => { + // Apply search filter + if (searchQuery) { + return ( + profile.content.name + .toLowerCase() + .includes(searchQuery.toLowerCase()) || + profile.content.tags?.some(tag => + tag + .toLowerCase() + .includes(searchQuery.toLowerCase()) + ) + ); + } + + // Apply existing filters + if (filterType === 'tag') { + return ( + profile.content.tags && + profile.content.tags.includes(filterValue) + ); + } + if (filterType === 'date') { + const profileDate = new Date(profile.modified_date); + const filterDate = new Date(filterValue); + return ( + profileDate.toDateString() === filterDate.toDateString() + ); + } + return true; + }) + .sort((a, b) => { + switch (sortBy) { + case 'dateModified': + return ( + new Date(b.modified_date) - + new Date(a.modified_date) + ); + case 'dateCreated': + return ( + new Date(b.created_date) - new Date(a.created_date) + ); + case 'name': + default: + return a.content.name.localeCompare(b.content.name); + } + }); + }; + const formatDate = dateString => { return new Date(dateString).toLocaleString(); }; - const sortedAndFilteredProfiles = profiles - .filter(profile => { - // Apply search filter - if (searchQuery) { - return ( - profile.content.name - .toLowerCase() - .includes(searchQuery.toLowerCase()) || - profile.content.tags?.some(tag => - tag.toLowerCase().includes(searchQuery.toLowerCase()) - ) - ); - } - - // Apply existing filters - if (filterType === 'tag') { - return ( - profile.content.tags && - profile.content.tags.includes(filterValue) - ); - } - if (filterType === 'date') { - const profileDate = new Date(profile.modified_date); - const filterDate = new Date(filterValue); - return profileDate.toDateString() === filterDate.toDateString(); - } - return true; - }) - .sort((a, b) => { - if (sortBy === 'name') - return a.content.name.localeCompare(b.content.name); - if (sortBy === 'dateCreated') - return new Date(b.created_date) - new Date(a.created_date); - if (sortBy === 'dateModified') - return new Date(b.modified_date) - new Date(a.modified_date); - return 0; - }); - if (isLoading) { return (
@@ -278,42 +287,28 @@ function ProfilePage() { ); } + const filteredProfiles = getFilteredAndSortedProfiles(); + return (
-
- -
- -
-
- -
-
- -
-
+ handleOpenModal()} + addButtonLabel='Add New Profile' + />
- {sortedAndFilteredProfiles.map((profile, index) => ( + {filteredProfiles.map((profile, index) => ( ))}
- {!isSelectionMode && ( - handleOpenModal()} - label='Add New Profile' - top='5vh' - left='75vw' - /> - )} - {isSelectionMode && ( { loadPatterns(); }, []); @@ -143,7 +138,6 @@ function RegexPage() { ); } - // Rest of the sorting logic remains the same... return filtered.sort((a, b) => { switch (sortBy) { case 'dateModified': @@ -173,37 +167,21 @@ function RegexPage() { return (
-
- -
- -
-
- -
-
- -
-
+ handleOpenModal()} + addButtonLabel='Add New Pattern' + />
{getFilteredAndSortedPatterns().map((pattern, index) => ( @@ -221,14 +199,6 @@ function RegexPage() { } /> ))} - {!isSelectionMode && ( - handleOpenModal()} - label='Add New Pattern' - top='5vh' - left='75vw' - /> - )}
{isSelectionMode && ( diff --git a/frontend/src/components/settings/arrs/ArrContainer.jsx b/frontend/src/components/settings/arrs/ArrContainer.jsx index 0b339ed..af0af82 100644 --- a/frontend/src/components/settings/arrs/ArrContainer.jsx +++ b/frontend/src/components/settings/arrs/ArrContainer.jsx @@ -2,7 +2,7 @@ import React, {useState, useEffect} from 'react'; import {Loader} from 'lucide-react'; import ArrModal from './ArrModal'; import ArrCard from './ArrCard'; -import AddButton from '@ui/AddButton'; +import AddButton from '@ui/DataBar/AddButton'; import {getArrConfigs} from '@api/arr'; const ArrContainer = () => { diff --git a/frontend/src/components/ui/AddButton.jsx b/frontend/src/components/ui/AddButton.jsx deleted file mode 100644 index 014d210..0000000 --- a/frontend/src/components/ui/AddButton.jsx +++ /dev/null @@ -1,42 +0,0 @@ -import React from 'react'; -import {Plus} from 'lucide-react'; - -const AddButton = ({onClick, label = 'Add New', top, right, bottom, left}) => { - const positionStyle = { - position: 'fixed', - zIndex: 50, - ...(top !== undefined && { - top: typeof top === 'number' ? `${top}px` : top - }), - ...(right !== undefined && { - right: typeof right === 'number' ? `${right}px` : right - }), - ...(bottom !== undefined && { - bottom: typeof bottom === 'number' ? `${bottom}px` : bottom - }), - ...(left !== undefined && { - left: typeof left === 'number' ? `${left}px` : left - }) - }; - - return ( -
-
-
- -
-
- - {label} - -
-
-
- ); -}; - -export default AddButton; diff --git a/frontend/src/components/ui/DataBar/AddButton.jsx b/frontend/src/components/ui/DataBar/AddButton.jsx new file mode 100644 index 0000000..4060d63 --- /dev/null +++ b/frontend/src/components/ui/DataBar/AddButton.jsx @@ -0,0 +1,16 @@ +import React from 'react'; +import {Plus} from 'lucide-react'; + +const AddButton = ({onClick, label = 'Add New'}) => { + return ( + + ); +}; + +export default AddButton; diff --git a/frontend/src/components/ui/DataBar/DataBar.jsx b/frontend/src/components/ui/DataBar/DataBar.jsx new file mode 100644 index 0000000..b595971 --- /dev/null +++ b/frontend/src/components/ui/DataBar/DataBar.jsx @@ -0,0 +1,102 @@ +import React, {useState, useEffect} from 'react'; +import SearchBar from './SearchBar'; +import FilterMenu from './FilterMenu'; +import {SortDropdown} from './SortDropdown'; +import ToggleSelectButton from './ToggleSelectButton'; +import AddButton from './AddButton'; + +const DataBar = ({ + onSearch, + searchPlaceholder = 'Search by name or tag...', + filterType, + setFilterType, + filterValue, + setFilterValue, + allTags, + sortBy, + setSortBy, + isSelectionMode, + toggleSelectionMode, + onAdd, + addButtonLabel = 'Add New', + showAddButton = true +}) => { + const [isFloating, setIsFloating] = useState(false); + const [isVisible, setIsVisible] = useState(true); + const [lastScrollY, setLastScrollY] = useState(0); + + useEffect(() => { + const handleScroll = () => { + const currentScrollY = window.scrollY; + + // Show/hide based on scroll direction + setIsVisible(currentScrollY <= 0 || currentScrollY < lastScrollY); + + // Start floating once we scroll past the initial position + setIsFloating(currentScrollY > 64); // Approximately the height of the bar + + setLastScrollY(currentScrollY); + }; + + window.addEventListener('scroll', handleScroll, {passive: true}); + return () => window.removeEventListener('scroll', handleScroll); + }, [lastScrollY]); + + return ( +
+
+ + +
+ setSortBy(key)} + /> +
+ +
+ +
+ +
+ +
+ + {showAddButton && !isSelectionMode && ( +
+ +
+ )} +
+
+ ); +}; + +export default DataBar; diff --git a/frontend/src/components/ui/FilterMenu.jsx b/frontend/src/components/ui/DataBar/FilterMenu.jsx similarity index 100% rename from frontend/src/components/ui/FilterMenu.jsx rename to frontend/src/components/ui/DataBar/FilterMenu.jsx diff --git a/frontend/src/components/ui/SearchBar.jsx b/frontend/src/components/ui/DataBar/SearchBar.jsx similarity index 100% rename from frontend/src/components/ui/SearchBar.jsx rename to frontend/src/components/ui/DataBar/SearchBar.jsx diff --git a/frontend/src/components/ui/SortDropdown.jsx b/frontend/src/components/ui/DataBar/SortDropdown.jsx similarity index 100% rename from frontend/src/components/ui/SortDropdown.jsx rename to frontend/src/components/ui/DataBar/SortDropdown.jsx diff --git a/frontend/src/components/ui/DataBar/ToggleSelectButton.jsx b/frontend/src/components/ui/DataBar/ToggleSelectButton.jsx new file mode 100644 index 0000000..fef7935 --- /dev/null +++ b/frontend/src/components/ui/DataBar/ToggleSelectButton.jsx @@ -0,0 +1,24 @@ +import React from 'react'; +import {CheckSquare} from 'lucide-react'; + +const ToggleSelectButton = ({ + isSelectionMode, + onClick, + shortcutKey = 'A' // Default to 'A' since that's what's used in the pages +}) => { + return ( + + ); +}; + +export default ToggleSelectButton;