mirror of
https://github.com/Funkoala14/CreatorCenter_OOIN.git
synced 2025-06-08 05:28:14 +08:00
[dev]brands search
This commit is contained in:
parent
1a51aff75b
commit
3492e16c40
@ -2,7 +2,7 @@ import { useEffect, useState } from 'react';
|
|||||||
import { Button, Form, Modal } from 'react-bootstrap';
|
import { Button, Form, Modal } from 'react-bootstrap';
|
||||||
import { useDispatch, useSelector } from 'react-redux';
|
import { useDispatch, useSelector } from 'react-redux';
|
||||||
import { fetchCampaigns } from '../store/slices/brandsSlice';
|
import { fetchCampaigns } from '../store/slices/brandsSlice';
|
||||||
import SpinningComponent from './Spinning';
|
import SpinningComponent from './SpinningComponent';
|
||||||
import { addCreatorsToCampaign } from '../store/slices/creatorsSlice';
|
import { addCreatorsToCampaign } from '../store/slices/creatorsSlice';
|
||||||
|
|
||||||
export default function AddToCampaign({ show, onHide }) {
|
export default function AddToCampaign({ show, onHide }) {
|
||||||
|
@ -3,15 +3,26 @@ import { useSelector, useDispatch } from 'react-redux';
|
|||||||
import { fetchBrands } from '../store/slices/brandsSlice';
|
import { fetchBrands } from '../store/slices/brandsSlice';
|
||||||
import { Card } from 'react-bootstrap';
|
import { Card } from 'react-bootstrap';
|
||||||
import { Folders, Hash, Link, Users } from 'lucide-react';
|
import { Folders, Hash, Link, Users } from 'lucide-react';
|
||||||
|
import SpinningComponent from './SpinningComponent';
|
||||||
|
|
||||||
export default function BrandsList({ openBrandDetail }) {
|
export default function BrandsList({ openBrandDetail }) {
|
||||||
const brands = useSelector((state) => state.brands.brands);
|
const { brands, status, error } = useSelector((state) => state.brands);
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
dispatch(fetchBrands());
|
dispatch(fetchBrands());
|
||||||
}, [dispatch]);
|
}, [dispatch]);
|
||||||
|
|
||||||
|
if (status === 'loading') {
|
||||||
|
return <SpinningComponent />;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果加载失败,显示错误信息
|
||||||
|
if (status === 'failed') {
|
||||||
|
return <div className='alert alert-danger'>{error || 'Failed to load brands. Please try again later.'}</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='brands-list'>
|
<div className='brands-list'>
|
||||||
{brands?.length > 0 && brands.map((brand) => (
|
{brands?.length > 0 && brands.map((brand) => (
|
||||||
|
@ -3,7 +3,7 @@ import { useEffect } from 'react';
|
|||||||
import { useSelector } from 'react-redux';
|
import { useSelector } from 'react-redux';
|
||||||
import { Link, useParams } from 'react-router-dom';
|
import { Link, useParams } from 'react-router-dom';
|
||||||
import { ChartNoAxesColumnIncreasing, CircleDollarSign, Edit, Eye, Folders, Hash, Layers, Tag, TrendingUp, UserRoundCheck } from 'lucide-react';
|
import { ChartNoAxesColumnIncreasing, CircleDollarSign, Edit, Eye, Folders, Hash, Layers, Tag, TrendingUp, UserRoundCheck } from 'lucide-react';
|
||||||
import Spinning from './Spinning';
|
import Spinning from './SpinningComponent';
|
||||||
|
|
||||||
export default function CampaignList() {
|
export default function CampaignList() {
|
||||||
const { selectedBrand ,status } = useSelector((state) => state.brands);
|
const { selectedBrand ,status } = useSelector((state) => state.brands);
|
||||||
|
@ -3,9 +3,9 @@ import { Table, Form, Button, Modal } from 'react-bootstrap';
|
|||||||
import { useSelector, useDispatch } from 'react-redux';
|
import { useSelector, useDispatch } from 'react-redux';
|
||||||
import '../styles/Products.scss';
|
import '../styles/Products.scss';
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
import Spinning from './Spinning';
|
import Spinning from './SpinningComponent';
|
||||||
import { Plus } from 'lucide-react';
|
import { Plus } from 'lucide-react';
|
||||||
import SpinningComponent from './Spinning';
|
import SpinningComponent from './SpinningComponent';
|
||||||
import { addProductToCampaign } from '../store/slices/productSlice';
|
import { addProductToCampaign } from '../store/slices/productSlice';
|
||||||
|
|
||||||
export default function ProductsList({ products, onShowProductDetail, type = 'default' }) {
|
export default function ProductsList({ products, onShowProductDetail, type = 'default' }) {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { Copy, Edit, FileText, LayoutTemplate } from 'lucide-react';
|
import { Copy, Edit, FileText, LayoutTemplate } from 'lucide-react';
|
||||||
import { Button } from 'react-bootstrap';
|
import { Button } from 'react-bootstrap';
|
||||||
import { useSelector } from 'react-redux';
|
import { useSelector } from 'react-redux';
|
||||||
import Spinning from './Spinning';
|
import Spinning from './SpinningComponent';
|
||||||
|
|
||||||
export default function TemplateList({ activeTab, openModal, setFormData }) {
|
export default function TemplateList({ activeTab, openModal, setFormData }) {
|
||||||
const { templates, templatesStatus } = useSelector((state) => state.inbox);
|
const { templates, templatesStatus } = useSelector((state) => state.inbox);
|
||||||
|
@ -6,27 +6,32 @@ import '../styles/Brands.scss';
|
|||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { Plus } from 'lucide-react';
|
import { Plus } from 'lucide-react';
|
||||||
import { useDispatch, useSelector } from 'react-redux';
|
import { useDispatch, useSelector } from 'react-redux';
|
||||||
import { createBrandThunk, fetchBrands, selectBrand } from '../store/slices/brandsSlice';
|
import { createBrandThunk, fetchBrands, searchBrands, selectBrand } from '../store/slices/brandsSlice';
|
||||||
import SpinningComponent from '../components/Spinning';
|
import SpinningComponent from '../components/SpinningComponent';
|
||||||
import { BRAND_SOURCES } from '../lib/constant';
|
import { BRAND_SOURCES } from '../lib/constant';
|
||||||
|
|
||||||
export default function Brands() {
|
export default function Brands() {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const [showAddBrandModal, setShowAddBrandModal] = useState(false);
|
const [showAddBrandModal, setShowAddBrandModal] = useState(false);
|
||||||
|
const [searchValue, setSearchValue] = useState('');
|
||||||
|
|
||||||
useEffect(() => {}, [dispatch]);
|
useEffect(() => {}, [dispatch]);
|
||||||
|
|
||||||
const openBrandDetail = async (item) => {
|
const openBrandDetail = async (item) => {
|
||||||
console.log(item);
|
|
||||||
await dispatch(selectBrand(item));
|
await dispatch(selectBrand(item));
|
||||||
navigate(`/brands/${item.id}`);
|
navigate(`/brands/${item.id}`);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleSearch = (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
dispatch(searchBrands({ keyword: searchValue }));
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<div className='function-bar'>
|
<div className='function-bar'>
|
||||||
<SearchBar />
|
<SearchBar onSearch={handleSearch} value={searchValue} onChange={(e) => setSearchValue(e.target.value)} />
|
||||||
<Button onClick={() => setShowAddBrandModal(true)}>
|
<Button onClick={() => setShowAddBrandModal(true)}>
|
||||||
<Plus />
|
<Plus />
|
||||||
Add Brand
|
Add Brand
|
||||||
@ -76,7 +81,7 @@ function AddBrandModal({ show, onHide }) {
|
|||||||
setCampaignId('');
|
setCampaignId('');
|
||||||
};
|
};
|
||||||
|
|
||||||
if (status === 'loading') {
|
if (show && status === 'loading') {
|
||||||
return <SpinningComponent />;
|
return <SpinningComponent />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,7 +17,6 @@ import SlidePanel from '../components/SlidePanel';
|
|||||||
import ProductDetail, { CampaignsCollabCreators } from '../components/ProductDetail';
|
import ProductDetail, { CampaignsCollabCreators } from '../components/ProductDetail';
|
||||||
import { CAMPAIGN_SERVICES, CREATOR_CATEGORIES, CREATOR_LEVELS, CREATOR_TYPES, GMV_RANGES } from '../lib/constant';
|
import { CAMPAIGN_SERVICES, CREATOR_CATEGORIES, CREATOR_LEVELS, CREATOR_TYPES, GMV_RANGES } from '../lib/constant';
|
||||||
import RangeSlider from '../components/RangeSlider';
|
import RangeSlider from '../components/RangeSlider';
|
||||||
import SpinningComponent from '../components/Spinning';
|
|
||||||
import { setNotificationBarMessage } from '../store/slices/notificationBarSlice';
|
import { setNotificationBarMessage } from '../store/slices/notificationBarSlice';
|
||||||
|
|
||||||
export default function BrandsDetail() {
|
export default function BrandsDetail() {
|
||||||
|
@ -120,6 +120,18 @@ export const fetchBrands = createAsyncThunk('brands/fetchBrands', async (_, { re
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const searchBrands = createAsyncThunk('brands/searchBrands', async (params, { rejectWithValue }) => {
|
||||||
|
try {
|
||||||
|
const response = await api.get('/brands/search/', { params });
|
||||||
|
if (response.code !== 200) {
|
||||||
|
throw new Error(response.message);
|
||||||
|
}
|
||||||
|
return response.data;
|
||||||
|
} catch (error) {
|
||||||
|
return rejectWithValue(error.message);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
export const fetchBrandDetail = createAsyncThunk('brands/fetchBrandDetail', async (brandId, { rejectWithValue }) => {
|
export const fetchBrandDetail = createAsyncThunk('brands/fetchBrandDetail', async (brandId, { rejectWithValue }) => {
|
||||||
try {
|
try {
|
||||||
const response = await api.get(`/brands/${brandId}/`);
|
const response = await api.get(`/brands/${brandId}/`);
|
||||||
@ -324,6 +336,17 @@ const brandsSlice = createSlice({
|
|||||||
.addCase(createCampaignThunk.rejected, (state, action) => {
|
.addCase(createCampaignThunk.rejected, (state, action) => {
|
||||||
state.status = 'failed';
|
state.status = 'failed';
|
||||||
state.error = action.error.message;
|
state.error = action.error.message;
|
||||||
|
})
|
||||||
|
.addCase(searchBrands.pending, (state) => {
|
||||||
|
state.status = 'loading';
|
||||||
|
})
|
||||||
|
.addCase(searchBrands.fulfilled, (state, action) => {
|
||||||
|
state.status = 'succeeded';
|
||||||
|
state.brands = action.payload;
|
||||||
|
})
|
||||||
|
.addCase(searchBrands.rejected, (state, action) => {
|
||||||
|
state.status = 'failed';
|
||||||
|
state.error = action.error.message;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user