refactor(marketplace): Reduce lines

This commit is contained in:
alexsparkes
2024-06-18 15:38:05 +01:00
parent 9c900c6484
commit 8b5b6fe18a
6 changed files with 170 additions and 201 deletions

View File

@@ -0,0 +1,101 @@
import { motion } from 'framer-motion';
import variables from 'config/variables';
import { useState } from 'react';
import placeholderIcon from 'assets/icons/marketplace-placeholder.png';
import { useTab } from 'components/Elements/MainModal/backend/TabContext';
import { useMarketData } from 'features/marketplace/api/MarketplaceDataContext';
import { MdOpenInNew } from "react-icons/md";
function ItemCard({ item, type, onCollection, isCurator, cardStyle }) {
const { getItemData, selectedItem, setSelectedItem } = useMarketData();
const { setSubTab } = useTab();
item._onCollection = onCollection;
const SelectItem = () => {
getItemData(item.type, item.name).then((data) => {
setSubTab(data.display_name);
});
};
const getName = (name) => {
const nameMappings = {
photos: 'photo_packs',
quotes: 'quote_packs',
settings: 'preset_settings',
};
return nameMappings[name] || name;
};
switch (cardStyle) {
case 'list':
return (
<tr key={item.name} className="py-5 hover:bg-white/5 rounded-lg cursor-pointer" onClick={SelectItem}>
<td className="flex flex-row items-center gap-10 py-3">
<img
className="w-10 h-10 rounded-lg"
alt="icon"
draggable={false}
src={item.icon_url}
onError={(e) => {
e.target.onerror = null;
e.target.src = placeholderIcon;
}}
/>
{item.display_name}
</td>
<td>{variables.getMessage('marketplace:' + getName(item.type)) || 'marketplace'}</td>
<td>{item.author}</td>
<td><MdOpenInNew /></td>
</tr>
);
default:
return (
<motion.div
whileHover={{ y: -10 }}
transition={{ type: 'spring', stiffness: 150, damping: 15, mass: 0.5 }}
className="item"
onClick={SelectItem}
key={item.name}
>
<img
className="item-back"
alt=""
draggable={false}
src={item.icon_url}
onError={(e) => {
e.target.onerror = null;
e.target.src = placeholderIcon;
}}
aria-hidden="true"
/>
<img
className="item-icon"
alt="icon"
draggable={false}
src={item.icon_url}
onError={(e) => {
e.target.onerror = null;
e.target.src = placeholderIcon;
}}
/>
<div className="card-details">
<span className="card-title">{item.display_name || item.name}</span>
{!isCurator ? (
<span className="card-subtitle">
{variables.getMessage('marketplace:by', { author: item.author })}
</span>
) : (
''
)}
{type === true && !onCollection ? (
<span className="card-type">{variables.getMessage('marketplace:' + item.type)}</span>
) : null}
</div>
</motion.div>
);
}
}
export { ItemCard as default, ItemCard };

View File

@@ -0,0 +1 @@
export * from './ItemCard';

View File

@@ -1,3 +1,4 @@
export * from './Carousel';
export * from './SideloadFailedModal';
export * from './Lightbox';
export * from './ItemCard';

View File

