refactor(marketplace): Context for marketplace data

This commit is contained in:
alexsparkes
2024-06-18 11:04:51 +01:00
parent 81b88e0846
commit 3f2f3fdfa3
8 changed files with 144 additions and 158 deletions

View File

@@ -0,0 +1,53 @@
import React, { createContext, useContext, useState, useEffect } from 'react';
import variables from 'config/variables';
import { sortItems } from '../../marketplace/api';
const MarketDataContext = createContext();
export const useMarketData = () => useContext(MarketDataContext);
export const MarketplaceDataProvider = ({ children }) => {
const [done, setDone] = useState(false);
const [items, setItems] = useState([]);
const [selectedItem, setSelectedItem] = useState(null);
const controller = new AbortController();
const getItems = async (type = 'all') => {
setDone(false);
const dataURL =
variables.constants.API_URL +
(type === 'collections' ? '/marketplace/collections' : '/marketplace/items/' + type);
const { data } = await (
await fetch(dataURL, {
signal: controller.signal,
})
).json();
if (controller.signal.aborted === true) {
return;
}
setItems(sortItems(data, 'z-a'));
setDone(true);
};
const getItemData = async (itemType, itemName) => {
const response = await fetch(
`${variables.constants.API_URL}/marketplace/item/${itemType}/${itemName}`,
{
signal: controller.signal,
},
);
const item = await response.json();
setSelectedItem(item.data);
return new Promise((resolve) => {
resolve(item.data);
});
};
return (
<MarketDataContext.Provider value={{ done, items, selectedItem, getItems, getItemData, setSelectedItem }}>
{children}
</MarketDataContext.Provider>
);
};

View File

