Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 34 additions & 1 deletion src/app-bundles/product-filter-bundle.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const productFilterBundle = {
dateFrom: new Date(),
dateTo: new Date(),
tags: [],
requiredTags: [], // Tags that products MUST have (AND logic)
parameters: [],
};

Expand Down Expand Up @@ -45,6 +46,10 @@ const productFilterBundle = {
return state.productFilter.tags;
},

selectProductFilterRequiredTags: (state) => {
return state.productFilter.requiredTags;
},

selectProductFilterParameters: (state) => {
return state.productFilter.parameters;
},
Expand All @@ -56,6 +61,7 @@ const productFilterBundle = {
'selectProductFilterDateFrom',
'selectProductFilterDateTo',
'selectProductFilterTags',
'selectProductFilterRequiredTags',
'selectProductFilterParameters',
(
items,
Expand All @@ -64,8 +70,14 @@ const productFilterBundle = {
dateFrom,
dateTo,
tags,
requiredTags,
parameters
) => {
// Safety check - if items is not available yet, return empty array
if (!items || !Array.isArray(items)) {
return [];
}

return items.filter((product) => {
let pass = true;

Expand Down Expand Up @@ -96,7 +108,17 @@ const productFilterBundle = {
}
}

// apply tag filters
// apply required tag filters (must have ALL of these tags - AND logic)
if (pass && requiredTags.length > 0) {
for (var r = 0; r < requiredTags.length; r++) {
if (product.tags.indexOf(requiredTags[r]) === -1) {
pass = false;
break;
}
}
}

// apply tag filters (must have ANY of these tags - OR logic)
if (pass && tags.length > 0) {
let matchFound = false;
for (var t = 0; t < product.tags.length; t++) {
Expand Down Expand Up @@ -174,6 +196,17 @@ const productFilterBundle = {
});
},

doProductFilterSetRequiredTags:
(requiredTags) =>
({ dispatch }) => {
dispatch({
type: 'PRODUCT_FILTER_SET_VALUE',
payload: {
requiredTags,
},
});
},

doProductFilterSetParameters:
(parameters) =>
({ dispatch }) => {
Expand Down
59 changes: 59 additions & 0 deletions src/app-pages/products/products.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,13 @@ export default connect(
'selectProductDateRangeFrom',
'selectProductDateRangeTo',
'selectProductSelectSelected',
'selectProductFilterRequiredTags',
'doModalOpen',
'doProductFilterSetFilterString',
'doProductFilterSetDateFrom',
'doProductFilterSetDateTo',
'doProductFilterSetApplyDateFilter',
'doProductFilterSetRequiredTags',
({
authIsLoggedIn,
productFilterResults: products,
Expand All @@ -43,12 +45,17 @@ export default connect(
productDateRangeFrom: rangeFrom,
productDateRangeTo: rangeTo,
productSelectSelected: selectedProducts,
productFilterRequiredTags: requiredTags,
doModalOpen,
doProductFilterSetFilterString: setFilterString,
doProductFilterSetDateFrom: setFilterDateFrom,
doProductFilterSetDateTo: setFilterDateTo,
doProductFilterSetApplyDateFilter: setApplyDateFilter,
doProductFilterSetRequiredTags: setRequiredTags,
}) => {
// Tab state - 'primary' or 'all'
const [activeTab, setActiveTab] = useState('primary');

// show / hide the filter panel
const [filtersActive, setFiltersActive] = useState(false);

Expand Down Expand Up @@ -118,6 +125,31 @@ export default connect(
doModalOpen(DownloadModal);
}, [doModalOpen]);

// Handle tab switching and apply tag filter accordingly
const handleTabChange = useCallback((tab) => {
setActiveTab(tab);
const primarySourceTagId = '8a7f4e6b-3c2d-4a9f-b1e5-9d8c7a6f5e4d';

if (tab === 'primary') {
// Require "primary source" tag (exclusive filter)
if (!requiredTags.includes(primarySourceTagId)) {
setRequiredTags([...requiredTags, primarySourceTagId]);
}
} else {
// Remove "primary source" from required tags to show all sources
setRequiredTags(requiredTags.filter(tag => tag !== primarySourceTagId));
}
}, [setRequiredTags, requiredTags]);

// Apply the initial filter when component mounts
useEffect(() => {
const primarySourceTagId = '8a7f4e6b-3c2d-4a9f-b1e5-9d8c7a6f5e4d';
// Only initialize once
if (activeTab === 'primary' && requiredTags.length === 0) {
setRequiredTags([primarySourceTagId]);
}
}, [activeTab, requiredTags, setRequiredTags]);

return (
<>
<div className='m-5 mb-5 inline-flex'>
Expand Down Expand Up @@ -346,6 +378,33 @@ export default connect(
</div>
) : null}


{/* Tab Navigation */}
<div className='border-b border-gray-200 mx-5 mt-5'>
<nav className='-mb-px flex space-x-8' aria-label='Tabs'>
<button
onClick={() => handleTabChange('primary')}
className={`${
activeTab === 'primary'
? 'border-indigo-500 text-indigo-600'
: 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300'
} whitespace-nowrap py-4 px-1 border-b-2 font-medium text-sm`}
>
Primary Sources
</button>
<button
onClick={() => handleTabChange('all')}
className={`${
activeTab === 'all'
? 'border-indigo-500 text-indigo-600'
: 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300'
} whitespace-nowrap py-4 px-1 border-b-2 font-medium text-sm`}
>
All Sources
</button>
</nav>
</div>

<div className='flex-grow w-full mt-5 overflow-x-hidden max-h-full'>
<div className='flex-1 min-w-0 flex'>
{filtersActive ? (
Expand Down