mirror of
https://github.com/Funkoala14/CreatorCenter_OOIN.git
synced 2025-06-08 01:18:14 +08:00
[dev]brands list
This commit is contained in:
parent
c518639845
commit
4c22e12101
@ -33,14 +33,14 @@ export default function BrandsList({ openBrandDetail }) {
|
||||
<Hash size={16} />
|
||||
Collab.
|
||||
</span>
|
||||
<span className='card-text-content'>{brand.collab}</span>
|
||||
<span className='card-text-content'>{brand.collab_count}</span>
|
||||
</Card.Text>
|
||||
<Card.Text className=''>
|
||||
<span className='card-text-title'>
|
||||
<Users size={16} />
|
||||
Creators
|
||||
</span>
|
||||
<span className='card-text-content'>{brand.creators}</span>
|
||||
<span className='card-text-content'>{brand.creators_count}</span>
|
||||
</Card.Text>
|
||||
<Card.Text className=''>
|
||||
<span className='card-text-title'>
|
||||
|
@ -3,14 +3,23 @@ import { useEffect } from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { ChartNoAxesColumnIncreasing, CircleDollarSign, Edit, Eye, Folders, Hash, Layers, Tag, TrendingUp, UserRoundCheck } from 'lucide-react';
|
||||
|
||||
import Spinning from './Spinning';
|
||||
|
||||
export default function CampaignList() {
|
||||
const { selectedBrand } = useSelector((state) => state.brands);
|
||||
const { selectedBrand ,status } = useSelector((state) => state.brands);
|
||||
|
||||
useEffect(() => {
|
||||
console.log(selectedBrand);
|
||||
}, [selectedBrand]);
|
||||
|
||||
if (status === 'loading') {
|
||||
return <Spinning />;
|
||||
}
|
||||
|
||||
if (selectedBrand?.campaigns?.length === 0) {
|
||||
return <div>No campaigns found</div>;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='campaigns-list'>
|
||||
{selectedBrand?.campaigns?.length > 0 &&
|
||||
|
@ -4,23 +4,16 @@ import { useSelector, useDispatch } from 'react-redux';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import '../styles/Products.scss';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import Spinning from './Spinning';
|
||||
|
||||
export default function ProductsList({ onShowProductDetail }) {
|
||||
const { brandId } = useParams();
|
||||
const { brands } = useSelector((state) => state.brands);
|
||||
const { selectedBrand } = useSelector((state) => state.brands);
|
||||
const [products, setProducts] = useState([]);
|
||||
const [selectedProducts, setSelectedProducts] = useState([]);
|
||||
const [sortField, setSortField] = useState(null);
|
||||
const [sortDirection, setSortDirection] = useState('asc');
|
||||
|
||||
useEffect(() => {
|
||||
if (brands.length > 0) {
|
||||
const brand = brands.find((b) => b.id.toString() === brandId);
|
||||
if (brand && brand.products) {
|
||||
setProducts(brand.products);
|
||||
}
|
||||
}
|
||||
}, [brands, brandId]);
|
||||
|
||||
const handleSort = (field) => {
|
||||
if (sortField === field) {
|
||||
@ -52,6 +45,11 @@ export default function ProductsList({ onShowProductDetail }) {
|
||||
}
|
||||
};
|
||||
|
||||
if (status === 'loading') {
|
||||
return <Spinning />;
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<div className='products-list rounded shadow-xs'>
|
||||
<Table responsive hover className='bg-white rounded overflow-hidden m-0'>
|
||||
@ -60,7 +58,7 @@ export default function ProductsList({ onShowProductDetail }) {
|
||||
<th className='selector' style={{ width: '40px' }}>
|
||||
<Form.Check
|
||||
type='checkbox'
|
||||
checked={selectedProducts.length === products.length && products.length > 0}
|
||||
checked={selectedProducts.length === selectedBrand?.products?.length && selectedBrand?.products?.length > 0}
|
||||
onChange={handleSelectAll}
|
||||
/>
|
||||
</th>
|
||||
@ -94,14 +92,14 @@ export default function ProductsList({ onShowProductDetail }) {
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{products.length === 0 ? (
|
||||
{selectedBrand?.products?.length === 0 ? (
|
||||
<tr>
|
||||
<td colSpan='10' className='text-center py-4'>
|
||||
No products found for this brand.
|
||||
</td>
|
||||
</tr>
|
||||
) : (
|
||||
products.map((product) => (
|
||||
selectedBrand?.products?.map((product) => (
|
||||
<tr key={product.id} className={selectedProducts.includes(product.id) ? 'selected' : ''}>
|
||||
<td>
|
||||
<Form.Check
|
||||
@ -117,19 +115,19 @@ export default function ProductsList({ onShowProductDetail }) {
|
||||
</div>
|
||||
</td>
|
||||
<td className='text-center' >
|
||||
<div>{product.commission}</div>
|
||||
<div className='small text-muted'>Open collab. {product.openCollab}</div>
|
||||
<div>{product.commission_rate}</div>
|
||||
<div className='small text-muted'>Open collab. {product.open_collab}</div>
|
||||
</td>
|
||||
<td className='text-center'>{product.availableSamples}</td>
|
||||
<td className='text-center'>{product.price}</td>
|
||||
<td className='text-center'>{product.available_samples}</td>
|
||||
<td className='text-center'>{product.sales_price_min} - {product.sales_price_max}</td>
|
||||
<td className='text-center'>{product.stock}</td>
|
||||
<td className='text-center'>{product.sold}</td>
|
||||
<td className='text-center'>{product.items_sold}</td>
|
||||
<td className='text-center'>
|
||||
<div>{product.rating}</div>
|
||||
<div className='small text-muted'>{product.reviews} Reviews</div>
|
||||
<div>{product.product_rating}</div>
|
||||
<div className='small text-muted'>{product.reviews_count} Reviews</div>
|
||||
</td>
|
||||
<td className='text-center'>{product.collabCreators}</td>
|
||||
<td className='text-center'>{product.tiktokShop && <FontAwesomeIcon icon='fa-brands fa-tiktok' />}</td>
|
||||
<td className='text-center'>{product.collab_creators}</td>
|
||||
<td className='text-center'>{product.tiktok_shop && <FontAwesomeIcon icon='fa-brands fa-tiktok' />}</td>
|
||||
</tr>
|
||||
))
|
||||
)}
|
||||
|
@ -6,7 +6,7 @@ import { useDispatch, useSelector } from 'react-redux';
|
||||
import { Link, useParams } from 'react-router-dom';
|
||||
import CampaignList from '../components/CampaignList';
|
||||
import ProductsList from '../components/ProductsList';
|
||||
import { findBrandById } from '../store/slices/brandsSlice';
|
||||
import { findBrandById, fetchBrandCampaigns, fetchBrandProducts } from '../store/slices/brandsSlice';
|
||||
|
||||
export default function BrandsDetail() {
|
||||
const { id } = useParams();
|
||||
@ -16,9 +16,9 @@ export default function BrandsDetail() {
|
||||
|
||||
useEffect(() => {
|
||||
if (id) {
|
||||
console.log(id);
|
||||
|
||||
dispatch(findBrandById(id));
|
||||
dispatch(fetchBrandCampaigns(id));
|
||||
dispatch(fetchBrandProducts(id));
|
||||
}
|
||||
}, [dispatch, id]);
|
||||
|
||||
@ -69,31 +69,31 @@ export default function BrandsDetail() {
|
||||
<Hash size={20} />
|
||||
Collab.
|
||||
</div>
|
||||
<div className='info-value'>{selectedBrand.collab}</div>
|
||||
<div className='info-value'>{selectedBrand.collab_count}</div>
|
||||
</div>
|
||||
<div className='info-item'>
|
||||
<div className='info-name'>
|
||||
<Users size={20} />
|
||||
Creators
|
||||
</div>
|
||||
<div className='info-value'>{selectedBrand.creators}</div>
|
||||
<div className='info-value'>{selectedBrand.creators_count}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='brand-info-bottom'>
|
||||
<div className='info-item'>
|
||||
<div className='info-value'>{selectedBrand.collab}</div>
|
||||
<div className='info-value'>{selectedBrand.creators_count}</div>
|
||||
<div className='info-name'>Total Collab. Creators</div>
|
||||
</div>
|
||||
<div className='info-item'>
|
||||
<div className='info-value'>{selectedBrand.collab}</div>
|
||||
<div className='info-value'>{selectedBrand.total_gmv_achieved}</div>
|
||||
<div className='info-name'>Total GMV Achieved</div>
|
||||
</div>
|
||||
<div className='info-item'>
|
||||
<div className='info-value'>{selectedBrand.collab}</div>
|
||||
<div className='info-value'>{selectedBrand.total_views_achieved}</div>
|
||||
<div className='info-name'>Total Views Achieved</div>
|
||||
</div>
|
||||
<div className='info-item'>
|
||||
<div className='info-value'>{selectedBrand.collab}</div>
|
||||
<div className='info-value'>{selectedBrand.shop_overall_rating}</div>
|
||||
<div className='info-name'>Shop Overall Rating</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit';
|
||||
|
||||
import api from '@/services/api';
|
||||
const mockProducts = [
|
||||
{
|
||||
id: 1,
|
||||
@ -108,10 +108,19 @@ const mockBrands = [
|
||||
|
||||
export const fetchBrands = createAsyncThunk('brands/fetchBrands', async () => {
|
||||
// const response = await fetch('https://api.example.com/brands');
|
||||
await new Promise((resolve) => setTimeout(resolve, 500));
|
||||
console.log('fetchBrands');
|
||||
const response = await api.get('/brands/');
|
||||
return response.data;
|
||||
});
|
||||
|
||||
return mockBrands;
|
||||
export const fetchBrandCampaigns = createAsyncThunk('brands/fetchBrandCampaigns', async (brandId) => {
|
||||
const response = await api.get(`/brands/${brandId}/campaigns/`);
|
||||
return response.data;
|
||||
});
|
||||
|
||||
export const fetchBrandProducts = createAsyncThunk('brands/fetchBrandProducts', async (brandId) => {
|
||||
const response = await api.get(`/brands/${brandId}/products/`);
|
||||
console.log(response);
|
||||
return response.data;
|
||||
});
|
||||
|
||||
const initialState = {
|
||||
@ -161,6 +170,28 @@ const brandsSlice = createSlice({
|
||||
.addCase(fetchBrands.rejected, (state, action) => {
|
||||
state.status = 'failed';
|
||||
state.error = action.error.message;
|
||||
})
|
||||
.addCase(fetchBrandCampaigns.pending, (state) => {
|
||||
state.status = 'loading';
|
||||
})
|
||||
.addCase(fetchBrandCampaigns.fulfilled, (state, action) => {
|
||||
state.status = 'succeeded';
|
||||
state.selectedBrand.campaigns = action.payload;
|
||||
})
|
||||
.addCase(fetchBrandCampaigns.rejected, (state, action) => {
|
||||
state.status = 'failed';
|
||||
state.error = action.error.message;
|
||||
})
|
||||
.addCase(fetchBrandProducts.pending, (state) => {
|
||||
state.status = 'loading';
|
||||
})
|
||||
.addCase(fetchBrandProducts.fulfilled, (state, action) => {
|
||||
state.status = 'succeeded';
|
||||
state.selectedBrand.products = action.payload;
|
||||
})
|
||||
.addCase(fetchBrandProducts.rejected, (state, action) => {
|
||||
state.status = 'failed';
|
||||
state.error = action.error.message;
|
||||
});
|
||||
},
|
||||
});
|
||||
|
@ -8,7 +8,8 @@
|
||||
gap: 1rem;
|
||||
|
||||
.brand-card {
|
||||
width: 325px;
|
||||
flex: 1;
|
||||
min-width: 325px;
|
||||
padding: 1.5rem;
|
||||
border-radius: 0.4rem;
|
||||
background-color: white;
|
||||
|
Loading…
Reference in New Issue
Block a user