diff --git a/src/App.js b/src/App.js index 0655d57..74cf227 100644 --- a/src/App.js +++ b/src/App.js @@ -20,11 +20,7 @@ import ProductsPage from './components/pages/ProductsPage'; import processProducts from './helper/processProducts'; function HomePage({ - hoveredCard, - setHoveredCard, - selectedProduct, setSelectedProduct, - showedModal, setShowedModal, productSectionRef, courseSectionRef, @@ -38,16 +34,12 @@ function HomePage({ } /> - } /> + } /> { diff --git a/src/components/AcademySection.js b/src/components/AcademySection.js index 3c4a5d6..3980091 100644 --- a/src/components/AcademySection.js +++ b/src/components/AcademySection.js @@ -2,9 +2,10 @@ import React, { useEffect, useState } from 'react'; import { Container } from 'react-bootstrap'; import styles from './Styles.module.css'; -const AcademySection = ({hoveredCard, setHoveredCard, setSelectedProduct, setShowedModal, courseSectionRef, setWillDo}) => { +const AcademySection = ({setSelectedProduct, setShowedModal, courseSectionRef, setWillDo}) => { const [products, setProducts] = useState([]); - + const [hoveredCard, setHoveredCard] = useState(null); + useEffect(() => { fetch('https://bot.kediritechnopark.com/webhook/store-production/products', { method: 'POST', diff --git a/src/components/Dashboard copy.js b/src/components/Dashboard copy.js new file mode 100644 index 0000000..b7cdd8e --- /dev/null +++ b/src/components/Dashboard copy.js @@ -0,0 +1,191 @@ +import React, { useState, useEffect } from 'react'; +import { TrendingUp, TrendingDown, DollarSign, ShoppingCart, Users, Plus, GitBranchPlus } from 'lucide-react'; +import styles from './Dashboard.module.css'; +import processProducts from '../helper/processProducts'; + +/** + * Props: + * - setShowedModal: (modalName: string, productId?: string|number) => void + */ +const Dashboard = ({ setShowedModal }) => { + const [unitType, setUnitType] = useState('duration'); // kept for potential reuse + const [durationUnit, setDurationUnit] = useState('days'); // kept for potential reuse + const [availableTypes, setAvailableTypes] = useState([]); + const [availableGroups, setAvailableGroups] = useState([]); + const [selectedType, setSelectedType] = useState(null); + const [selectedGroup, setSelectedGroup] = useState(null); + const [isVisible, setIsVisible] = useState(true); + const [products, setProducts] = useState([]); + + const [dashboardData, setDashboardData] = useState({ + totalRevenue: { amount: 10215845, currency: 'IDR', change: 33.87, period: '22 - 29 May 2025' }, + totalItemsSold: { amount: 128980, change: -33.87, period: '22 - 29 May 2025' }, + totalVisitors: { amount: 2905897, change: 33.87, period: '22 - 29 May 2025' }, + chartData: [ + { date: '22/06', items: 200, revenue: 800 }, + { date: '23/06', items: 750, revenue: 450 }, + { date: '24/06', items: 550, revenue: 200 }, + { date: '25/06', items: 300, revenue: 350 }, + { date: '26/06', items: 900, revenue: 450 }, + { date: '27/06', items: 550, revenue: 200 }, + ], + latestTransactions: [] + }); + + useEffect(() => { + const fetchDistinctOptions = async () => { + const match = document.cookie.match(new RegExp('(^| )token=([^;]+)')); + if (!match) return; + const token = match[2]; + + try { + const res = await fetch('https://bot.kediritechnopark.com/webhook/store-production/get-products', { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${token}`, + }, + }); + + const result = await res.json(); + const productsArr = result || []; + + const types = [...new Set(productsArr.map(p => p.type).filter(Boolean))]; + const groups = [...new Set(productsArr.map(p => p.group).filter(Boolean))]; + + setAvailableTypes(types); + setAvailableGroups(groups); + setProducts(processProducts(productsArr)); + } catch (err) { + console.error('Gagal ambil produk:', err); + } + }; + + fetchDistinctOptions(); + }, []); + + const formatCurrency = (amount) => new Intl.NumberFormat('id-ID').format(amount); + + const getStatusClass = (status) => { + switch (status) { + case 'confirmed': return styles.statusConfirmed; + case 'waiting payment': return styles.statusWaiting; + case 'payment expired': return styles.statusExpired; + default: return styles.statusConfirmed; + } + }; + + const StatCard = ({ title, value, currency, change, period, icon: Icon, isNegative }) => ( + + + {title} + + + + {currency && `${currency} `}{formatCurrency(value)} + + + + {isNegative ? ( + + ) : ( + + )} + + {Math.abs(change)}% + + from last week + + + {period} + + ); + + const BarChart = ({ data }) => { + const maxValue = Math.max(...data.map(item => Math.max(item.items, item.revenue))); + return ( + + {data.map((item, index) => ( + + + + + + {item.date} + + ))} + + ); + }; + + return ( + + + + + + + + + {/* Tempatkan jika mau ditampilkan */} + + + {/* Products List */} + + + Products + + {/* Tombol "Buat Item" → buka modal create */} + setShowedModal && setShowedModal('create-item')} + title="Buat produk baru" + > + + Buat Item + + + + + {products.map((product) => ( + + + + {product.name} + {product.children && product.children.map((child) => ( + - {child.name} + ))} + + + + + + IDR {formatCurrency(product.price)} + + + {product.status} + + {/* Tombol "Add Child" → buka modal create dengan parent product_id */} + setShowedModal('create-item', product.id)} + title="Tambah sub-produk" + style={{ marginLeft: '0.75rem' }} + > + + Add Child + + + + ))} + + + + {/* Bagian form create yang lama sudah DIPINDAH ke halaman/komponen baru */} + + ); +}; + +export default Dashboard; diff --git a/src/components/Dashboard.js b/src/components/Dashboard.js index b7cdd8e..e69de29 100644 --- a/src/components/Dashboard.js +++ b/src/components/Dashboard.js @@ -1,191 +0,0 @@ -import React, { useState, useEffect } from 'react'; -import { TrendingUp, TrendingDown, DollarSign, ShoppingCart, Users, Plus, GitBranchPlus } from 'lucide-react'; -import styles from './Dashboard.module.css'; -import processProducts from '../helper/processProducts'; - -/** - * Props: - * - setShowedModal: (modalName: string, productId?: string|number) => void - */ -const Dashboard = ({ setShowedModal }) => { - const [unitType, setUnitType] = useState('duration'); // kept for potential reuse - const [durationUnit, setDurationUnit] = useState('days'); // kept for potential reuse - const [availableTypes, setAvailableTypes] = useState([]); - const [availableGroups, setAvailableGroups] = useState([]); - const [selectedType, setSelectedType] = useState(null); - const [selectedGroup, setSelectedGroup] = useState(null); - const [isVisible, setIsVisible] = useState(true); - const [products, setProducts] = useState([]); - - const [dashboardData, setDashboardData] = useState({ - totalRevenue: { amount: 10215845, currency: 'IDR', change: 33.87, period: '22 - 29 May 2025' }, - totalItemsSold: { amount: 128980, change: -33.87, period: '22 - 29 May 2025' }, - totalVisitors: { amount: 2905897, change: 33.87, period: '22 - 29 May 2025' }, - chartData: [ - { date: '22/06', items: 200, revenue: 800 }, - { date: '23/06', items: 750, revenue: 450 }, - { date: '24/06', items: 550, revenue: 200 }, - { date: '25/06', items: 300, revenue: 350 }, - { date: '26/06', items: 900, revenue: 450 }, - { date: '27/06', items: 550, revenue: 200 }, - ], - latestTransactions: [] - }); - - useEffect(() => { - const fetchDistinctOptions = async () => { - const match = document.cookie.match(new RegExp('(^| )token=([^;]+)')); - if (!match) return; - const token = match[2]; - - try { - const res = await fetch('https://bot.kediritechnopark.com/webhook/store-production/get-products', { - method: 'GET', - headers: { - 'Content-Type': 'application/json', - Authorization: `Bearer ${token}`, - }, - }); - - const result = await res.json(); - const productsArr = result || []; - - const types = [...new Set(productsArr.map(p => p.type).filter(Boolean))]; - const groups = [...new Set(productsArr.map(p => p.group).filter(Boolean))]; - - setAvailableTypes(types); - setAvailableGroups(groups); - setProducts(processProducts(productsArr)); - } catch (err) { - console.error('Gagal ambil produk:', err); - } - }; - - fetchDistinctOptions(); - }, []); - - const formatCurrency = (amount) => new Intl.NumberFormat('id-ID').format(amount); - - const getStatusClass = (status) => { - switch (status) { - case 'confirmed': return styles.statusConfirmed; - case 'waiting payment': return styles.statusWaiting; - case 'payment expired': return styles.statusExpired; - default: return styles.statusConfirmed; - } - }; - - const StatCard = ({ title, value, currency, change, period, icon: Icon, isNegative }) => ( - - - {title} - - - - {currency && `${currency} `}{formatCurrency(value)} - - - - {isNegative ? ( - - ) : ( - - )} - - {Math.abs(change)}% - - from last week - - - {period} - - ); - - const BarChart = ({ data }) => { - const maxValue = Math.max(...data.map(item => Math.max(item.items, item.revenue))); - return ( - - {data.map((item, index) => ( - - - - - - {item.date} - - ))} - - ); - }; - - return ( - - - - - - - - - {/* Tempatkan jika mau ditampilkan */} - - - {/* Products List */} - - - Products - - {/* Tombol "Buat Item" → buka modal create */} - setShowedModal && setShowedModal('create-item')} - title="Buat produk baru" - > - - Buat Item - - - - - {products.map((product) => ( - - - - {product.name} - {product.children && product.children.map((child) => ( - - {child.name} - ))} - - - - - - IDR {formatCurrency(product.price)} - - - {product.status} - - {/* Tombol "Add Child" → buka modal create dengan parent product_id */} - setShowedModal('create-item', product.id)} - title="Tambah sub-produk" - style={{ marginLeft: '0.75rem' }} - > - - Add Child - - - - ))} - - - - {/* Bagian form create yang lama sudah DIPINDAH ke halaman/komponen baru */} - - ); -}; - -export default Dashboard; diff --git a/src/components/Header.js b/src/components/Header.js index bf1cc9a..8dfbdda 100644 --- a/src/components/Header.js +++ b/src/components/Header.js @@ -21,28 +21,41 @@ const Header = ({ username, scrollToProduct, scrollToCourse, setShowedModal, han > HOME - setHoveredNav(3)} - onMouseLeave={() => setHoveredNav(null)} - onClick={() => { - if (!username) scrollToProduct(); - else navigate('/products'); - }} - > - {username ? 'MY PRODUCTS' : 'PRODUCTS'} - - setHoveredNav(4)} - onMouseLeave={() => setHoveredNav(null)} - onClick={() => { - if (!username) scrollToCourse(); - else window.location.href = 'https://academy.kediritechnopark.com' - }} - > - {username ? 'MY ACADEMY' : 'ACADEMY'} - + {username && + setHoveredNav(3)} + onMouseLeave={() => setHoveredNav(null)} + onClick={() => { + navigate('/dashboard'); + }}> + DASHBOARD + + } + {!username && + <> + setHoveredNav(3)} + onMouseLeave={() => setHoveredNav(null)} + onClick={() => { + navigate('/products'); + }} + > + PRODUCTS + + setHoveredNav(4)} + onMouseLeave={() => setHoveredNav(null)} + onClick={() => { + scrollToCourse(); + }} + > + ACADEMY + + > + } {/* Burger Menu Button */} @@ -58,9 +71,9 @@ const Header = ({ username, scrollToProduct, scrollToCourse, setShowedModal, han {username} { - navigate('/products'); + navigate('/dashboard'); }}> - MY PRODUCTS + DASHBOARD { diff --git a/src/components/Login.js b/src/components/Login.js index d022e64..3abfd65 100644 --- a/src/components/Login.js +++ b/src/components/Login.js @@ -1,6 +1,8 @@ import React, { useState } from 'react'; +import { useNavigate } from 'react-router-dom'; const LoginRegister = ({setShowedModal}) => { + const navigate = useNavigate(); const [tab, setTab] = useState('login'); // 'login' or 'register' const [email, setEmail] = useState(''); const [username, setUsername] = useState(''); @@ -103,6 +105,7 @@ const LoginRegister = ({setShowedModal}) => { window.history.replaceState({}, '', newUrl); setShowedModal('product'); } else { + navigate('/dashboard'); window.location.reload(); } } else { diff --git a/src/components/ProductSection.js b/src/components/ProductSection.js index 0f5a410..52200c2 100644 --- a/src/components/ProductSection.js +++ b/src/components/ProductSection.js @@ -4,27 +4,28 @@ import styles from './Styles.module.css'; import processProducts from '../helper/processProducts'; -const ProductSection = ({ hoveredCard, setHoveredCard, setSelectedProduct, setShowedModal, productSectionRef, setWillDo }) => { +const ProductSection = ({ setSelectedProduct, setShowedModal, productSectionRef, setWillDo }) => { const [products, setProducts] = useState([]); -// Define this function outside useEffect so it can be called anywhere + const [hoveredCard, setHoveredCard] = useState(null); + // Define this function outside useEffect so it can be called anywhere -// Inside your component -useEffect(() => { - fetch('https://bot.kediritechnopark.com/webhook/store-production/products', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ type: 'product' }), - }) - .then(res => res.json()) - .then(data => { - const enrichedData = processProducts(data); - setProducts(enrichedData); + // Inside your component + useEffect(() => { + fetch('https://bot.kediritechnopark.com/webhook/store-production/products', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ type: 'product' }), }) - .catch(err => console.error('Fetch error:', err)); -}, []); + .then(res => res.json()) + .then(data => { + const enrichedData = processProducts(data); + setProducts(enrichedData); + }) + .catch(err => console.error('Fetch error:', err)); + }, []); return ( @@ -75,12 +76,12 @@ useEffect(() => { : `Rp ${product.price.toLocaleString('id-ID')}`} - { - setSelectedProduct(product); - setShowedModal('product'); - setWillDo('checkout'); - }}>Beli + { + setSelectedProduct(product); + setShowedModal('product'); + setWillDo('checkout'); + }}>Beli ))} diff --git a/src/components/Styles.module.css b/src/components/Styles.module.css index a00a110..dada98a 100644 --- a/src/components/Styles.module.css +++ b/src/components/Styles.module.css @@ -304,7 +304,7 @@ } .currentPrice { - font-size: 1.2rem; + font-size: 0.9rem; font-weight: bold; color: #2563eb; } diff --git a/src/components/pages/ProductsPage.js b/src/components/pages/ProductsPage.js index 6cb3dff..f50f4cb 100644 --- a/src/components/pages/ProductsPage.js +++ b/src/components/pages/ProductsPage.js @@ -3,11 +3,8 @@ import ProductDetailPage from '../ProductDetailPage'; import Login from '../Login'; import styles from '../Styles.module.css'; -const CoursePage = ({ subscriptions }) => { - const [postLoginAction, setPostLoginAction] = useState(null); - const [selectedProduct, setSelectedProduct] = useState({}); +const CoursePage = ({ subscriptions, setSelectedProduct, setShowedModal}) => { const [hoveredCard, setHoveredCard] = useState(null); - const [showedModal, setShowedModal] = useState(null); const [products, setProducts] = useState([]); // Buka modal otomatis berdasarkan query @@ -107,7 +104,7 @@ const CoursePage = ({ subscriptions }) => { children: [], }; }); - console.log(enrichedData) + console.log(enrichedData) setProducts(enrichedData); }) .catch(err => console.error('Fetch error:', err)); @@ -156,50 +153,18 @@ const CoursePage = ({ subscriptions }) => { : `SISA TOKEN ${product.quantity || 0}`} + + { + setSelectedProduct(product); + setShowedModal('product'); + }}>Perpanjang ))} - - {/* Features Section */} - {/* ... tidak berubah ... */} - - {/* Footer */} - {/* ... tidak berubah ... */} - - {/* Unified Modal */} - {showedModal && ( - { - setShowedModal(null); - setSelectedProduct({}); - }} - > - e.stopPropagation()}> - {showedModal === 'product' && ( - - { - setShowedModal(null); - setSelectedProduct({}); - }} - /> - - )} - {showedModal === 'login' && ( - setShowedModal(null)} /> - )} - - - ) - } ); };
- {child.name}