@@ -1,106 +1,6 @@
import variables from 'config/variables';
import { motion } from 'framer-motion';
import { useState } from 'react';
import placeholderIcon from 'assets/icons/marketplace-placeholder.png';
import { useTab } from 'components/Elements/MainModal/backend/TabContext';
import { useMarketData } from 'features/marketplace/api/MarketplaceDataContext';
import { MdOpenInNew } from "react-icons/md";
function ItemCard({ item, type, onCollection, isCurator, cardStyle }) {
const { getItemData, selectedItem, setSelectedItem } = useMarketData();
const { setSubTab } = useTab();
item._onCollection = onCollection;
const SelectItem = () => {
console.log('Item selected: ', item.display_name);
console.log('Item type: ', item.type);
getItemData(item.type, item.name).then((data) => {
console.log('Selected item: ', data);
//setSelectedItem(data);
setSubTab(data.display_name);
});
};
const getName = (name) => {
const nameMappings = {
photos: 'photo_packs',
quotes: 'quote_packs',
settings: 'preset_settings',
};
return nameMappings[name] || name;
};
switch (cardStyle) {
case 'list':
return (
<tr key={item.name} className="py-5 hover:bg-white/5 rounded-lg cursor-pointer" onClick={SelectItem}>
<td className="flex flex-row items-center gap-10 py-3">
<img
className="w-10 h-10 rounded-lg"
alt="icon"
draggable={false}
src={item.icon_url}
onError={(e) => {
e.target.onerror = null;
e.target.src = placeholderIcon;
}}
/>
{item.display_name}
</td>
<td>{variables.getMessage('marketplace:' + getName(item.type)) || 'marketplace'}</td>
<td>{item.author}</td>
<td><MdOpenInNew /></td>
</tr>
);
default:
return (
<motion.div
whileHover={{ y: -10 }}
transition={{ type: 'spring', stiffness: 150, damping: 15, mass: 0.5 }}
className="item"
onClick={SelectItem}
key={item.name}
>
<img
className="item-back"
alt=""
draggable={false}
src={item.icon_url}
onError={(e) => {
e.target.onerror = null;
e.target.src = placeholderIcon;
}}
aria-hidden="true"
/>
<img
className="item-icon"
alt="icon"
draggable={false}
src={item.icon_url}
onError={(e) => {
e.target.onerror = null;
e.target.src = placeholderIcon;
}}
/>
<div className="card-details">
<span className="card-title">{item.display_name || item.name}</span>
{!isCurator ? (
<span className="card-subtitle">
{variables.getMessage('marketplace:by', { author: item.author })}
</span>
) : (
''
)}
{type === true && !onCollection ? (
<span className="card-type">{variables.getMessage('marketplace:' + item.type)}</span>
) : null}
</div>
</motion.div>
);
}
}
import { ItemCard } from 'features/marketplace/components/Elements';
const NewItems = ({ items, view }) => {
const { setSubTab } = useTab();

View File

@@ -1,10 +1,9 @@
import { memo, useEffect, useState } from 'react';
import { memo, useCallback, useEffect, useState } from 'react';
import variables from 'config/variables';
import { useMarketData } from 'features/marketplace/api/MarketplaceDataContext';
import MarketplaceTab from '../../marketplace/views/Browse';
import { useTab } from 'components/Elements/MainModal/backend/TabContext';
import { ItemPage } from '../../marketplace/views/ItemPage';
import { NewItems as Items } from '../../marketplace/components/Items/Items';
@@ -13,91 +12,71 @@ import Collection from '../../marketplace/components/Collection/Collection';
import clsx from 'clsx';
import { PiGridFourFill } from 'react-icons/pi';
import {
MdFormatListBulleted,
MdFilterListAlt,
MdOutlineArrowForward,
MdOutlineOpenInNew,
} from 'react-icons/md';
import { MdFormatListBulleted } from 'react-icons/md';
const filterTypes = [
{ key: 'all', label: 'marketplace:photo_packs' },
{ key: 'photo_packs', label: 'marketplace:photo_packs' },
{ key: 'quote_packs', label: 'marketplace:quote_packs' },
{ key: 'preset_settings', label: 'marketplace:preset_settings' },
];
const filterItems = (items, filter) => {
if (filter === 'all') return items;
return items.filter((item) => item.type === filter);
};
function Marketplace(props) {
const { done, items, collections, getItems, getCollections, selectedItem } = useMarketData();
const {
done,
items = [],
collections = [],
getItems,
getCollections,
selectedItem,
} = useMarketData();
const { subTab } = useTab();
const [itemsView, setItemsView] = useState('grid');
const [itemsFilter, setItemsFilter] = useState('all');
const [filteredItems, setFilteredItems] = useState([]);
const [sortItems, setSortItems] = useState('a-z');
const FilterOptions = () => {
return (
<div className="flex flex-row gap-2 my-3">
<div
onClick={() => {
setItemsFilter('all');
}}
className={clsx(
'cursor-pointer transition-all duration-200 rounded-full px-6 py-2 text-base ',
{
'bg-white text-black': itemsFilter === 'all',
'bg-[#333] hover:bg-[#222222] text-white cursor:pointer': itemsFilter !== 'all',
},
)}
>
All
</div>
<div
onClick={() => {
setItemsFilter('photo_packs');
}}
className={clsx(
'cursor-pointer transition-all duration-200 rounded-full px-6 py-2 text-base ',
{
'bg-white text-black': itemsFilter === 'photo_packs',
'bg-[#333] hover:bg-[#222222] text-white cursor:pointer':
itemsFilter !== 'photo_packs',
},
)}
>
{variables.getMessage('marketplace:photo_packs') || 'marketplace'}
</div>
<div
onClick={() => {
setItemsFilter('quote_packs');
}}
className={clsx(
'cursor-pointer transition-all duration-200 rounded-full px-6 py-2 text-base ',
{
'bg-white text-black': itemsFilter === 'quote_packs',
'bg-[#333] hover:bg-[#222222] text-white': itemsFilter !== 'quote_packs',
},
)}
>
{variables.getMessage('marketplace:quote_packs') || 'marketplace'}
</div>
<div
onClick={() => {
setItemsFilter('preset_settings');
}}
className={clsx(
'cursor-pointer transition-all duration-200 rounded-full px-6 py-2 text-base ',
{
'bg-white text-black': itemsFilter === 'preset_settings',
'bg-[#333] hover:bg-[#222222] text-white': itemsFilter !== 'preset_settings',
},
)}
>
{variables.getMessage('marketplace:preset_settings') || 'marketplace'}
</div>
</div>
);
const fetchMarketData = async () => {
try {
await getItems();
await getCollections();
} catch (error) {
console.error('Error fetching market data:', error);
}
};
const ItemView = () => {
const FilterOptions = useCallback(() => {
return (
<div className="flex flex-row gap-2 my-3">
{filterTypes.map(({ key, label }) => (
<div
key={key}
onClick={() => setItemsFilter(key)}
className={clsx(
'cursor-pointer transition-all duration-200 rounded-full px-6 py-2 text-base',
{
'bg-white text-black': itemsFilter === key,
'bg-[#333] hover:bg-[#222222] text-white': itemsFilter !== key,
},
)}
>
{key !== 'all' ? <>{variables.getMessage(`${label}`) || 'marketplace'}</> : <>All</>}
</div>
))}
</div>
);
}, [itemsFilter]);
const ItemView = useCallback(
() => (
<div className="flex flex-row gap-2">
<button
onClick={() => setItemsView('grid')}
className={clsx('cursor:pointer h-[40px] w-[40px] grid place-items-center rounded-lg', {
className={clsx('cursor-pointer h-[40px] w-[40px] grid place-items-center rounded-lg', {
'bg-[#333]': itemsView === 'grid',
})}
>
@@ -105,42 +84,27 @@ function Marketplace(props) {
</button>
<button
onClick={() => setItemsView('list')}
className={clsx('cursor:pointer h-[40px] w-[40px] grid place-items-center rounded-lg', {
className={clsx('cursor-pointer h-[40px] w-[40px] grid place-items-center rounded-lg', {
'bg-[#333]': itemsView === 'list',
})}
>
<MdFormatListBulleted />
</button>
</div>
);
};
),
[itemsView],
);
useEffect(() => {
if (navigator.onLine === false || localStorage.getItem('offlineMode') === 'true') {
return;
}
getItems();
getCollections();
}, []); // Only runs once when the component mounts
fetchMarketData();
}, []);
useEffect(() => {
switch (itemsFilter) {
case 'all':
setFilteredItems(items);
break;
case 'photo_packs':
setFilteredItems(items.filter((item) => item.type === 'photo_packs'));
break;
case 'quote_packs':
setFilteredItems(items.filter((item) => item.type === 'quote_packs'));
break;
case 'preset_settings':
setFilteredItems(items.filter((item) => item.type === 'preset_settings'));
break;
default:
setFilteredItems(items);
}
}, [itemsFilter, items]); // Only depends on itemsFilter and items
setFilteredItems(filterItems(items, itemsFilter));
}, [itemsFilter, items]);
return (
<AnimatePresence mode="wait">
@@ -156,8 +120,10 @@ function Marketplace(props) {
<Collection collections={collections} />
<motion.div key="items">
<div className="w-full flex flex-row justify-between items-center">
{FilterOptions()}
<div className="flex flex-row gap-2">{ItemView()}</div>
<FilterOptions />
<div className="flex flex-row gap-2">
<ItemView />
</div>
</div>
<Items items={filteredItems} view={itemsView} />
</motion.div>

View File

@@ -73,7 +73,7 @@ modals:
navbar:
settings: Settings
addons: Library
marketplace: Marketplace
marketplace: Discover
error_boundary:
title: Error
message: Failed to load this component of Mue