diff --git a/src/components/BrandsList.jsx b/src/components/BrandsList.jsx index 81d2270..d19fd98 100644 --- a/src/components/BrandsList.jsx +++ b/src/components/BrandsList.jsx @@ -25,7 +25,7 @@ export default function BrandsList({ openBrandDetail }) { return (
- {brands?.length > 0 && brands.map((brand) => ( + {brands?.length > 0 ? brands.map((brand) => (
openBrandDetail(brand)}> @@ -62,7 +62,9 @@ export default function BrandsList({ openBrandDetail }) {
- ))} + )) : ( +
No brands found.
+ )}
); } diff --git a/src/components/CreatorList.jsx b/src/components/CreatorList.jsx index b1c9ac6..79ee2b5 100644 --- a/src/components/CreatorList.jsx +++ b/src/components/CreatorList.jsx @@ -176,17 +176,17 @@ export default function CreatorList({ path }) { /> -
+
{creator.name} {creator.status && }
- +
{creator.name} - -
+
+ - + {creator.category} diff --git a/src/components/DiscoveryList.jsx b/src/components/DiscoveryList.jsx index d8f5aab..218e136 100644 --- a/src/components/DiscoveryList.jsx +++ b/src/components/DiscoveryList.jsx @@ -1,10 +1,11 @@ +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Table } from 'react-bootstrap'; import { useSelector, useDispatch } from 'react-redux'; import { Link } from 'react-router-dom'; export default function DiscoveryList() { const dispatch = useDispatch(); - const { creators, error, status } = useSelector((state) => state.discovery); + const { sessions, error, status } = useSelector((state) => state.discovery); // 如果加载失败,显示错误信息 if (status === 'failed') { @@ -27,18 +28,18 @@ export default function DiscoveryList() { - {creators?.length > 0 ? ( - creators.map((creator) => ( - - {creator.sessions} - {creator.creator} - {creator.shoppableCreators} - {creator.avgFollowers} - {creator.avgGMV} - {creator.avgVideoViews} - {creator.date} + {sessions?.length > 0 ? ( + sessions.map((session) => ( + + {session.session_number} + {session.creator_count} + {session.shoppable_creators} + {session.avg_followers} + {session.avg_gmv} + {session.avg_video_views} + {session.date_created} - View + View )) @@ -54,3 +55,103 @@ export default function DiscoveryList() { ); } + +function SeesionResultModal({ session }) { + + return ( +
+
+ + + + + + + + + + + + + + + + {session.creators.length <= 0 ? ( + + + + ) : ( + session.creators.map((creator) => ( + + + + + + + + + + + + )) + )} + +
+ Creator + + Category + + E-commerce Level + + Exposure Level + + Followers + + GMV + + Avg. Video Views + E-commerceProfile
+ No creators found matching your filters. +
+ +
+ {creator.name} +
+
+ {creator.name} +
+ +
+ + {creator.category} + + + {creator.ecommerce_level} + + + {creator.exposure_level} + + {creator.followers} +
{creator.gmv}
+
Items Sold: {creator.soldPercentage}
+
{creator.avg_video_views} + {creator.has_ecommerce ?
: null} +
+ {creator.hasTiktok && ( +
+ +
+ )} +
+
+
+ ) +} \ No newline at end of file diff --git a/src/pages/Brands.jsx b/src/pages/Brands.jsx index 0d0b7f0..9f15f00 100644 --- a/src/pages/Brands.jsx +++ b/src/pages/Brands.jsx @@ -113,7 +113,7 @@ function AddBrandModal({ show, onHide }) { setBrandSource(e.target.value)} required> {BRAND_SOURCES.map((option) => ( ))} diff --git a/src/pages/CreatorDetail.jsx b/src/pages/CreatorDetail.jsx index ef75f9f..97628a0 100644 --- a/src/pages/CreatorDetail.jsx +++ b/src/pages/CreatorDetail.jsx @@ -75,6 +75,7 @@ export default function CreatorDetail({}) { dispatch(fetchCreatorVideos({ creatorId: id })); }; const processChartData = (data, chart) => { + if (!data) return; switch (chart) { case 'channel': return { @@ -242,17 +243,21 @@ export default function CreatorDetail({}) {
GMV per sales channel
- + {selectedCreator?.analytics?.gmv_by_channel && ( + + )}
GMV by product category
- + {selectedCreator?.analytics?.gmv_by_category && ( + + )}
@@ -525,24 +530,30 @@ function CreatorFollowerInfo({ selectedCreator }) {
Follower Gender
- + {selectedCreator?.followerData?.gender && ( + + )}
Follower Age
- + {selectedCreator?.followerData?.age && ( + + )}
Top 5 Locations
- + {selectedCreator?.followerData?.locations && ( + + )}
@@ -615,7 +626,9 @@ function CreatorTrends({ selectedCreator }) {
- + {selectedCreator?.trendsData && ( + + )}
); @@ -624,9 +637,9 @@ function CreatorVideos({ selectedCreator }) { return (
Videos
- {selectedCreator?.videosData?.regular_videos.total > 0 && + {selectedCreator?.videosData?.regular_videos?.videos?.length > 0 && selectedCreator?.videosData.regular_videos?.videos.map((video) => ( -
+
@@ -649,9 +662,9 @@ function CreatorVideos({ selectedCreator }) { ))}
Videos with Product
- {selectedCreator?.videosData?.product_videos?.total > 0 && + {selectedCreator?.videosData?.product_videos?.videos?.length > 0 && selectedCreator?.videosData?.product_videos?.videos.map((video) => ( -
+
diff --git a/src/pages/CreatorDiscovery.jsx b/src/pages/CreatorDiscovery.jsx index c09e0e2..a17c71c 100644 --- a/src/pages/CreatorDiscovery.jsx +++ b/src/pages/CreatorDiscovery.jsx @@ -4,7 +4,7 @@ import { Button, Form } from 'react-bootstrap'; import '@/styles/CreatorDiscovery.scss'; import DiscoveryList from '../components/DiscoveryList'; import { useDispatch } from 'react-redux'; -import { fetchDiscovery, fetchDiscoveryByIndividual, fetchDiscoveryByMode } from '../store/slices/discoverySlice'; +import { fetchDiscovery, fetchDiscoveryByIndividual, fetchDiscoveryByMode, resetStatus } from '../store/slices/discoverySlice'; export default function CreatorDiscovery() { const [search, setSearch] = useState(''); @@ -12,7 +12,12 @@ export default function CreatorDiscovery() { const dispatch = useDispatch(); - useEffect(() => {}, [dispatch]); + useEffect(() => { + + return () => { + dispatch(resetStatus()); + }; + }, [dispatch]); const handleSubmit = (e) => { e.preventDefault(); diff --git a/src/store/slices/creatorsSlice.js b/src/store/slices/creatorsSlice.js index 02da087..9aa6819 100644 --- a/src/store/slices/creatorsSlice.js +++ b/src/store/slices/creatorsSlice.js @@ -332,7 +332,7 @@ export const fetchCreatorMetrics = createAsyncThunk( try { const response = await api.get(`/daren_detail/creators/${creatorId}/metrics`); if (response.code === 200 || response.code === 201) { - return response; + return response.data; } else { throw new Error(response.message); } @@ -348,7 +348,7 @@ export const fetchCreatorFollowers = createAsyncThunk( try { const response = await api.get(`/daren_detail/creator/${creatorId}/followers`); if (response.code === 200) { - return response; + return response.data; } else { throw new Error(response.message); } @@ -364,7 +364,7 @@ export const fetchCreatorTrends = createAsyncThunk( try { const response = await api.get(`/daren_detail/creator/${creatorId}/trends`); if (response.code === 200) { - return response; + return response.data; } else { throw new Error(response.message); } @@ -380,7 +380,7 @@ export const fetchCreatorVideos = createAsyncThunk( try { const response = await api.get(`/daren_detail/creator/${creatorId}/videos`); if (response.code === 200) { - return response; + return response.data; } else { throw new Error(response.message); } @@ -513,16 +513,16 @@ const creatorsSlice = createSlice({ state.error = action.error.message; }) .addCase(fetchCreatorMetrics.fulfilled, (state, action) => { - state.selectedCreator.metricsData = action.payload.data; + state.selectedCreator.metricsData = action.payload; }) .addCase(fetchCreatorFollowers.fulfilled, (state, action) => { - state.selectedCreator.followerData = action.payload.data; + state.selectedCreator.followerData = action.payload; }) .addCase(fetchCreatorTrends.fulfilled, (state, action) => { - state.selectedCreator.trendsData = action.payload.data; + state.selectedCreator.trendsData = action.payload; }) .addCase(fetchCreatorVideos.fulfilled, (state, action) => { - state.selectedCreator.videosData = action.payload.data; + state.selectedCreator.videosData = action.payload; }) .addCase(searchCreators.pending, (state) => { state.status = 'loading'; diff --git a/src/store/slices/discoverySlice.js b/src/store/slices/discoverySlice.js index a2259d0..5ca9f4d 100644 --- a/src/store/slices/discoverySlice.js +++ b/src/store/slices/discoverySlice.js @@ -28,7 +28,7 @@ export const fetchDiscovery = createAsyncThunk( 'discovery/fetchDiscovery', async (query, { rejectWithValue, dispatch }) => { try { - const response = await api.post('/discovery/creators/search/', {query: query}); + const response = await api.post('/discovery/creators/search/', { query: query }); if (response.code === 200) { return response.data; } @@ -72,7 +72,7 @@ export const fetchDiscoveryByIndividual = createAsyncThunk( } ); const initialState = { - creators: [], + sessions: [], status: 'idle', error: null, }; @@ -80,7 +80,12 @@ const initialState = { const discoverySlice = createSlice({ name: 'discovery', initialState, - reducers: {}, + reducers: { + resetStatus: (state) => { + state.status = 'idle'; + state.error = null; + }, + }, extraReducers: (builder) => { builder .addCase(fetchDiscovery.pending, (state) => { @@ -88,7 +93,7 @@ const discoverySlice = createSlice({ }) .addCase(fetchDiscovery.fulfilled, (state, action) => { state.status = 'succeeded'; - state.creators = action.payload; + state.sessions = action.payload; }) .addCase(fetchDiscovery.rejected, (state, action) => { state.status = 'failed'; @@ -99,7 +104,7 @@ const discoverySlice = createSlice({ }) .addCase(fetchDiscoveryByMode.fulfilled, (state, action) => { state.status = 'succeeded'; - state.creators = action.payload; + state.sessions = [action.payload]; }) .addCase(fetchDiscoveryByMode.rejected, (state, action) => { state.status = 'failed'; @@ -110,7 +115,7 @@ const discoverySlice = createSlice({ }) .addCase(fetchDiscoveryByIndividual.fulfilled, (state, action) => { state.status = 'succeeded'; - state.creators = action.payload; + state.sessions = [action.payload]; }) .addCase(fetchDiscoveryByIndividual.rejected, (state, action) => { state.status = 'failed'; @@ -119,6 +124,6 @@ const discoverySlice = createSlice({ }, }); -export const {} = discoverySlice.actions; +export const { resetStatus } = discoverySlice.actions; export default discoverySlice.reducer; diff --git a/src/store/slices/inboxSlice.js b/src/store/slices/inboxSlice.js index 73e3977..6ea861f 100644 --- a/src/store/slices/inboxSlice.js +++ b/src/store/slices/inboxSlice.js @@ -173,13 +173,14 @@ const chatDateFormat = (date) => { export const fetchInboxList = createAsyncThunk('inbox/fetchInboxList', async (_, { rejectWithValue }) => { try { - const response = await api.get(`/chat-history/`); + const response = await api.get('/chat-history/'); if (response.code === 200) { return response.data; + } else { + throw new Error(response.message); } - throw new Error(response.message); } catch (error) { - return rejectWithValue(error.message); + return rejectWithValue(error.response.data.message); } }); @@ -247,7 +248,7 @@ const inboxSlice = createSlice({ }) .addCase(fetchInboxList.rejected, (state, action) => { state.inboxStatus = 'failed'; - state.error = action.error.message; + state.error = action.payload; }) .addCase(fetchChatHistory.pending, (state) => { state.chatStatus = 'loading'; @@ -264,11 +265,11 @@ const inboxSlice = createSlice({ }) .addCase(fetchChatHistory.rejected, (state, action) => { state.chatStatus = 'failed'; - state.error = action.error.message; + state.error = action.payload; }) .addCase(fetchTemplates.rejected, (state, action) => { state.templatesStatus = 'failed'; - state.error = action.error.message; + state.error = action.payload; }) .addCase(fetchTemplates.pending, (state) => { state.templatesStatus = 'loading'; @@ -286,7 +287,7 @@ const inboxSlice = createSlice({ }) .addCase(editTemplateApi.rejected, (state, action) => { state.templatesStatus = 'failed'; - state.error = action.error.message; + state.error = action.payload; }) .addCase(addTemplateApi.pending, (state) => { state.templatesStatus = 'loading'; @@ -298,7 +299,7 @@ const inboxSlice = createSlice({ }) .addCase(addTemplateApi.rejected, (state, action) => { state.templatesStatus = 'failed'; - state.error = action.error.message; + state.error = action.payload; }); }, });