ok
This commit is contained in:
@@ -5,7 +5,7 @@ import { useNavigationHelpers } from "../helpers/navigationHelpers";
|
|||||||
import Switch from "react-switch";
|
import Switch from "react-switch";
|
||||||
|
|
||||||
const HeaderBar = styled.div`
|
const HeaderBar = styled.div`
|
||||||
margin-top: 25px;
|
margin-top:${(props) => (props.HeaderMargin)};
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -230,6 +230,7 @@ const Header = ({
|
|||||||
removeConnectedGuestSides,
|
removeConnectedGuestSides,
|
||||||
setIsEditMode,
|
setIsEditMode,
|
||||||
isEditMode,
|
isEditMode,
|
||||||
|
HeaderMargin='25px'
|
||||||
}) => {
|
}) => {
|
||||||
const { goToLogin, goToGuestSideLogin, goToAdminCafes } =
|
const { goToLogin, goToGuestSideLogin, goToAdminCafes } =
|
||||||
useNavigationHelpers(shopId, tableCode);
|
useNavigationHelpers(shopId, tableCode);
|
||||||
@@ -300,7 +301,7 @@ const Header = ({
|
|||||||
return `${cafeName}'s menu`;
|
return `${cafeName}'s menu`;
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<HeaderBar>
|
<HeaderBar HeaderMargin={HeaderMargin}>
|
||||||
<Title HeaderSize={HeaderSize}>
|
<Title HeaderSize={HeaderSize}>
|
||||||
{shopName == null
|
{shopName == null
|
||||||
? HeaderText == null
|
? HeaderText == null
|
||||||
|
|||||||
@@ -390,9 +390,9 @@ export const getFavourite = async (cafeId) => {
|
|||||||
return response.json();
|
return response.json();
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getAnalytics = async (cafeId, filter) => {
|
export const getReports = async (cafeId, filter) => {
|
||||||
const response = await fetch(
|
const response = await fetch(
|
||||||
API_BASE_URL + "/transaction/get-analytics/" + cafeId + "?type=" + filter,
|
API_BASE_URL + "/transaction/reports/" + cafeId + "?type=" + filter,
|
||||||
{
|
{
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
@@ -402,6 +402,13 @@ export const getAnalytics = async (cafeId, filter) => {
|
|||||||
);
|
);
|
||||||
return response.json();
|
return response.json();
|
||||||
};
|
};
|
||||||
|
export const getAnalytics = async (filter) => {
|
||||||
|
const response = await fetch(
|
||||||
|
API_BASE_URL + "/transaction/get-analytics" + "?type=" + filter,
|
||||||
|
getHeaders('POST')
|
||||||
|
);
|
||||||
|
return response.json();
|
||||||
|
};
|
||||||
|
|
||||||
export const getIncome = async (cafeId) => {
|
export const getIncome = async (cafeId) => {
|
||||||
const response = await fetch(
|
const response = await fetch(
|
||||||
|
|||||||
@@ -175,7 +175,7 @@ export const getAllCafeOwner = async (formData) => {
|
|||||||
const token = getLocalStorage("auth");
|
const token = getLocalStorage("auth");
|
||||||
if (token) {
|
if (token) {
|
||||||
try {
|
try {
|
||||||
const response = await fetch(API_BASE_URL + "/user/get-admin", {
|
const response = await fetch(API_BASE_URL + "/transaction/get-analytics", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
@@ -186,6 +186,7 @@ export const getAllCafeOwner = async (formData) => {
|
|||||||
throw new Error(`HTTP error! status: ${response.status}`);
|
throw new Error(`HTTP error! status: ${response.status}`);
|
||||||
}
|
}
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
|
console.log(data)
|
||||||
return data;
|
return data;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error updating user:", error);
|
console.error("Error updating user:", error);
|
||||||
|
|||||||
@@ -1,16 +1,14 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import styles from './LinktreePage.module.css'; // Import the module.css file
|
|
||||||
import { loginUser } from "../helpers/userHelpers";
|
|
||||||
import { ThreeDots } from "react-loader-spinner";
|
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
|
import styles from './LinktreePage.module.css';
|
||||||
import { getLocalStorage, removeLocalStorage } from "../helpers/localStorageHelpers";
|
import { loginUser, getAllCafeOwner, createCafeOwner } from "../helpers/userHelpers";
|
||||||
import { getAllCafeOwner, createCafeOwner } from "../helpers/userHelpers";
|
|
||||||
import { getOwnedCafes, createCafe, updateCafe } from "../helpers/cafeHelpers";
|
import { getOwnedCafes, createCafe, updateCafe } from "../helpers/cafeHelpers";
|
||||||
import { getMyTransactions } from "../helpers/transactionHelpers";
|
import { getMyTransactions } from "../helpers/transactionHelpers";
|
||||||
import { unsubscribeUser } from "../helpers/subscribeHelpers.js";
|
import { unsubscribeUser } from "../helpers/subscribeHelpers.js";
|
||||||
|
import { getLocalStorage, removeLocalStorage } from "../helpers/localStorageHelpers";
|
||||||
|
import { ThreeDots } from "react-loader-spinner";
|
||||||
import Header from '../components/Header';
|
import Header from '../components/Header';
|
||||||
|
import CircularDiagram from "./CircularDiagram";
|
||||||
|
|
||||||
const LinktreePage = ({ user, setModal }) => {
|
const LinktreePage = ({ user, setModal }) => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
@@ -19,203 +17,238 @@ const LinktreePage = ({ user, setModal }) => {
|
|||||||
const [password, setPassword] = useState('');
|
const [password, setPassword] = useState('');
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [error, setError] = useState(false);
|
const [error, setError] = useState(false);
|
||||||
|
|
||||||
const [items, setItems] = useState([]);
|
const [items, setItems] = useState([]);
|
||||||
const [isCreating, setIsCreating] = useState(false);
|
const [isCreating, setIsCreating] = useState(false);
|
||||||
const [newItem, setNewItem] = useState({ name: "", type: "" });
|
const [newItem, setNewItem] = useState({ name: "", type: "" });
|
||||||
const [isModalOpen, setIsModalOpen] = useState(false);
|
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||||
const [expanded, setIsExpand] = useState(false);
|
const [expanded, setIsExpand] = useState(false);
|
||||||
const [expandedCafeId, setExpandedCafeId] = useState(null); // Track which cafe is expanded
|
const [expandedCafeId, setExpandedCafeId] = useState(null);
|
||||||
|
const [selectedItemId, setSelectedItemId] = useState(0);
|
||||||
|
|
||||||
|
// Handle expand/collapse of cafe details
|
||||||
const handleToggleExpand = (cafeId) => {
|
const handleToggleExpand = (cafeId) => {
|
||||||
setExpandedCafeId(expandedCafeId === cafeId ? null : cafeId); // Toggle expand for a specific cafe
|
setExpandedCafeId(expandedCafeId === cafeId ? null : cafeId);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Handle user transactions
|
||||||
const handleMyTransactions = async () => {
|
const handleMyTransactions = async () => {
|
||||||
try {
|
try {
|
||||||
setError(false);
|
setError(false);
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
const response = await getMyTransactions();
|
const response = await getMyTransactions();
|
||||||
|
|
||||||
if (response) {
|
if (response) {
|
||||||
console.log(response)
|
setItems(response);
|
||||||
return response;
|
|
||||||
} else {
|
} else {
|
||||||
setError(true); // Trigger error state in the button
|
setError(true);
|
||||||
console.error('Login failed');
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setError(true);
|
setError(true);
|
||||||
console.error('Error occurred while logging in:', error.message);
|
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false); // Ensure loading state is cleared
|
setLoading(false);
|
||||||
|
console.log(items);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Handle login
|
||||||
const handleLogin = async () => {
|
const handleLogin = async () => {
|
||||||
try {
|
try {
|
||||||
setError(false);
|
setError(false);
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
const response = await loginUser(username, password);
|
const response = await loginUser(username, password);
|
||||||
|
|
||||||
if (response.success) {
|
if (response.success) {
|
||||||
localStorage.setItem('auth', response.token);
|
localStorage.setItem('auth', response.token);
|
||||||
|
window.location.href = response.cafeId ? `/${response.cafeId}` : '/';
|
||||||
if (response.cafeId !== null) {
|
|
||||||
window.location.href = response.cafeId;
|
|
||||||
} else {
|
|
||||||
let destination = '/';
|
|
||||||
window.location.href = destination;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
setError(true); // Trigger error state in the button
|
setError(true);
|
||||||
console.error('Login failed');
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setError(true);
|
setError(true);
|
||||||
console.error('Error occurred while logging in:', error.message);
|
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false); // Ensure loading state is cleared
|
setLoading(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleModalClose = () => {
|
// Handle logout
|
||||||
setIsModalOpen(false);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleLogout = () => {
|
const handleLogout = () => {
|
||||||
removeLocalStorage("auth");
|
removeLocalStorage("auth");
|
||||||
unsubscribeUser();
|
unsubscribeUser();
|
||||||
navigate(0);
|
navigate(0);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Fetch data when the user changes
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (user && user.roleId === 0) {
|
if (user) {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
getAllCafeOwner()
|
switch (user.roleId) {
|
||||||
.then((data) => {
|
case 0:
|
||||||
setItems(data);
|
getAllCafeOwner().then(setItems).catch(console.error).finally(() => setLoading(false));
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
getOwnedCafes(user.userId).then(setItems).catch(console.error).finally(() => setLoading(false));
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
handleMyTransactions();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
})
|
break;
|
||||||
.catch((error) => {
|
}
|
||||||
console.error("Error fetching cafe owners:", error);
|
|
||||||
setLoading(false);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
if (user && user.roleId === 1) {
|
|
||||||
setLoading(true);
|
|
||||||
getOwnedCafes(user.userId)
|
|
||||||
.then((data) => {
|
|
||||||
setItems(data);
|
|
||||||
setLoading(false);
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
console.error("Error fetching owned cafes:", error);
|
|
||||||
setLoading(false);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (user && user.roleId == 3) {
|
|
||||||
handleMyTransactions()
|
|
||||||
.then((data) => {
|
|
||||||
setItems(data);
|
|
||||||
setLoading(false);
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
console.error("Error fetching owned cafes:", error);
|
|
||||||
setLoading(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
console.log(items);
|
||||||
}, [user]);
|
}, [user]);
|
||||||
const handleCreateItem = () => {
|
|
||||||
if (user.roleId < 1) {
|
// Handle create item (admin or cafe owner)
|
||||||
// Create admin functionality
|
const handleCreateItem = async () => {
|
||||||
createCafeOwner(newItem.email, newItem.username, newItem.password)
|
try {
|
||||||
.then((newitem) => {
|
if (user.roleId < 1) {
|
||||||
setItems([...items, { userId: newitem.userId, name: newitem.username }]);
|
const newOwner = await createCafeOwner(newItem.email, newItem.username, newItem.password);
|
||||||
setIsCreating(false);
|
setItems([...items, { userId: newOwner.userId, name: newOwner.username }]);
|
||||||
setNewItem({ name: "", type: "" });
|
} else {
|
||||||
})
|
const newCafe = await createCafe(newItem.name);
|
||||||
.catch((error) => {
|
setItems([...items, { cafeId: newCafe.cafeId, name: newCafe.name }]);
|
||||||
console.error("Error creating admin:", error);
|
}
|
||||||
});
|
setIsCreating(false);
|
||||||
|
setNewItem({ name: "", type: "" });
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error creating item:", error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const formatIncome = (amount) => {
|
||||||
|
if (amount >= 1_000_000_000) {
|
||||||
|
// Format for billions
|
||||||
|
const billions = amount / 1_000_000_000;
|
||||||
|
return billions.toFixed(0) + "b"; // No decimal places for billions
|
||||||
|
} else if (amount >= 1_000_000) {
|
||||||
|
// Format for millions
|
||||||
|
const millions = amount / 1_000_000;
|
||||||
|
return millions.toFixed(2).replace(/\.00$/, "") + "m"; // Two decimal places, remove trailing '.00'
|
||||||
|
} else if (amount >= 1_000) {
|
||||||
|
// Format for thousands
|
||||||
|
const thousands = amount / 1_000;
|
||||||
|
return thousands.toFixed(1).replace(/\.0$/, "") + "k"; // One decimal place, remove trailing '.0'
|
||||||
} else {
|
} else {
|
||||||
// Create cafe functionality
|
// Less than a thousand
|
||||||
createCafe(newItem.name)
|
if (amount != null) return amount.toString();
|
||||||
.then((newitem) => {
|
|
||||||
setItems([...items, { cafeId: newitem.cafeId, name: newitem.name }]);
|
|
||||||
setIsCreating(false);
|
|
||||||
setNewItem({ name: "", type: "" });
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
console.error("Error creating cafe:", error);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<div className={styles.linktreePage}>
|
<>
|
||||||
{/* SVG Icon */}
|
{user && user.roleId < 2 ? (
|
||||||
|
<div className={styles.nonCenteredLinktreePage}>
|
||||||
|
|
||||||
{user && user.roleId < 2 && (
|
<div className={styles.dashboard}>
|
||||||
<div className={styles.dashboard}>
|
<div className={styles.header}>
|
||||||
{loading && <ThreeDots />}
|
|
||||||
{items.map((item, index) => (
|
<Header
|
||||||
<div
|
HeaderText={"selamat siang " + user.username}
|
||||||
key={index}
|
isEdit={() => setIsModalOpen(true)}
|
||||||
onClick={() => navigate("/" + item.cafeId)}
|
isLogout={handleLogout}
|
||||||
className={styles.rectangle}
|
user={user}
|
||||||
>
|
showProfile={true}
|
||||||
<h1>{item.name || item.username}</h1>
|
setModal={setModal}
|
||||||
<div><h1>{item.report?.totalIncome}</h1></div>
|
HeaderMargin='0px'
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
))}
|
<div className={styles.headerCardWrapper}>
|
||||||
{user && user.roleId < 1 ? (
|
<div className={styles.headerCard}>
|
||||||
<div
|
<h1>Total pemasukan</h1>
|
||||||
className={styles.rectangle}
|
</div>
|
||||||
onClick={() => setIsCreating(true)}
|
|
||||||
>
|
|
||||||
Create Client
|
|
||||||
</div>
|
</div>
|
||||||
) : (
|
|
||||||
<div
|
</div>
|
||||||
className={styles.rectangle}
|
|
||||||
onClick={() => setIsCreating(true)}
|
<div style={{ flex: 1 }}>
|
||||||
>
|
<CircularDiagram segments={[]} />
|
||||||
+
|
</div>
|
||||||
|
|
||||||
|
<div style={{ flex: 1 }}>
|
||||||
|
<CircularDiagram segments={[]} />
|
||||||
|
</div>
|
||||||
|
<div className={styles.cafeListWrapper}>
|
||||||
|
<div className={styles.cafeListHeader}>
|
||||||
|
Semua {user.roleId < 1 ? 'penyewa' : 'kedai yang dikau miliki'}
|
||||||
</div>
|
</div>
|
||||||
)}
|
<div className={styles.cafeList}>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{user.roleId < 1 &&
|
||||||
|
<div className={styles.rectangle}
|
||||||
|
style={{ backgroundColor: selectedItemId == -1 ? 'rgb(69, 69, 69)' : 'rgb(114, 114, 114)' }}
|
||||||
|
onClick={() => setSelectedItemId(selectedItemId == 0 ? -1 : 0)}
|
||||||
|
>
|
||||||
|
Tambah penyewa
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
{
|
||||||
|
items && Array.isArray(items.tenants) && items.tenants.length > 0 ? (
|
||||||
|
items.tenants.map((tenant, tenantIndex) => (
|
||||||
|
<>
|
||||||
|
<div key={tenant.userId} onClick={() => setSelectedItemId(selectedItemId == tenant.userId ? 0 : tenant.userId)} style={{ backgroundColor: selectedItemId == tenant.userId ? 'rgb(69, 69, 69)' : 'rgb(114, 114, 114)' }} className={styles.rectangle}>
|
||||||
|
<h3>{tenant.username}</h3>
|
||||||
|
<div>
|
||||||
|
Total Pendapatan: {formatIncome(tenant.totalIncome)} {/* Total Income for the tenant */}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{selectedItemId == tenant.userId && tenant.cafes && tenant.cafes.length > 0 && tenant.cafes.map((cafe, cafeIndex) => (
|
||||||
|
<div>
|
||||||
|
<h5 >↳</h5>
|
||||||
|
<div key={cafe.cafeId} className={styles.subRectangle}
|
||||||
|
onClick={() => setSelectedItemId(selectedItemId === cafe.cafeId ? -1 : cafe.cafeId)}
|
||||||
|
style={{
|
||||||
|
backgroundColor: selectedItemId === cafe.cafeId ? 'rgb(69, 69, 69)' : 'rgb(114, 114, 114)'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{cafe.name}
|
||||||
|
pendapatan {formatIncome(cafe.report?.totalIncome || 0)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</>
|
||||||
|
))
|
||||||
|
) : (
|
||||||
|
<div>No tenants available</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
{user.roleId > 0 &&
|
||||||
|
<div className={styles.rectangle}
|
||||||
|
|
||||||
|
style={{ backgroundColor: selectedItemId == 0 ? 'rgb(69, 69, 69)' : 'rgb(114, 114, 114)' }}
|
||||||
|
onClick={() => { setSelectedItemId(selectedItemId == 0 ? -1 : 0); setModal('create-cafe'); }}
|
||||||
|
>
|
||||||
|
Tambah kedai
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
) : (
|
||||||
{(user.length == 0 || user.roleId > 1) &&
|
<div className={styles.centeredLinktreePage}>
|
||||||
<>
|
|
||||||
<div className={styles.dashboardLine}></div>
|
<div className={styles.dashboardLine}></div>
|
||||||
|
|
||||||
<div className={styles.dashboardContainer}>
|
<div className={styles.dashboardContainer}>
|
||||||
{/* Main Heading */}
|
|
||||||
<div className={styles.mainHeading}>
|
<div className={styles.mainHeading}>
|
||||||
COBA KEDAIMASTER
|
COBA KEDAIMASTER
|
||||||
<div className={styles.swipeContainer}>
|
<div className={styles.swipeContainer}>
|
||||||
<div className={styles.swipeContent}>
|
<div className={styles.swipeContent}>
|
||||||
<div className={styles.swipeItem}>pemesanan langsung dari meja</div>
|
{['pemesanan langsung dari meja', 'pengelolaan pesanan dan keuangan', 'tentukan suasana musik', 'pengelolaan stok dan manajemen', 'jangan pernah ragukan pelanggan'].map((item, index) => (
|
||||||
<div className={styles.swipeItem}>pengelolaan pesanan dan keuangan</div>
|
<div key={index} className={styles.swipeItem}>{item}</div>
|
||||||
<div className={styles.swipeItem}>tentukan suasana musik</div>
|
))}
|
||||||
<div className={styles.swipeItem}>pengelolaan stok dan manajemen</div>
|
|
||||||
<div className={styles.swipeItem}>jangan pernah ragukan pelanggan</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
diskon 0%
|
diskon 0%
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Sub Heading */}
|
|
||||||
<div className={styles.subHeading}>
|
<div className={styles.subHeading}>
|
||||||
Solusi berbasis web untuk memudahkan pengelolaan kedai, dengan fitur yang mempermudah pemilik, kasir, dan tamu berinteraksi.
|
Solusi berbasis web untuk memudahkan pengelolaan kedai, dengan fitur yang mempermudah pemilik, kasir, dan tamu berinteraksi.
|
||||||
</div>
|
</div>
|
||||||
{getLocalStorage('auth') == null &&
|
|
||||||
|
{getLocalStorage('auth') == null && (
|
||||||
<div className={styles.LoginForm}>
|
<div className={styles.LoginForm}>
|
||||||
<div className={`${styles.FormUsername} ${inputtingPassword ? styles.animateForm : styles.reverseForm}`}>
|
<div className={`${styles.FormUsername} ${inputtingPassword ? styles.animateForm : styles.reverseForm}`}>
|
||||||
<label htmlFor="username" className={styles.usernameLabel}>
|
<label htmlFor="username" className={styles.usernameLabel}>---- masuk -------------------------------</label>
|
||||||
---- masuk -------------------------------
|
|
||||||
</label>
|
|
||||||
<input
|
<input
|
||||||
id="username"
|
id="username"
|
||||||
placeholder="username"
|
placeholder="username"
|
||||||
@@ -231,13 +264,12 @@ const LinktreePage = ({ user, setModal }) => {
|
|||||||
|
|
||||||
<div className={`${styles.FormPassword} ${inputtingPassword ? styles.animateForm : styles.reverseForm}`}>
|
<div className={`${styles.FormPassword} ${inputtingPassword ? styles.animateForm : styles.reverseForm}`}>
|
||||||
<span>
|
<span>
|
||||||
<label onClick={() => setInputtingPassword(false)} htmlFor="password" className={styles.usernameLabel}>
|
<label onClick={() => setInputtingPassword(false)} htmlFor="password" className={styles.usernameLabel}> <--- <-- kembali </label>
|
||||||
<--- <-- kembali
|
<label htmlFor="password" className={styles.usernameLabel}> ----- </label>
|
||||||
</label><label htmlFor="password" className={styles.usernameLabel}>
|
<label onClick={() => setModal('reset-password', { username: username })} className={styles.usernameLabel}>
|
||||||
------
|
|
||||||
</label><label onClick={() => setModal('reset-password', { username: username })} htmlFor="password" className={styles.usernameLabel}>
|
|
||||||
lupa password? -
|
lupa password? -
|
||||||
</label></span>
|
</label>
|
||||||
|
</span>
|
||||||
<input
|
<input
|
||||||
id="password"
|
id="password"
|
||||||
placeholder="password"
|
placeholder="password"
|
||||||
@@ -256,133 +288,34 @@ const LinktreePage = ({ user, setModal }) => {
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
}
|
|
||||||
{/* Footer Links */}
|
|
||||||
<div className={styles.footer}>
|
<div className={styles.footer}>
|
||||||
<div className={styles.footerLinks}>
|
<div className={styles.footerLinks}>
|
||||||
<a
|
<a href="https://linktr.ee/discover/trending" target="_blank" rel="noreferrer" className={styles.footerLink}>Pelajari lebih lanjut</a>
|
||||||
href="https://linktr.ee/discover/trending"
|
<a href="https://linktr.ee" target="_blank" rel="noreferrer" className={styles.footerLink}>Tentang kedaimaster.com</a>
|
||||||
target="_blank"
|
|
||||||
rel="noreferrer"
|
|
||||||
className={styles.footerLink}
|
|
||||||
>
|
|
||||||
Pelajari lebih lanjut
|
|
||||||
</a>
|
|
||||||
<a
|
|
||||||
href="https://linktr.ee"
|
|
||||||
target="_blank"
|
|
||||||
rel="noreferrer"
|
|
||||||
className={styles.footerLink}
|
|
||||||
>
|
|
||||||
Tentang kedaimaster.com
|
|
||||||
</a>
|
|
||||||
<a
|
<a
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noreferrer"
|
rel="noreferrer"
|
||||||
className={styles.signupButton}
|
className={styles.signupButton}
|
||||||
style={{ textDecoration: 'none' }}
|
|
||||||
onClick={() => setModal('join')}
|
onClick={() => setModal('join')}
|
||||||
>
|
>
|
||||||
Daftarkan kedaimu
|
Daftarkan kedaimu
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.footerImage}>
|
<div className={styles.footerImage}>
|
||||||
<img
|
<img
|
||||||
style={{ height: '226px', width: '150px', objectFit: 'cover' }}
|
style={{ height: '226px', width: '150px', objectFit: 'cover' }}
|
||||||
src="/kedai.png"
|
src="/kedai.png"
|
||||||
alt="Linktree visual"
|
alt="Linktree visual"
|
||||||
onError={(e) => e.target.src = '/fallback-image.png'}
|
onError={(e) => e.target.src = '/fallback-image.png'}
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{user.length != 0 &&
|
|
||||||
<div className={` ${expanded ? styles.userInfoExpanded : styles.userInfo}`}>
|
|
||||||
<div onClick={() => setIsExpand(!expanded)} className={styles.userInfoExpandButton}>
|
|
||||||
{!expanded ?
|
|
||||||
<svg
|
|
||||||
viewBox="0 0 16 16"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
fill="#000000"
|
|
||||||
style={{ width: '100%', height: '100%' }} // Ensure SVG fits the div
|
|
||||||
>
|
|
||||||
<g id="SVGRepo_bgCarrier" strokeWidth="0"></g>
|
|
||||||
<g id="SVGRepo_tracerCarrier" strokeLinecap="round" strokeLinejoin="round"></g>
|
|
||||||
<g id="SVGRepo_iconCarrier">
|
|
||||||
<path d="m 1 11 c 0 -0.265625 0.105469 -0.519531 0.292969 -0.707031 l 6 -6 c 0.390625 -0.390625 1.023437 -0.390625 1.414062 0 l 6 6 c 0.1875 0.1875 0.292969 0.441406 0.292969 0.707031 s -0.105469 0.519531 -0.292969 0.707031 c -0.390625 0.390625 -1.023437 0.390625 -1.414062 0 l -5.292969 -5.292969 l -5.292969 5.292969 c -0.390625 0.390625 -1.023437 0.390625 -1.414062 0 c -0.1875 -0.1875 -0.292969 -0.441406 -0.292969 -0.707031 z m 0 0" fill={"#2e3436"}></path>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
||||||
:
|
|
||||||
|
|
||||||
<svg
|
|
||||||
viewBox="0 0 16 16"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
fill="#000000"
|
|
||||||
style={{ width: '100%', height: '100%' }} // Ensure SVG fits the div
|
|
||||||
>
|
|
||||||
<g id="SVGRepo_bgCarrier" strokeWidth="0"></g>
|
|
||||||
<g id="SVGRepo_tracerCarrier" strokeLinecap="round" strokeLinejoin="round"></g>
|
|
||||||
<g id="SVGRepo_iconCarrier">
|
|
||||||
<path d="m 1 5 c 0 -0.265625 0.105469 -0.519531 0.292969 -0.707031 c 0.390625 -0.390625 1.023437 -0.390625 1.414062 0 l 5.292969 5.292969 l 5.292969 -5.292969 c 0.390625 -0.390625 1.023437 -0.390625 1.414062 0 c 0.1875 0.1875 0.292969 0.441406 0.292969 0.707031 s -0.105469 0.519531 -0.292969 0.707031 l -6 6 c -0.390625 0.390625 -1.023437 0.390625 -1.414062 0 l -6 -6 c -0.1875 -0.1875 -0.292969 -0.441406 -0.292969 -0.707031 z m 0 0" fill={"#2e3436"}></path>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
<Header
|
|
||||||
HeaderText={"Kedai yang pernah kamu kunjungi"}
|
|
||||||
HeaderSize={'4vw'}
|
|
||||||
showProfile={true}
|
|
||||||
setModal={setModal}
|
|
||||||
isLogout={handleLogout}
|
|
||||||
user={user}
|
|
||||||
/>
|
/>
|
||||||
<div className={styles.ItemContainer} style={{height: expanded?'85%':'43.5%'}}>
|
|
||||||
|
|
||||||
{items.map((item, index) => (
|
|
||||||
<div className={styles.Item}onClick={() => handleToggleExpand(item.cafeId)} key={index}>
|
|
||||||
{/* Render cafes */}
|
|
||||||
<div
|
|
||||||
// Toggle expansion on cafe click
|
|
||||||
className={styles.rectangle}
|
|
||||||
>
|
|
||||||
<h1>{item.name || item.username}</h1>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Render transactions if the cafe is expanded */}
|
|
||||||
{expandedCafeId === item.cafeId && item.transactions && (
|
|
||||||
<div className={styles.Item}>
|
|
||||||
{item.transactions.map((transaction, transactionIndex) => (
|
|
||||||
<div
|
|
||||||
key={transactionIndex}
|
|
||||||
className={styles.transaction}
|
|
||||||
style={{ backgroundColor: 'orange' }}
|
|
||||||
>
|
|
||||||
{transaction.detailedTransactions && transaction.detailedTransactions.map((detailedTransaction, detailedTransactionIndex) => (
|
|
||||||
<div key={detailedTransactionIndex}>
|
|
||||||
<p>Quantity: {detailedTransaction.qty}</p>
|
|
||||||
{detailedTransaction.Item && (
|
|
||||||
<div>
|
|
||||||
<h4>Item Name: {detailedTransaction.Item.name}</h4>
|
|
||||||
<p>Price: {detailedTransaction.Item.price}</p>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
))}
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
</div>
|
</div>
|
||||||
</>
|
</div>
|
||||||
}
|
)}
|
||||||
</div>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/* General container */
|
/* General container */
|
||||||
.linktreePage {
|
.centeredLinktreePage {
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@@ -7,6 +7,14 @@
|
|||||||
background-color: rgb(210, 232, 35);
|
background-color: rgb(210, 232, 35);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.nonCenteredLinktreePage {
|
||||||
|
height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: start;
|
||||||
|
background-color: rgb(193 201 134);
|
||||||
|
}
|
||||||
|
|
||||||
.dashboardLine {
|
.dashboardLine {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
left: 0px;
|
left: 0px;
|
||||||
@@ -319,11 +327,90 @@
|
|||||||
|
|
||||||
|
|
||||||
.rectangle {
|
.rectangle {
|
||||||
height: 150px; /* Height of each rectangle */
|
height: 50px; /* Height of each rectangle */
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
border-radius: 10px; /* Rounded corners */
|
border-radius: 10px; /* Rounded corners */
|
||||||
font-size: 24px;
|
font-size: 20px;
|
||||||
background-color: rgb(114, 114, 114);
|
background-color: rgb(114, 114, 114);
|
||||||
|
margin: 5%;
|
||||||
|
position: relative;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
.subRectangle {
|
||||||
|
height: 50px; /* Height of each rectangle */
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
border-radius: 10px; /* Rounded corners */
|
||||||
|
font-size: 20px;
|
||||||
|
background-color: rgb(114, 114, 114);
|
||||||
|
margin: 5%;
|
||||||
|
position: relative;
|
||||||
|
font-weight: 500;
|
||||||
|
margin-left: 60px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.header {
|
||||||
|
background-color: white;
|
||||||
|
top: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: calc(25vh - 25px);
|
||||||
|
margin-bottom: 15vh;
|
||||||
|
padding-top: 25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.headerCardWrapper {
|
||||||
|
top: 0;
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
bottom: 50vh;
|
||||||
|
justify-content: center;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.headerCard {
|
||||||
|
background-color: #947257;
|
||||||
|
position: relative;
|
||||||
|
width: 90%;
|
||||||
|
border-radius: 20px;
|
||||||
|
height: 40%;
|
||||||
|
}
|
||||||
|
.cafeListWrapper{
|
||||||
|
background-color: white;
|
||||||
|
border-radius: 20px 20px 0 0;
|
||||||
|
bottom: 0;
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
max-height: 164.5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cafeListHeader{
|
||||||
|
background-color: white;
|
||||||
|
border-radius: 20px 20px 0 0;
|
||||||
|
bottom: 0;
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
top: -45px;
|
||||||
|
background-color: #b09c72;
|
||||||
|
text-align: center;
|
||||||
|
padding-top: 10px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
.cafeList{
|
||||||
|
background-color: white;
|
||||||
|
border-radius: 20px 20px 0 0;
|
||||||
|
bottom: 0;
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.itemInput{
|
||||||
|
width: 50%;
|
||||||
|
height: 60%;
|
||||||
|
border-radius: 14px;
|
||||||
}
|
}
|
||||||
@@ -2,7 +2,7 @@ import React, { useEffect, useState } from "react";
|
|||||||
import { ThreeDots } from "react-loader-spinner";
|
import { ThreeDots } from "react-loader-spinner";
|
||||||
import {
|
import {
|
||||||
getFavourite,
|
getFavourite,
|
||||||
getAnalytics,
|
getReports,
|
||||||
getIncome,
|
getIncome,
|
||||||
} from "../helpers/transactionHelpers.js";
|
} from "../helpers/transactionHelpers.js";
|
||||||
import CircularDiagram from "./CircularDiagram";
|
import CircularDiagram from "./CircularDiagram";
|
||||||
@@ -115,7 +115,7 @@ const App = ({ cafeId,
|
|||||||
try {
|
try {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
// Fetch the analytics data with the selected filter
|
// Fetch the analytics data with the selected filter
|
||||||
const analyticsData = await getAnalytics(cafeId, filter);
|
const analyticsData = await getReports(cafeId, filter);
|
||||||
console.log(analyticsData);
|
console.log(analyticsData);
|
||||||
if (analyticsData) setAnalytics(analyticsData);
|
if (analyticsData) setAnalytics(analyticsData);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
Reference in New Issue
Block a user