ok
This commit is contained in:
@@ -1,8 +1,6 @@
|
|||||||
import React, { useState, useEffect } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import styles from "../Styles.module.css";
|
import { Container, Row, Col, Card, Button, Tabs, Tab, Form } from "react-bootstrap";
|
||||||
import { Box, Settings, ShoppingCart } from "lucide-react";
|
import { useNavigate } from "react-router-dom";
|
||||||
import { useNavigate } from 'react-router-dom';
|
|
||||||
|
|
||||||
|
|
||||||
const Dashboard = ({
|
const Dashboard = ({
|
||||||
subscriptions,
|
subscriptions,
|
||||||
@@ -13,10 +11,9 @@ const Dashboard = ({
|
|||||||
}) => {
|
}) => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const [activeTab, setActiveTab] = useState("products");
|
const [activeTab, setActiveTab] = useState("products");
|
||||||
const [hoveredCard, setHoveredCard] = useState(null);
|
|
||||||
const [products, setProducts] = useState([]);
|
const [products, setProducts] = useState([]);
|
||||||
|
const [hoveredCard, setHoveredCard] = useState(null);
|
||||||
|
|
||||||
// User Settings form state
|
|
||||||
const [settings, setSettings] = useState({
|
const [settings, setSettings] = useState({
|
||||||
username: "",
|
username: "",
|
||||||
email: "",
|
email: "",
|
||||||
@@ -30,16 +27,32 @@ const Dashboard = ({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
// 🔹 Handle input settings
|
||||||
if (userData) {
|
const handleSettingsChange = (field, value, nested = false) => {
|
||||||
setSettings(userData);
|
if (nested) {
|
||||||
|
setSettings((prev) => ({
|
||||||
|
...prev,
|
||||||
|
profile_data: { ...prev.profile_data, [field]: value }
|
||||||
|
}));
|
||||||
|
} else {
|
||||||
|
setSettings((prev) => ({ ...prev, [field]: value }));
|
||||||
}
|
}
|
||||||
}, [userData]);
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
// 🔹 Save profile
|
||||||
if (!subscriptions) return;
|
const saveSettings = () => {
|
||||||
|
fetch("https://bot.kediritechnopark.com/webhook-test/user-production/data", {
|
||||||
|
method: "PUT",
|
||||||
|
headers: { "Content-Type": "application/json" },
|
||||||
|
body: JSON.stringify(settings)
|
||||||
|
})
|
||||||
|
.then((res) => res.json())
|
||||||
|
.then(() => alert("Settings updated successfully!"))
|
||||||
|
.catch((err) => alert("Error updating settings: " + err));
|
||||||
|
};
|
||||||
|
|
||||||
function groupSubscriptionsByProductName(subs) {
|
// 🔹 Group subscriptions
|
||||||
|
const groupSubscriptionsByProductName = (subs) => {
|
||||||
const result = {};
|
const result = {};
|
||||||
subs.forEach((sub) => {
|
subs.forEach((sub) => {
|
||||||
const name = sub.product_name;
|
const name = sub.product_name;
|
||||||
@@ -54,52 +67,43 @@ const Dashboard = ({
|
|||||||
subscriptions: []
|
subscriptions: []
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const currentEnd = new Date(result[name].end_date);
|
const currentEnd = new Date(result[name].end_date);
|
||||||
const thisEnd = new Date(sub.end_date);
|
const thisEnd = new Date(sub.end_date);
|
||||||
if (thisEnd > currentEnd) {
|
if (thisEnd > currentEnd) result[name].end_date = sub.end_date;
|
||||||
result[name].end_date = sub.end_date;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sub.unit_type === "token") {
|
if (sub.unit_type === "token") {
|
||||||
result[name].quantity += sub.quantity ?? 0;
|
result[name].quantity += sub.quantity ?? 0;
|
||||||
} else {
|
} else {
|
||||||
result[name].quantity += 1;
|
result[name].quantity += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
result[name].subscriptions.push(sub);
|
result[name].subscriptions.push(sub);
|
||||||
});
|
});
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
};
|
||||||
|
|
||||||
|
// 🔹 Fetch produk berdasarkan subscription
|
||||||
|
useEffect(() => {
|
||||||
|
if (!subscriptions) return;
|
||||||
|
|
||||||
const groupedSubs = groupSubscriptionsByProductName(subscriptions);
|
const groupedSubs = groupSubscriptionsByProductName(subscriptions);
|
||||||
const productIds = [...new Set(subscriptions.map((s) => s.product_id))];
|
const productIds = [...new Set(subscriptions.map((s) => s.product_id))];
|
||||||
|
|
||||||
fetch(
|
fetch("https://bot.kediritechnopark.com/webhook/store-production/products", {
|
||||||
"https://bot.kediritechnopark.com/webhook/store-production/products",
|
|
||||||
{
|
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: { "Content-Type": "application/json" },
|
||||||
"Content-Type": "application/json"
|
body: JSON.stringify({ itemsId: productIds })
|
||||||
},
|
})
|
||||||
body: JSON.stringify({ itemsId: productIds})
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.then((res) => res.json())
|
.then((res) => res.json())
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
// Step 1: Enrich base products (without children yet)
|
|
||||||
const enrichedData = Object.values(groupedSubs)
|
const enrichedData = Object.values(groupedSubs)
|
||||||
.filter((group) => data.some((p) => p.id === group.product_id))
|
.filter((group) => data.some((p) => p.id === group.product_id))
|
||||||
.map((group) => {
|
.map((group) => {
|
||||||
const productData = data.find((p) => p.id == group.product_id);
|
const productData = data.find((p) => p.id === group.product_id);
|
||||||
let image = productData?.image || "";
|
let image = productData?.image || "";
|
||||||
let description = productData?.description || "";
|
let description = productData?.description || "";
|
||||||
let site_url = productData?.site_url || "";
|
let site_url = productData?.site_url || "";
|
||||||
if (!image && productData?.sub_product_of) {
|
if (!image && productData?.sub_product_of) {
|
||||||
const parent = data.find(
|
const parent = data.find((p) => p.id === productData.sub_product_of);
|
||||||
(p) => p.id === productData.sub_product_of
|
|
||||||
);
|
|
||||||
image = parent?.image || "";
|
image = parent?.image || "";
|
||||||
description = parent?.description || "";
|
description = parent?.description || "";
|
||||||
site_url = parent?.site_url || "";
|
site_url = parent?.site_url || "";
|
||||||
@@ -124,301 +128,203 @@ const Dashboard = ({
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
// Step 2: Create a quick lookup table for enrichedData
|
|
||||||
const productMap = {};
|
|
||||||
enrichedData.forEach((p) => {
|
|
||||||
console.log(p)
|
|
||||||
productMap[p.name.split("%%%")[1]] = p;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Step 3: Find children in API `data` and attach to parents
|
|
||||||
data
|
|
||||||
.filter((p) => p.sub_product_of) // only those with a parent
|
|
||||||
.forEach((child) => {
|
|
||||||
// ✅ Current logic — attach to the real parent
|
|
||||||
const parent = productMap[child.sub_product_of];
|
|
||||||
if (parent) {
|
|
||||||
parent.children.push(child);
|
|
||||||
}
|
|
||||||
// ➕ New logic — attach to other products with the same sub_product_of
|
|
||||||
Object.values(productMap).forEach((possibleParent) => {
|
|
||||||
if (
|
|
||||||
possibleParent.id !== child.id && // not itself
|
|
||||||
possibleParent.sub_product_of === child.sub_product_of // same parent reference
|
|
||||||
) {
|
|
||||||
possibleParent.children.push(child);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
console.log(enrichedData)
|
|
||||||
setProducts(enrichedData);
|
setProducts(enrichedData);
|
||||||
})
|
})
|
||||||
.catch((err) => console.error("Fetch error:", err));
|
.catch((err) => console.error("Fetch error:", err));
|
||||||
|
|
||||||
}, [subscriptions]);
|
}, [subscriptions]);
|
||||||
|
|
||||||
const handleSettingsChange = (field, value, nested = false) => {
|
|
||||||
if (nested) {
|
|
||||||
setSettings((prev) => ({
|
|
||||||
...prev,
|
|
||||||
profile_data: { ...prev.profile_data, [field]: value }
|
|
||||||
}));
|
|
||||||
} else {
|
|
||||||
setSettings((prev) => ({ ...prev, [field]: value }));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const saveSettings = () => {
|
|
||||||
fetch(
|
|
||||||
"https://bot.kediritechnopark.com/webhook-test/user-production/data",
|
|
||||||
{
|
|
||||||
method: "PUT",
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json"
|
|
||||||
},
|
|
||||||
body: JSON.stringify(settings)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.then((res) => res.json())
|
|
||||||
.then(() => {
|
|
||||||
alert("Settings updated successfully!");
|
|
||||||
})
|
|
||||||
.catch((err) => alert("Error updating settings: " + err));
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ fontFamily: "Inter, system-ui, sans-serif" }}>
|
<Container fluid className="mt-4">
|
||||||
{/* Tabs Navigation */}
|
<Tabs
|
||||||
<div className={styles.navTabs}>
|
activeKey={activeTab}
|
||||||
<button
|
onSelect={(k) => setActiveTab(k)}
|
||||||
className={`${styles.floatMenuItem} ${activeTab === "products" ? styles.floatMenuItemActive : ""
|
className="mb-3"
|
||||||
}`}
|
|
||||||
onClick={() => setActiveTab("products")}
|
|
||||||
>
|
>
|
||||||
<span className={styles.floatMenuTitle}>Produk Saya</span>
|
{/* Produk Saya */}
|
||||||
<Box size={16} className={styles.floatMenuIcon} />
|
<Tab eventKey="products" title="Produk Saya">
|
||||||
</button>
|
<Row>
|
||||||
|
|
||||||
<button
|
|
||||||
className={`${styles.floatMenuItem} ${activeTab === "settings" ? styles.floatMenuItemActive : ""
|
|
||||||
}`}
|
|
||||||
onClick={() => setActiveTab("settings")}
|
|
||||||
>
|
|
||||||
<span className={styles.floatMenuTitle}>Profil Pengguna</span>
|
|
||||||
<Settings size={16} className={styles.floatMenuIcon} />
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button
|
|
||||||
className={`${styles.floatMenuItem} ${activeTab === "orders" ? styles.floatMenuItemActive : ""
|
|
||||||
}`}
|
|
||||||
onClick={() => setActiveTab("orders")}
|
|
||||||
>
|
|
||||||
<span className={styles.floatMenuTitle}>Pembelian</span>
|
|
||||||
<ShoppingCart size={16} className={styles.floatMenuIcon} />
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Tab Content */}
|
|
||||||
{activeTab === "products" && (
|
|
||||||
<section className={styles.Section}>
|
|
||||||
<div className={styles.coursesContainer}>
|
|
||||||
<div className={styles.coursesGrid}>
|
|
||||||
{products.map((product) => (
|
{products.map((product) => (
|
||||||
<div
|
<Col md={4} key={product.id} className="mb-4">
|
||||||
key={product.name}
|
<Card
|
||||||
className={`${styles.courseCard} ${hoveredCard === product.name ? styles.courseCardHover : ""
|
className={`h-100 shadow-sm ${hoveredCard === product.name ? "border-primary" : ""}`}
|
||||||
}`}
|
onMouseEnter={() => setHoveredCard(product.name)}
|
||||||
|
onMouseLeave={() => setHoveredCard(null)}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setSelectedProduct(product);
|
setSelectedProduct(product);
|
||||||
setShowedModal("product");
|
setShowedModal("product");
|
||||||
}}
|
}}
|
||||||
onMouseEnter={() => setHoveredCard(product.name)}
|
|
||||||
onMouseLeave={() => setHoveredCard(null)}
|
|
||||||
>
|
|
||||||
<div>
|
|
||||||
<div
|
|
||||||
className={styles.courseImage}
|
|
||||||
style={{
|
|
||||||
backgroundImage: `url(${product.image})`
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<div className={styles.courseContentTop}>
|
|
||||||
<h3 className={styles.courseTitle}>
|
|
||||||
{product.name.split("%%%")[0]}
|
|
||||||
</h3>
|
|
||||||
<p className={styles.courseDesc}>
|
|
||||||
{product.description}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className={styles.courseContentBottom}>
|
|
||||||
<div className={styles.coursePrice}>
|
|
||||||
<span
|
|
||||||
className={
|
|
||||||
product.price === 0
|
|
||||||
? styles.freePrice
|
|
||||||
: styles.currentPrice
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
|
{product.image && (
|
||||||
|
<Card.Img variant="top" src={product.image} />
|
||||||
|
)}
|
||||||
|
<Card.Body>
|
||||||
|
<Card.Title>{product.name.split("%%%")[0]}</Card.Title>
|
||||||
|
<Card.Text>{product.description}</Card.Text>
|
||||||
|
</Card.Body>
|
||||||
|
<Card.Footer>
|
||||||
|
<small className="text-muted">
|
||||||
{product.unit_type === "duration"
|
{product.unit_type === "duration"
|
||||||
? `Valid until: ${product.end_date
|
? `Valid until: ${
|
||||||
? new Date(
|
|
||||||
product.end_date
|
product.end_date
|
||||||
).toLocaleDateString()
|
? new Date(product.end_date).toLocaleDateString()
|
||||||
: "N/A"
|
: "N/A"
|
||||||
}`
|
}`
|
||||||
: `SISA TOKEN ${product.quantity || 0}`}
|
: `SISA TOKEN ${product.quantity || 0}`}
|
||||||
</span>
|
</small>
|
||||||
</div>
|
<Button
|
||||||
|
variant="primary"
|
||||||
<button
|
size="sm"
|
||||||
className="px-4 py-2 rounded-pill text-white"
|
className="float-end"
|
||||||
style={{
|
|
||||||
background:
|
|
||||||
"linear-gradient(to right, #6a59ff, #8261ee)",
|
|
||||||
border: "none"
|
|
||||||
}}
|
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setSelectedProduct(product);
|
setSelectedProduct(product);
|
||||||
setShowedModal("product");
|
setShowedModal("product");
|
||||||
setWillDo('checkout');
|
setWillDo("checkout");
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Perpanjang
|
Perpanjang
|
||||||
</button>
|
</Button>
|
||||||
</div>
|
</Card.Footer>
|
||||||
</div>
|
</Card>
|
||||||
|
</Col>
|
||||||
))}
|
))}
|
||||||
<div
|
|
||||||
className={`${styles.courseCard} ${hoveredCard === 0 ? styles.courseCardHover : ""
|
{/* Tambah produk baru */}
|
||||||
}`}
|
<Col md={4} className="mb-4">
|
||||||
onMouseEnter={() => setHoveredCard(0)}
|
<Card
|
||||||
onMouseLeave={() => setHoveredCard(null)}
|
className={`h-100 shadow-sm text-center align-items-center justify-content-center`}
|
||||||
onClick={() => navigate('/?tab=products')
|
onClick={() => navigate("/?tab=products")}
|
||||||
}
|
|
||||||
>
|
>
|
||||||
<div>
|
<Card.Body>
|
||||||
+ Tambah produk baru</div>
|
<h5>+ Tambah produk baru</h5>
|
||||||
</div>
|
</Card.Body>
|
||||||
</div>
|
</Card>
|
||||||
</div>
|
</Col>
|
||||||
</section>
|
</Row>
|
||||||
)}
|
</Tab>
|
||||||
|
|
||||||
{activeTab === "settings" && (
|
{/* Profil Pengguna */}
|
||||||
<section className={styles.profileSection}>
|
<Tab eventKey="settings" title="Profil Pengguna">
|
||||||
<h2 className={styles.profileHeading}>Profil</h2>
|
<Form>
|
||||||
<div className={styles.sectionDivider}></div>
|
<Row>
|
||||||
|
<Col md={6}>
|
||||||
<div className={styles.formGrid}>
|
<Form.Group className="mb-3">
|
||||||
<div>
|
<Form.Label>Username</Form.Label>
|
||||||
<label className={styles.label}>Username</label>
|
<Form.Control
|
||||||
<input
|
|
||||||
className={styles.inputField}
|
|
||||||
value={settings.username}
|
value={settings.username}
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
handleSettingsChange("username", e.target.value)
|
handleSettingsChange("username", e.target.value)
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</div>
|
</Form.Group>
|
||||||
<div>
|
</Col>
|
||||||
<label className={styles.label}>Email</label>
|
|
||||||
<input
|
<Col md={6}>
|
||||||
className={styles.inputField}
|
<Form.Group className="mb-3">
|
||||||
|
<Form.Label>Email</Form.Label>
|
||||||
|
<Form.Control
|
||||||
value={settings.email}
|
value={settings.email}
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
handleSettingsChange("email", e.target.value)
|
handleSettingsChange("email", e.target.value)
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</div>
|
</Form.Group>
|
||||||
<div>
|
</Col>
|
||||||
<label className={styles.label}>Full Name</label>
|
</Row>
|
||||||
<input
|
|
||||||
className={styles.inputField}
|
<Row>
|
||||||
|
<Col md={6}>
|
||||||
|
<Form.Group className="mb-3">
|
||||||
|
<Form.Label>Full Name</Form.Label>
|
||||||
|
<Form.Control
|
||||||
value={settings.profile_data.name}
|
value={settings.profile_data.name}
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
handleSettingsChange("name", e.target.value, true)
|
handleSettingsChange("name", e.target.value, true)
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</div>
|
</Form.Group>
|
||||||
<div>
|
</Col>
|
||||||
<label className={styles.label}>Phone</label>
|
<Col md={6}>
|
||||||
<input
|
<Form.Group className="mb-3">
|
||||||
className={styles.inputField}
|
<Form.Label>Phone</Form.Label>
|
||||||
|
<Form.Control
|
||||||
value={settings.profile_data.phone}
|
value={settings.profile_data.phone}
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
handleSettingsChange("phone", e.target.value, true)
|
handleSettingsChange("phone", e.target.value, true)
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</div>
|
</Form.Group>
|
||||||
<div className={styles.fullWidth}>
|
</Col>
|
||||||
<label className={styles.label}>Address</label>
|
</Row>
|
||||||
<input
|
|
||||||
className={styles.inputField}
|
<Form.Group className="mb-3">
|
||||||
|
<Form.Label>Address</Form.Label>
|
||||||
|
<Form.Control
|
||||||
value={settings.profile_data.address}
|
value={settings.profile_data.address}
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
handleSettingsChange("address", e.target.value, true)
|
handleSettingsChange("address", e.target.value, true)
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</div>
|
</Form.Group>
|
||||||
<div>
|
|
||||||
<label className={styles.label}>Company</label>
|
<Row>
|
||||||
<input
|
<Col md={6}>
|
||||||
className={styles.inputField}
|
<Form.Group className="mb-3">
|
||||||
|
<Form.Label>Company</Form.Label>
|
||||||
|
<Form.Control
|
||||||
value={settings.profile_data.company}
|
value={settings.profile_data.company}
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
handleSettingsChange("company", e.target.value, true)
|
handleSettingsChange("company", e.target.value, true)
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</div>
|
</Form.Group>
|
||||||
<div>
|
</Col>
|
||||||
<label className={styles.label}>Profile Image URL</label>
|
<Col md={6}>
|
||||||
<input
|
<Form.Group className="mb-3">
|
||||||
className={styles.inputField}
|
<Form.Label>Profile Image URL</Form.Label>
|
||||||
|
<Form.Control
|
||||||
value={settings.profile_data.image}
|
value={settings.profile_data.image}
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
handleSettingsChange("image", e.target.value, true)
|
handleSettingsChange("image", e.target.value, true)
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</div>
|
</Form.Group>
|
||||||
</div>
|
</Col>
|
||||||
|
</Row>
|
||||||
|
|
||||||
<h2 className={styles.profileHeading}>Ganti password</h2>
|
<Row>
|
||||||
<div className={styles.sectionDivider}></div>
|
<Col md={6}>
|
||||||
<div className={styles.formGrid}>
|
<Form.Group className="mb-3">
|
||||||
<div>
|
<Form.Label>New Password</Form.Label>
|
||||||
<label className={styles.label}>New Password</label>
|
<Form.Control
|
||||||
<input
|
|
||||||
className={styles.inputField}
|
|
||||||
type="password"
|
type="password"
|
||||||
value={settings.password}
|
value={settings.password}
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
handleSettingsChange("password", e.target.value)
|
handleSettingsChange("password", e.target.value)
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</div>
|
</Form.Group>
|
||||||
<div>
|
</Col>
|
||||||
<label className={styles.label}>Re-type New Password</label>
|
<Col md={6}>
|
||||||
<input
|
<Form.Group className="mb-3">
|
||||||
className={styles.inputField}
|
<Form.Label>Re-type New Password</Form.Label>
|
||||||
type="password"
|
<Form.Control type="password" />
|
||||||
/>
|
</Form.Group>
|
||||||
</div>
|
</Col>
|
||||||
</div>
|
</Row>
|
||||||
|
|
||||||
<button className={styles.saveButton} onClick={saveSettings}>
|
<Button variant="success" onClick={saveSettings}>
|
||||||
Save Changes
|
Save Changes
|
||||||
</button>
|
</Button>
|
||||||
</section>
|
</Form>
|
||||||
)}
|
</Tab>
|
||||||
|
|
||||||
{activeTab === "orders" && (
|
{/* Orders */}
|
||||||
<section className={styles.Section}>
|
<Tab eventKey="orders" title="Pembelian">
|
||||||
<h2>My Orders</h2>
|
<h4>My Orders</h4>
|
||||||
<p>Orders list will be displayed here.</p>
|
<p>Orders list will be displayed here.</p>
|
||||||
</section>
|
</Tab>
|
||||||
)}
|
</Tabs>
|
||||||
</div>
|
</Container>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user