// #region [Imports] =================================================================================================== import { useEffect, useState, useMemo, useCallback } from 'react'; import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; // Types import { ICouponTemplateListItem } from '../../types/couponTemplates'; import { IStore } from '../../types/store'; // Actions import { CouponTemplatesActions } from '../../store/actions/couponTemplates'; // Components import TemplatesSkeleton from './TemplatesSkeleton'; import TemplatesList from './TemplatesList'; import SearchFilter from './SearchFilter'; // #endregion [Imports] // #region [Variables] ================================================================================================= const { readRecentCouponTemplates, setSearchFilters, setSortOptions } = CouponTemplatesActions; // #endregion [Variables] // #region [Interfaces]================================================================================================= interface IActions { readRecentCouponTemplates: typeof readRecentCouponTemplates; setSearchFilters: typeof setSearchFilters; setSortOptions: typeof setSortOptions; } interface IProps { templates: ICouponTemplateListItem[]; searchFilters: { searchTerm: string; licenseFilter: string; }; sortOptions: { sortBy: 'title' | 'date'; sortOrder: 'asc' | 'desc'; }; actions: IActions; } // #endregion [Interfaces] // #region [Component] ================================================================================================= const RecentTemplates = (props: IProps) => { const { templates, searchFilters, sortOptions, actions } = props; const [loading, setLoading] = useState(false); // Filter and sort templates based on search criteria and sort options const filteredTemplates = useMemo(() => { let filtered = [...templates]; // Filter by search term (title and description) if (searchFilters.searchTerm.trim()) { const searchTerm = searchFilters.searchTerm.toLowerCase().trim(); filtered = filtered.filter( (template) => template.title.toLowerCase().includes(searchTerm) || template.description.toLowerCase().includes(searchTerm) ); } // Filter by license type if (searchFilters.licenseFilter !== 'all') { filtered = filtered.filter((template) => template.license_type === searchFilters.licenseFilter); } // Sort templates filtered.sort((a, b) => { let comparison = 0; switch (sortOptions.sortBy) { case 'title': comparison = a.title.localeCompare(b.title); break; case 'date': const dateA = a.date ? new Date(a.date).getTime() : 0; const dateB = b.date ? new Date(b.date).getTime() : 0; comparison = dateA - dateB; break; default: comparison = 0; } return sortOptions.sortOrder === 'desc' ? -comparison : comparison; }); return filtered; }, [templates, searchFilters, sortOptions]); const handleSearchChange = useCallback( (searchTerm: string) => { actions.setSearchFilters({ searchTerm, licenseFilter: searchFilters.licenseFilter, }); }, [actions, searchFilters.licenseFilter] ); const handleLicenseFilterChange = useCallback( (licenseFilter: string) => { actions.setSearchFilters({ searchTerm: searchFilters.searchTerm, licenseFilter, }); }, [actions, searchFilters.searchTerm] ); const handleSortByChange = useCallback( (sortBy: 'title' | 'date') => { actions.setSortOptions({ sortBy, sortOrder: sortOptions.sortOrder, }); }, [actions, sortOptions.sortOrder] ); const handleSortOrderChange = useCallback( (sortOrder: 'asc' | 'desc') => { actions.setSortOptions({ sortBy: sortOptions.sortBy, sortOrder, }); }, [actions, sortOptions.sortBy] ); useEffect(() => { setLoading(true); actions.readRecentCouponTemplates({ successCB: () => setLoading(false) }); }, [actions]); if (loading) { return ( <> ); } return ( <> ); }; const mapStateToProps = (state: IStore) => ({ templates: state.couponTemplates?.recent ?? [], searchFilters: state.couponTemplates?.searchFilters ?? { searchTerm: '', licenseFilter: 'all' }, sortOptions: state.couponTemplates?.sortOptions ?? { sortBy: 'title', sortOrder: 'asc' }, }); const mapDispatchToProps = (dispatch: any) => ({ actions: bindActionCreators({ readRecentCouponTemplates, setSearchFilters, setSortOptions }, dispatch), }); export default connect(mapStateToProps, mapDispatchToProps)(RecentTemplates); // #endregion [Component]