@@ -3,15 +3,30 @@ 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';
function ItemCard({ item, onClick, type, onCollection, isCurator }) {
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);
});
}
return (
<motion.div
whileHover={{ y: -10 }}
transition={{ type: 'spring', stiffness: 150, damping: 15, mass: 0.5 }}
className="item"
onClick={onClick}
onClick={SelectItem}
key={item.name}
>
<img

View File

@@ -20,6 +20,8 @@ import { Header } from 'components/Layout/Settings';
import Modal from 'react-modal';
import Markdown from 'markdown-to-jsx';
import { Button } from 'components/Elements';
import { useMarketData } from 'features/marketplace/api/MarketplaceDataContext';
import { Carousel } from '../components/Elements/Carousel';
const NewItemPage = () => {
const { subTab } = useTab();
@@ -27,51 +29,16 @@ const NewItemPage = () => {
const [count, setCount] = useState(5);
const [item, setItemData] = useState(null);
const [shareModal, setShareModal] = useState(false);
const { selectedItem } = useMarketData();
async function getItemData() {
let testType = 'quote_packs';
// Fetch data from API
const response = await fetch(
`${variables.constants.API_URL}/marketplace/item/${testType}/${subTab}`,
{
signal: controller.signal,
},
);
const item = await response.json();
console.log(item);
const { data } = item;
return {
data,
const getName = (name) => {
const nameMappings = {
photos: 'photo_packs',
quotes: 'quote_packs',
settings: 'preset_settings',
};
}
useEffect(() => {
async function fetchData() {
const data = await getItemData();
setItemData(data.data);
}
fetchData();
}, []);
if (!item) {
return null; // or a loading spinner
}
const {
onCollection,
type,
display_name,
author,
description,
version,
icon,
data,
local,
slug,
} = item;
return nameMappings[name] || name;
};
const moreInfoItem = (icon, header, text) => (
<div className="infoItem">
@@ -118,45 +85,45 @@ const NewItemPage = () => {
{variables.getMessage('marketplace:product.details')}
</span>
<div className="moreInfo">
{item?.updated_at &&
{selectedItem?.updated_at &&
moreInfoItem(
<MdCalendarMonth />,
variables.getMessage('marketplace:product.updated_at'),
formattedDate,
)}
{item?.quotes &&
{selectedItem?.quotes &&
moreInfoItem(
<MdFormatQuote />,
variables.getMessage('marketplace:product.no_quotes'),
item.quotes.length,
selectedItem.quotes.length,
)}
{item?.photos &&
{selectedItem?.photos &&
moreInfoItem(
<MdImage />,
variables.getMessage('marketplace:product.no_images'),
item.photos.length,
selectedItem.photos.length,
)}
{item?.quotes && item?.language
{selectedItem?.quotes && selectedItem?.language
? moreInfoItem(
<MdTranslate />,
variables.getMessage('settings:sections.language.title'),
languageNames.of(item.language),
languageNames.of(selectedItem.language),
)
: null}
{/*{moreInfoItem(
{moreInfoItem(
<MdStyle />,
variables.getMessage('settings:sections.background.type.title'),
variables.getMessage(
'marketplace:' + this.getName(this.props.data.data.type),
'marketplace:' + getName(selectedItem.type),
) || 'marketplace',
)}*/}
)}
</div>
</div>
);
};
const ItemShowcase = () => {
switch (item.type) {
switch (selectedItem.type) {
case 'quotes':
return (
<>
@@ -166,7 +133,7 @@ const NewItemPage = () => {
<th>{variables.getMessage('settings:sections.quote.title')}</th>
<th>{variables.getMessage('settings:sections.quote.author')}</th>
</tr>
{item.quotes.slice(0, count).map((quote, index) => (
{selectedItem.quotes.slice(0, count).map((quote, index) => (
<tr key={index}>
<td>{quote.quote}</td>
<td>{quote.author}</td>
@@ -175,8 +142,8 @@ const NewItemPage = () => {
</tbody>
</table>
<div className="showMoreItems">
<span className="link" onClick={() => count === item.quotes.length}>
{count !== item.quotes.length
<span className="link" onClick={() => count === selectedItem.quotes.length}>
{count !== selectedItem.quotes.length
? variables.getMessage('marketplace:product.show_all')
: variables.getMessage('marketplace:product.show_less')}
</span>
@@ -192,8 +159,8 @@ const NewItemPage = () => {
<th>{variables.getMessage('marketplace:product.setting')}</th>
<th>{variables.getMessage('marketplace:product.value')}</th>
</tr>
{Object.entries(this.props.data.data.settings)
.slice(0, this.state.count)
{Object.entries(selectedItem.settings)
.slice(0, count)
.map(([key, value]) => (
<tr key={key}>
<td>{key}</td>
@@ -204,7 +171,7 @@ const NewItemPage = () => {
</table>
<div className="showMoreItems">
<span className="link" onClick={() => this.incrementCount('settings')}>
{this.state.count !== this.props.data.data.settings.length
{count !== selectedItem.settings.length
? variables.getMessage('marketplace:product.show_all')
: variables.getMessage('marketplace:product.show_less')}
</span>
@@ -221,8 +188,8 @@ const NewItemPage = () => {
let languageNames = new Intl.DisplayNames([shortLocale], { type: 'language' });
let dateObj, formattedDate;
if (item.updated_at) {
dateObj = new Date(item.updated_at);
if (selectedItem.updated_at) {
dateObj = new Date(selectedItem.updated_at);
formattedDate = new Intl.DateTimeFormat(shortLocale, {
year: 'numeric',
month: 'long',
@@ -241,7 +208,7 @@ const NewItemPage = () => {
onRequestClose={() => setShareModal(false)}
>
<ShareModal
data={variables.constants.API_URL + '/marketplace/share/' + btoa(this.props.data.slug)}
data={variables.constants.API_URL + '/marketplace/share/' + btoa(selectedItem.name)}
modalClose={() => setShareModal(false)}
/>
</Modal>
@@ -267,18 +234,18 @@ const NewItemPage = () => {
{moreInfoItem(
<MdAccountCircle />,
variables.getMessage('marketplace:product.created_by'),
item.author,
selectedItem.author,
)}
{itemWarning()}
</div>
{/*{this.props.data.data.photos && (
{selectedItem.photos && (
<div className="carousel">
<div className="carousel_container">
<Carousel data={this.props.data.data.photos} />
<Carousel data={selectedItem.photos} />
</div>
</div>
)}
{this.props.data.data.settings && (
{/*{selectedItem.settings && (
<img
alt="product"
draggable={false}
@@ -293,7 +260,7 @@ const NewItemPage = () => {
<span className="title">
{variables.getMessage('marketplace:product.description')}
</span>
<Markdown>{item.description}</Markdown>
<Markdown>{selectedItem.description}</Markdown>
</div>
<ItemShowcase />
<ItemDetails />
@@ -301,7 +268,7 @@ const NewItemPage = () => {
<div
className="itemInfo"
style={{
backgroundImage: `url("${item.icon_url || placeholderIcon}")`,
backgroundImage: `url("${selectedItem.icon_url || placeholderIcon}")`,
}}
>
<div className="front">
@@ -309,7 +276,7 @@ const NewItemPage = () => {
className="icon"
alt="icon"
draggable={false}
src={item.icon_url}
src={selectedItem.icon_url}
onError={(e) => {
e.target.onerror = null;
e.target.src = placeholderIcon;
@@ -329,7 +296,7 @@ const NewItemPage = () => {
)}
</p>
)}
{item.sideload !== true && (
{selectedItem.sideload !== true && (
<div className="iconButtons">
<Button
type="icon"
@@ -355,8 +322,7 @@ const NewItemPage = () => {
/>
</div>
)}
{/*}
{this.props.data.data.in_collections?.length > 0 && (
{selectedItem.in_collections?.length > 0 && (
<div>
<div className="inCollection">
<span className="subtitle">
@@ -364,18 +330,18 @@ const NewItemPage = () => {
</span>
<span
className="title"
onClick={() =>
/*onClick={() =>
this.props.toggleFunction(
'collection',
this.props.data.data.in_collections[0].name,
selectedItem.in_collections[0].name,
)
}
}*/
>
{this.props.data.data.in_collections[0].display_name}
{selectedItem.in_collections[0].display_name}
</span>
</div>
</div>
)}*/}
)}
</div>
</div>
</div>

View File

@@ -1,94 +1,42 @@
import variables from 'config/variables';
import { memo, useState, useEffect } from 'react';
import { memo, useEffect } from 'react';
import { useMarketData } from 'features/marketplace/api/MarketplaceDataContext';
import MarketplaceTab from '../../marketplace/views/Browse';
import { sortItems } from '../../marketplace/api';
import { NewItems as Items } from '../../marketplace/components/Items/NewItems';
import { useTab } from 'components/Elements/MainModal/backend/TabContext';
import { NewItemPage } from '../../marketplace/views/newItemPage';
import { AnimatePresence, motion } from 'framer-motion';
function Marketplace(props) {
const [done, setDone] = useState(false);
const [items, setItems] = useState([]);
const [type, setType] = useState('all');
const [selectedItem, setSelectedItem] = useState(null);
const { done, items, getItems } = useMarketData();
const { subTab } = useTab();
const controller = new AbortController();
async function getItems() {
setDone(false);
const dataURL =
variables.constants.API_URL +
(type === 'collections' ? '/marketplace/collections' : '/marketplace/items/' + type);
const { data } = await (
await fetch(dataURL, {
signal: controller.signal,
})
).json();
if (controller.signal.aborted === true) {
return;
}
setItems(sortItems(data, 'z-a'));
setDone(true);
}
useEffect(() => {
if (navigator.onLine === false || localStorage.getItem('offlineMode') === 'true') {
return;
}
getItems();
}, []);
return (
{
/*<Tabs changeTab={(type) => props.changeTab(type)} current="marketplace" modalClose={props.modalClose}>
<div label={variables.getMessage('marketplace:all')} name="all">
<MarketplaceTab type="all" />
</div>
<div label={variables.getMessage('marketplace:photo_packs')} name="photo_packs">
<MarketplaceTab type="photo_packs" />
</div>
<div label={variables.getMessage('marketplace:quote_packs')} name="quote_packs">
<MarketplaceTab type="quote_packs" />
</div>
<div
label={variables.getMessage('marketplace:preset_settings')}
name="preset_settings"
<AnimatePresence mode="wait">
<motion.div
className="modalTabContent"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
transition={{ duration: 0.8 }}
>
<MarketplaceTab type="preset_settings" />
</div>
<div label={variables.getMessage('marketplace:collections')} name="collections">
<MarketplaceTab type="collections" />
</div>
</Tabs>*/
},
(
<AnimatePresence mode="wait">
<motion.div
className="modalTabContent"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
transition={{ duration: 0.8 }}
>
{subTab === '' ? (
<motion.div key="items">
<Items items={items} />
</motion.div>
) : (
<motion.div key="itempage">
<NewItemPage />
</motion.div>
)}
</motion.div>
</AnimatePresence>
)
{subTab === '' ? (
<motion.div key="items">
<Items items={items} />
</motion.div>
) : (
<motion.div key="itempage">
<NewItemPage />
</motion.div>
)}
</motion.div>
</AnimatePresence>
);
}