diff --git a/src/components/CampaignList.jsx b/src/components/CampaignList.jsx index 321c05b..6472c04 100644 --- a/src/components/CampaignList.jsx +++ b/src/components/CampaignList.jsx @@ -25,7 +25,7 @@ export default function CampaignList() {
{selectedBrand?.campaigns?.length > 0 && selectedBrand.campaigns.map((campaign) => ( -
+
{campaign.name} diff --git a/src/components/ProductDetail.jsx b/src/components/ProductDetail.jsx new file mode 100644 index 0000000..e9d05b5 --- /dev/null +++ b/src/components/ProductDetail.jsx @@ -0,0 +1,55 @@ +import { useSelector } from "react-redux"; + +export default function ProductDetail() { + const selectedProduct = useSelector((state) => state.brands.selectedProduct); + + return ( +
+
+
{selectedProduct.name}
+
PID: {selectedProduct.id}
+
+
+
+
+
+
{selectedProduct.commission_rate}
+
Commission Rate
+
+
+
{selectedProduct.available_samples}
+
Available Samples
+
+
+
{selectedProduct.sales_price_max} - {selectedProduct.sales_price_min}
+
Sales Price
+
+
+
{selectedProduct.stock}
+
Stock
+
+
+
{selectedProduct.items_sold}
+
Items Sold
+
+
+
{selectedProduct.product_rating}
+
Product Rating
+
+
+
{selectedProduct.collab_creators}
+
Collab Creators
+
+
+
{selectedProduct.gmv}
+
GMV Achieved
+
+
+
{selectedProduct.reviews_count}
+
Views Achieved
+
+
+
+
+ ); +} diff --git a/src/components/ProductsList.jsx b/src/components/ProductsList.jsx index 43c6bbe..a7470c8 100644 --- a/src/components/ProductsList.jsx +++ b/src/components/ProductsList.jsx @@ -16,6 +16,7 @@ export default function ProductsList({ onShowProductDetail }) { const handleSort = (field) => { + return; if (sortField === field) { setSortDirection(sortDirection === 'asc' ? 'desc' : 'asc'); } else { @@ -25,6 +26,7 @@ export default function ProductsList({ onShowProductDetail }) { }; const renderSortIcon = (field) => { + return; if (sortField !== field) return null; return sortDirection === 'asc' ? '↑' : '↓'; }; @@ -109,7 +111,7 @@ export default function ProductsList({ onShowProductDetail }) { /> -
onShowProductDetail(product.id)} style={{cursor: 'pointer'}}> +
onShowProductDetail(product)} style={{cursor: 'pointer'}}>
{product.name.slice(0, 1)}
{product.name}
diff --git a/src/pages/BrandsDetail.jsx b/src/pages/BrandsDetail.jsx index 79c25a5..ac359dd 100644 --- a/src/pages/BrandsDetail.jsx +++ b/src/pages/BrandsDetail.jsx @@ -6,13 +6,16 @@ import { useDispatch, useSelector } from 'react-redux'; import { Link, useParams } from 'react-router-dom'; import CampaignList from '../components/CampaignList'; import ProductsList from '../components/ProductsList'; -import { fetchBrandDetail, fetchBrandCampaigns, fetchBrandProducts } from '../store/slices/brandsSlice'; +import { fetchBrandDetail, fetchBrandCampaigns, fetchBrandProducts, setSelectedProduct } from '../store/slices/brandsSlice'; +import SlidePanel from '../components/SlidePanel'; +import ProductDetail from '../components/ProductDetail'; export default function BrandsDetail() { const { id } = useParams(); const dispatch = useDispatch(); const [activeTab, setActiveTab] = useState('campaigns'); const { selectedBrand } = useSelector((state) => state.brands); + const [showProductDetail, setShowProductDetail] = useState(false); useEffect(() => { if (id) { @@ -22,6 +25,12 @@ export default function BrandsDetail() { } }, [dispatch, id]); + const handleShowProductDetail = (product) => { + dispatch(setSelectedProduct(product)); + setShowProductDetail(true); + }; + + return ( selectedBrand?.id && ( @@ -114,7 +123,19 @@ export default function BrandsDetail() {
{activeTab === 'campaigns' && } - {activeTab === 'products' && {}} />} + {activeTab === 'products' && ( + <> + + setShowProductDetail(false)} + title='Product Detail' + size='xxl' + > + + + + )} ) ); diff --git a/src/pages/CampaignDetail.jsx b/src/pages/CampaignDetail.jsx index e8a8654..a81b881 100644 --- a/src/pages/CampaignDetail.jsx +++ b/src/pages/CampaignDetail.jsx @@ -3,7 +3,7 @@ import { Link, useParams } from 'react-router-dom'; import SearchBar from '../components/SearchBar'; import { Button, Form, Modal } from 'react-bootstrap'; import { useSelector, useDispatch } from 'react-redux'; -import { fetchBrands, fetchBrandDetail, findProductById, fetchCampaignDetail } from '../store/slices/brandsSlice'; +import { fetchBrands, fetchBrandDetail, fetchCampaignDetail, setSelectedProduct } from '../store/slices/brandsSlice'; import CampaignInfo from '../components/CampaignInfo'; import { ChevronRight, Send, Plus } from 'lucide-react'; import ProductsList from '../components/ProductsList'; @@ -20,36 +20,25 @@ export default function CampaignDetail() { const [showProductDetail, setShowProductDetail] = useState(false); const [showAddProductModal, setShowAddProductModal] = useState(false); - useEffect(() => { - dispatch(fetchBrands()); - }, [dispatch]); - useEffect(() => { if (brandId && campaignId) { - if (!selectedBrand) { + if (!selectedBrand?.id) { dispatch(fetchBrandDetail(brandId)); dispatch(fetchCampaignDetail(campaignId)); } else { dispatch(fetchCampaignDetail(campaignId)); } } - }, [brandId, campaignId]); + }, [dispatch, brandId, campaignId]); - const handleShowProductDetail = (productId) => { - dispatch(findProductById({ brandId, campaignId, productId })); + const handleShowProductDetail = (product) => { + dispatch(setSelectedProduct(product)); setShowProductDetail(true); }; return ( selectedCampaign?.id && (
-
- - -
Brands @@ -59,6 +48,13 @@ export default function CampaignDetail() {
{selectedCampaign.name}
+
+ + +
diff --git a/src/pages/CampaignScript.jsx b/src/pages/CampaignScript.jsx index 2c929dc..b70b597 100644 --- a/src/pages/CampaignScript.jsx +++ b/src/pages/CampaignScript.jsx @@ -4,6 +4,7 @@ import { Accordion, Button, Card, Col, Form, Row, Table } from 'react-bootstrap' import { CloudUpload, Paperclip } from 'lucide-react'; import { useDropzone } from 'react-dropzone'; import { mockCreators } from '../store/slices/creatorsSlice'; +import ProductDetail from '../components/ProductDetail'; export default function CampaignScript() { const dispatch = useDispatch(); @@ -17,53 +18,7 @@ export default function CampaignScript() { return ( selectedProduct?.id && (
-
-
-
{selectedProduct.name}
-
PID: {selectedProduct.id}
-
-
-
-
-
-
{selectedProduct.commission}
-
Commission Rate
-
-
-
{selectedProduct.availableSamples}
-
Available Samples
-
-
-
{selectedProduct.price}
-
Sales Price
-
-
-
{selectedProduct.stock}
-
Stock
-
-
-
{selectedProduct.sold}
-
Items Sold
-
-
-
{selectedProduct.rating}
-
Product Rating
-
-
-
{selectedProduct.collabCreators}
-
Collab Creators
-
-
-
{selectedProduct.gmv}
-
GMV Achieved
-
-
-
{selectedProduct.reviews}
-
Views Achieved
-
-
-
-
+
c.id.toString() === campaignId) || {}; }, - findProductById: (state, action) => { - const { brandId, campaignId, productId } = action.payload; - const brand = state.brands?.find((b) => b.id.toString() === brandId); - const campaign = brand?.campaigns?.find((c) => c.id.toString() === campaignId); - const product = campaign?.products?.find((p) => p.id.toString() === productId.toString()); - console.log(brand, campaign, product); - state.selectedProduct = product; + setSelectedProduct: (state, action) => { + state.selectedProduct = action.payload; }, }, extraReducers: (builder) => { @@ -308,6 +303,6 @@ const brandsSlice = createSlice({ }, }); -export const { selectBrand, findBrandById, findCampaignById, findProductById } = brandsSlice.actions; +export const { selectBrand, findBrandById, findCampaignById, setSelectedProduct } = brandsSlice.actions; export default brandsSlice.reducer; diff --git a/src/styles/Brands.scss b/src/styles/Brands.scss index b4fd9d7..5276729 100644 --- a/src/styles/Brands.scss +++ b/src/styles/Brands.scss @@ -267,7 +267,10 @@ display: flex; flex-flow: row wrap; gap: 1rem; - + justify-content: space-between; + height: 100%; + overflow-y: auto; + .campaign-detail-info { width: 100%; background-color: #fff; diff --git a/src/styles/Campaign.scss b/src/styles/Campaign.scss index 87d72db..b81a256 100644 --- a/src/styles/Campaign.scss +++ b/src/styles/Campaign.scss @@ -7,65 +7,6 @@ flex-flow: column nowrap; gap: 1rem; - .product-details { - background-color: #fff; - padding: 1.5rem; - border-radius: 0.5rem; - - .product-details-header { - display: flex; - flex-flow: column nowrap; - align-items: flex-start; - .product-details-header-title { - font-size: 1rem; - color: $primary; - font-weight: 800; - } - .product-details-header-pid { - font-size: 0.75rem; - color: $neutral-600; - } - } - .product-details-body { - display: flex; - flex-flow: row wrap; - justify-content: space-between; - - .product-img { - flex-shrink: 0; - width: 16rem; - padding-right: 1rem; - height: 15rem; - background-color: $neutral-200; - border-radius: 0.5rem; - } - .product-detail-list { - display: grid; - grid-template-columns: repeat(3, 1fr); - justify-content: space-between; - gap: 0.5rem; - - .product-detail-item { - display: flex; - flex-flow: column nowrap; - align-items: center; - background-color: $neutral-150; - border-radius: 0.375rem; - padding: 0.75rem 0; - width: 10rem; - - .product-detail-item-value { - font-size: 1rem; - font-weight: 600; - } - .product-detail-item-label { - font-size: 0.875rem; - color: $neutral-600; - } - } - } - } - } .product-script-video-req { .video-req-form { display: flex; diff --git a/src/styles/Products.scss b/src/styles/Products.scss index 3cf8811..7655ccb 100644 --- a/src/styles/Products.scss +++ b/src/styles/Products.scss @@ -17,3 +17,64 @@ margin-right: .25rem; } } + + +.product-details { + background-color: #fff; + padding: 1.5rem; + border-radius: 0.5rem; + + .product-details-header { + display: flex; + flex-flow: column nowrap; + align-items: flex-start; + .product-details-header-title { + font-size: 1rem; + color: $primary; + font-weight: 800; + } + .product-details-header-pid { + font-size: 0.75rem; + color: $neutral-600; + } + } + .product-details-body { + display: flex; + flex-flow: row wrap; + justify-content: space-between; + + .product-img { + flex-shrink: 0; + width: 16rem; + padding-right: 1rem; + height: 15rem; + background-color: $neutral-200; + border-radius: 0.5rem; + } + .product-detail-list { + display: grid; + grid-template-columns: repeat(3, 1fr); + justify-content: space-between; + gap: 0.5rem; + + .product-detail-item { + display: flex; + flex-flow: column nowrap; + align-items: center; + background-color: $neutral-150; + border-radius: 0.375rem; + padding: 0.75rem 0; + width: 10rem; + + .product-detail-item-value { + font-size: 1rem; + font-weight: 600; + } + .product-detail-item-label { + font-size: 0.875rem; + color: $neutral-600; + } + } + } + } +} \ No newline at end of file