- {[1, 2, 3, 4, 5].map((num) => (
-
-
+
+ {logos.map((logo, index) => (
+
+
- ))}
+ ))}
+
@@ -25,4 +37,4 @@ const ClientsSection = () => {
);
};
-export default ClientsSection;
\ No newline at end of file
+export default ClientsSection;
diff --git a/src/components/CreateProductPage.js b/src/components/CreateProductPage.js
new file mode 100644
index 0000000..9a9398f
--- /dev/null
+++ b/src/components/CreateProductPage.js
@@ -0,0 +1,239 @@
+import React, { useEffect, useState } from 'react';
+import styles from './Dashboard.module.css';
+
+const CreateProductPage = ({ parentId = null, onSuccess, onCancel }) => {
+ const [availableTypes, setAvailableTypes] = useState([]);
+ const [availableGroups, setAvailableGroups] = useState([]);
+
+ const [name, setName] = useState('');
+ const [description, setDescription] = useState('');
+ const [image, setImage] = useState('');
+ const [price, setPrice] = useState('');
+ const [unitType, setUnitType] = useState('duration');
+ const [durationValue, setDurationValue] = useState('');
+ const [durationUnit, setDurationUnit] = useState('days');
+ const [quantity, setQuantity] = useState('');
+ const [selectedType, setSelectedType] = useState('');
+ const [selectedGroup, setSelectedGroup] = useState('');
+ const [siteUrl, setSiteUrl] = useState('');
+ const [createUpdateUrl, setCreateUpdateUrl] = useState('');
+ const [isVisible, setIsVisible] = useState(true);
+
+ const [step, setStep] = useState(0);
+
+ 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);
+ } catch (err) {
+ console.error('Gagal ambil produk:', err);
+ }
+ };
+
+ fetchDistinctOptions();
+ }, []);
+
+ const sendDataToN8N = async () => {
+ const match = document.cookie.match(new RegExp('(^| )token=([^;]+)'));
+ if (!match) {
+ alert('Token tidak ditemukan. Silakan login kembali.');
+ return;
+ }
+ const token = match[2];
+
+ const isToken = unitType === 'token';
+ const payload = {
+ name,
+ type: selectedType,
+ image,
+ description,
+ price: price === '' ? null : parseInt(price, 10),
+ currency: 'IDR',
+ duration: isToken ? null : `${parseInt(durationValue || '0', 10)} ${durationUnit}`,
+ quantity: isToken ? parseInt(quantity || '0', 10) : null,
+ unit_type: unitType,
+ sub_product_of: parentId,
+ is_visible: isVisible,
+ group: selectedGroup || null,
+ site_url: siteUrl || null,
+ create_update_url: createUpdateUrl || null,
+ created_at: new Date().toISOString(),
+ updated_at: new Date().toISOString(),
+ };
+
+ try {
+ const response = await fetch(
+ 'https://bot.kediritechnopark.com/webhook/store-production/add-product',
+ {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ Authorization: `Bearer ${token}`,
+ },
+ body: JSON.stringify(payload),
+ }
+ );
+
+ if (response.ok) {
+ alert('Produk berhasil ditambahkan!');
+ if (onSuccess) onSuccess();
+ } else {
+ const errorText = await response.text();
+ console.error('Response Error:', errorText);
+ alert('Gagal mengirim data: ' + response.status);
+ }
+ } catch (error) {
+ console.error('Error sending data to n8n:', error);
+ alert('Terjadi kesalahan saat mengirim data.');
+ }
+ };
+
+ return (
+
+
+ {parentId ? 'Tambah Sub-Produk' : 'Tambah Produk Baru'}
+
+
+ {step === 0 && (
+
+ )}
+
+ {step === 1 && (
+
+ )}
+
+ {step === 2 && (
+
+
+
+
setSelectedType(e.target.value)} />
+
+ {availableTypes.map((type) => (
+
+ ))}
+
+
+
+
+
setSelectedGroup(e.target.value)} />
+
+ {availableGroups.map((group) => (
+
+ ))}
+
+
+
+
+ setSiteUrl(e.target.value)} />
+
+
+
+ setCreateUpdateUrl(e.target.value)} />
+
+
+ )}
+
+
+
+
+
+ {step < 2 ? (
+
+ ) : (
+
+ )}
+
+
+ );
+};
+
+export default CreateProductPage;
diff --git a/src/components/Dashboard.js b/src/components/Dashboard.js
index 075a20c..b7cdd8e 100644
--- a/src/components/Dashboard.js
+++ b/src/components/Dashboard.js
@@ -1,12 +1,15 @@
import React, { useState, useEffect } from 'react';
-import { TrendingUp, TrendingDown, DollarSign, ShoppingCart, Users } from 'lucide-react';
+import { TrendingUp, TrendingDown, DollarSign, ShoppingCart, Users, Plus, GitBranchPlus } from 'lucide-react';
import styles from './Dashboard.module.css';
import processProducts from '../helper/processProducts';
-
-const Dashboard = () => {
- const [unitType, setUnitType] = useState('duration');
- const [durationUnit, setDurationUnit] = useState('day');
+/**
+ * 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);
@@ -14,24 +17,10 @@ const Dashboard = () => {
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'
- },
+ 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 },
@@ -40,48 +29,7 @@ const Dashboard = () => {
{ date: '26/06', items: 900, revenue: 450 },
{ date: '27/06', items: 550, revenue: 200 },
],
- latestTransactions: [
- {
- id: 1,
- name: 'Samantha William',
- amount: 250875,
- date: 'May 22, 2025',
- status: 'confirmed',
- avatar: 'SW'
- },
- {
- id: 2,
- name: 'Kevin Anderson',
- amount: 350620,
- date: 'May 22, 2025',
- status: 'waiting payment',
- avatar: 'KA'
- },
- {
- id: 3,
- name: 'Angela Samantha',
- amount: 870563,
- date: 'May 22, 2025',
- status: 'confirmed',
- avatar: 'AS'
- },
- {
- id: 4,
- name: 'Michael Smith',
- amount: 653975,
- date: 'May 22, 2025',
- status: 'payment expired',
- avatar: 'MS'
- },
- {
- id: 5,
- name: 'Jonathan Sebastian',
- amount: 950000,
- date: 'May 22, 2025',
- status: 'confirmed',
- avatar: 'JS'
- }
- ]
+ latestTransactions: []
});
useEffect(() => {
@@ -91,7 +39,7 @@ const Dashboard = () => {
const token = match[2];
try {
- const res = await fetch('https://bot.kediritechnopark.com/webhook/store-dev/get-products', {
+ const res = await fetch('https://bot.kediritechnopark.com/webhook/store-production/get-products', {
method: 'GET',
headers: {
'Content-Type': 'application/json',
@@ -99,16 +47,15 @@ const Dashboard = () => {
},
});
- const result = await res.json(); // hasil berupa array produk
- const products = result || [];
+ const result = await res.json();
+ const productsArr = result || [];
- // Ambil distinct `type` dan `group` manual
- const types = [...new Set(products.map(p => p.type).filter(Boolean))];
- const groups = [...new Set(products.map(p => p.group).filter(Boolean))];
+ 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(products));
+ setProducts(processProducts(productsArr));
} catch (err) {
console.error('Gagal ambil produk:', err);
}
@@ -117,47 +64,6 @@ const Dashboard = () => {
fetchDistinctOptions();
}, []);
-
- const sendDataToN8N = async (webhookUrl, data) => {
- const match = document.cookie.match(new RegExp('(^| )token=([^;]+)'));
- if (match) {
- const token = match[2];
-
- const payload = {
- ...data,
- duration: data.unit_type === 'token' ? null : data.duration,
- quantity: data.unit_type === 'duration' ? null : data.quantity,
- };
-
- if (!token) {
- alert('Token tidak ditemukan. Silakan login kembali.');
- return;
- }
-
- try {
- const response = await fetch(webhookUrl, {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- 'Authorization': `Bearer ${token}`,
- },
- body: JSON.stringify(payload),
- });
-
- if (response.ok) {
- alert('Dorm berhasil ditambahkan!');
- } else {
- const errorText = await response.text();
- console.error('Response Error:', errorText);
- alert('Gagal mengirim data: ' + response.status);
- }
- } catch (error) {
- console.error('Error sending data to n8n:', error);
- alert('Terjadi kesalahan saat mengirim data.');
- }
- }
- };
-
const formatCurrency = (amount) => new Intl.NumberFormat('id-ID').format(amount);
const getStatusClass = (status) => {
@@ -221,202 +127,63 @@ const Dashboard = () => {