This commit is contained in:
zadit
2024-10-17 00:15:35 +07:00
parent 4dd12f3835
commit 8f50909e1a
23 changed files with 415 additions and 177 deletions

16
package-lock.json generated
View File

@@ -8031,14 +8031,6 @@
"tslib": "^2.0.3"
}
},
"node_modules/dotenv": {
"version": "10.0.0",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz",
"integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==",
"engines": {
"node": ">=10"
}
},
"node_modules/dotenv-expand": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz",
@@ -16193,6 +16185,14 @@
}
}
},
"node_modules/react-scripts/node_modules/dotenv": {
"version": "10.0.0",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz",
"integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==",
"engines": {
"node": ">=10"
}
},
"node_modules/react-switch": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/react-switch/-/react-switch-7.0.0.tgz",

View File

@@ -20,10 +20,10 @@ self.addEventListener("notificationclick", (event) => {
const { cafeId, transactionId } = event.notification.data; // Get the notification data
// Open the URL with the cafeId and transactionId
event.waitUntil(
clients.openWindow(
`https://srrk5s-3000.csb.app/${cafeId}?modal=new_transaction&transactionId=${transactionId}`
)
);
// Dynamically detect the domain and construct the URL
const domainUrl = self.location.origin;
const url = `${domainUrl}/${cafeId}?modal=new_transaction&transactionId=${transactionId}`;
// Open the constructed URL
event.waitUntil(clients.openWindow(url));
});

View File

@@ -142,20 +142,6 @@ function App() {
setGuestSides(sessionLeft.guestSideList);
};
// const checkNotifications = async (userId) => {
// try {
// const permissionGranted =
// await NotificationService.requestNotificationPermission(setModal);
// if (permissionGranted) {
// await SubscriptionService.subscribeUserToNotifications(userId);
// } else {
// setModal("blocked_notification");
// console.log("req notif");
// }
// } catch (error) {
// console.error("Error handling notifications:", error);
// }
// };
useEffect(() => {
if (socket == null) return;
@@ -227,6 +213,7 @@ function App() {
removeLocalStorage("auth");
setDeviceType("guestDevice");
} else {
console.log(data)
setUser(data.data.user);
if (
data.data.user.password == "unsetunsetunset" &&

View File

@@ -124,7 +124,7 @@ export default function Footer({
</div>
{/* Rounded Rectangle with "Scan Meja" and QR Icon */}
{showTable && shopId && (
{/* {showTable && shopId && (
<div
ref={scanMejaRef}
onClick={table.length == 0 ? goToScan : handleScanMejaClick}
@@ -150,7 +150,7 @@ export default function Footer({
</button>
)}
</div>
)}
)} */}
</div>
);
}

View File

@@ -3,7 +3,7 @@
.footer-rect {
height: 75px;
background-color: #fff;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.5);
display: flex;
justify-content: space-around;
/* Adjust spacing between SVG icons */

View File

@@ -301,7 +301,7 @@ const Header = ({
<Title>
{shopName == null
? HeaderText == null
? "Groovebrew"
? "kedaimaster"
: HeaderText
: generateMenuHeader(shopName)}
</Title>
@@ -331,12 +331,13 @@ const Header = ({
Edit profile
</Child>
)}
{shopId && user.roleId == 1 && (
<Child onClick={goToAdminCafes}>see your {user.userId == shopOwnerId ? 'other' : ''} cafes</Child>)}
{shopId &&
user.userId == shopOwnerId &&
user.username !== undefined &&
user.roleId === 1 && (
<>
<Child onClick={goToAdminCafes}>see your other cafes</Child>
{/* <Child onClick={() => setModal("update_stock")}>
update stock
@@ -365,7 +366,7 @@ const Header = ({
</Child>
<Child hasChildren>
clerks
<Child onClick={() => setModal("craete_account_clerk")}>
<Child onClick={() => setModal("create_clerk")}>
+ Add clerk
</Child>
{shopClerks &&

View File

@@ -205,11 +205,11 @@ const Item = ({
<div className={styles.itemQty}>
<button
className={styles.addButton}
style={{ backgroundColor: !isAvailable ? "gray" : "#4da94d" }}
style={{ backgroundColor: !isAvailable ? "gray" : "inherit" }}
onClick={handlePlusClick}
disabled={!isAvailable} // Optionally disable the button if not available
>
Tambah
Pesan
</button>
</div>
) : (

View File

@@ -33,7 +33,7 @@
.itemImage {
width: 139px;
height: 149px;
border-radius: 20px;
border-radius: 10px;
margin-right: 10px;
object-fit: cover;
position: relative;
@@ -167,11 +167,13 @@
}
.addButton {
background-color: #04aa6d;
border: none;
color: white;
background-color: #ffffff;
border: 2px solid #73a585;
/* border: none; */
color: #73a585;
display: inline-block;
font-size: 16px;
font-weight: 600;
cursor: pointer;
width: 95px;
height: 35px;

View File

@@ -151,6 +151,7 @@ const ItemLister = ({
const handleImageChange = (previewUrl, selectedImage) => {
setSelectedImage(selectedImage);
console.log(selectedImage);
console.log(previewUrl);
setPreviewUrl(previewUrl);
};
@@ -288,10 +289,13 @@ const ItemLister = ({
handleCreateItem(itemTypeId, name, price, selectedImage);
}
} else {
console.log(selectedImage)
console.log(previewUrl)
const itemType = await createItemType(
shopId,
editedTypeName,
selectedImage
selectedImage,
previewUrl
);
console.log(itemType);
for (const { name, price, selectedImage } of itemsToCreate) {
@@ -301,6 +305,7 @@ const ItemLister = ({
// Clear the itemsToUpdate after saving
setItemsToUpdate([]);
setIsEditing(false);
if (handleUnEdit) handleUnEdit();
} catch (error) {
console.error("Failed to save item type:", error);
}
@@ -503,9 +508,8 @@ const ItemLister = ({
)}
<div className={styles["item-list"]}>
{user &&
user.roleId == 1 &&
user.userId == shopOwnerId &&
{user &&(
user.userId == shopOwnerId || user.cafeId == shopId) &&
isEditMode && (
<>
{!isAddingNewItem && (

View File

@@ -1,15 +1,13 @@
/* ItemLister.module.css */
.item-lister {
border-top: 1px solid #888;
width: 100%;
padding: 10px; /* Adjust padding as needed */
box-sizing: border-box; /* Ensure padding doesn't affect width */
white-space: break-spaces;
}
.item-lister:last-child {
margin-bottom: 50px;
}
.fullscreen {
position: fixed; /* Keep the container fixed */
top: 0; /* Adjust the top position as needed */
@@ -30,6 +28,7 @@
height: calc(49vw - 20px);
}
.title-container {
display: flex;
align-items: center;

View File

@@ -2,7 +2,7 @@ import React, { useState, useRef, useEffect } from "react";
import smoothScroll from "smooth-scroll-into-view-if-needed";
import "./ItemTypeLister.css";
import ItemType from "./ItemType";
import { createItemType } from "../helpers/itemHelper.js";
import { createItem, createItemType } from "../helpers/itemHelper.js";
import { getImageUrl } from "../helpers/itemHelper";
import ItemLister from "./ItemLister";
const ItemTypeLister = ({
@@ -98,18 +98,16 @@ const ItemTypeLister = ({
>
{isEditMode &&
!isAddingNewItem &&
user &&
user.roleId === 1 &&
user.userId === shopOwnerId && (
user && (
user.userId == shopOwnerId || user.cafeId == shopId) && (
<ItemType
onClick={toggleAddNewItem}
name={"create"}
imageUrl={getImageUrl("uploads/addnew.png")}
/>
)}
{user &&
user.roleId === 1 &&
user.userId === shopOwnerId &&
{user &&(
user.userId == shopOwnerId || user.cafeId == shopId) &&
isAddingNewItem && (
<>
<ItemLister
@@ -119,7 +117,7 @@ const ItemTypeLister = ({
typeName={"add new"}
itemList={items}
isEditMode={true}
handleCreateItem={handleCreateItem}
handleCreateItem={(itemTypeId, name, price, selectedImage) => createItem(shopId, name, price, selectedImage,itemTypeId)}
beingEditedType={beingEditedType}
setBeingEditedType={setBeingEditedType}
alwaysEdit={true}
@@ -137,8 +135,8 @@ const ItemTypeLister = ({
{itemTypes &&
itemTypes.map(
(itemType) =>
((user && user.roleId === 1 && user.userId === shopOwnerId) ||
itemType.itemList.length > 0) && (
(
itemType.itemList.length > 0 || (user && (user.userId == shopOwnerId || user.cafeId == shopId))) && (
<ItemType
key={itemType.itemTypeId}
name={itemType.name}

View File

@@ -1,5 +1,6 @@
import React from "react";
import styles from "./Modal.module.css";
import CreateClerk from "../pages/CreateClerk"
import TablesPage from "./TablesPage.js";
import PaymentOptions from "./PaymentOptions.js";
import TableMaps from "../components/TableMaps";
@@ -37,6 +38,7 @@ const Modal = ({ shop, isOpen, onClose, modalContent }) => {
</button>
{modalContent === "req_notification" && <NotificationBlocked />}
{modalContent === "blocked_notification" && <NotificationBlocked />}
{modalContent === "create_clerk" && <CreateClerk shopId={shop.cafeId} />}
{modalContent === "edit_tables" && <TablesPage shop={shop} />}
{modalContent === "new_transaction" && (
<Transaction propsShopId={shop.cafeId} />

View File

@@ -1,7 +1,7 @@
.music-player {
position: relative;
width: 95%;
margin: -10px auto 20px;
margin: 7px auto 20px;
/* Added padding for top and bottom */
color: white;
box-sizing: border-box;
@@ -24,7 +24,7 @@
/* Center the background image */
filter: blur(1.5px);
-webkit-filter: blur(1.5px);
border-radius: 23px 23px 0 0;
border-radius: 13px 13px 0 0;
background-color: rgb(95 121 89);
/* Rounded corners at the top */
text-align: right;
@@ -32,6 +32,8 @@
}
.current-name {
white-space: nowrap;
pointer-events: none;
position: relative;
z-index: 2;
text-align: left;
@@ -41,7 +43,29 @@
/* Text shadow for readability */
}
/* styles.css */
@keyframes slideAnimation {
0% {
margin-left: 100vw;
}
10% {
margin-left: 30px;
}
70% {
margin-left: 30px;
}
100% {
margin-left: -100vw;
}
}
.animated-text {
animation: slideAnimation 3s linear infinite; /* 4s duration for the animation */
white-space: nowrap; /* Prevent text from wrapping */
}
.current-artist {
pointer-events: none;
position: relative;
z-index: 2;
text-align: left;
@@ -52,6 +76,7 @@
}
.progress-container {
pointer-events: none;
position: relative;
z-index: 2;
text-align: left;
@@ -104,9 +129,10 @@
position: relative;
left: 0;
right: 0;
background-color: rgb(29, 185, 84);
/* background-color: rgb(29, 185, 84); */
background-color: #73a585;
/* background-color: rgb(218 163 99); */
border-radius: 0 0 23px 23px;
border-radius: 0 0 13px 13px;
/* Rounded corners at the bottom */
cursor: pointer;
text-align: center;
@@ -134,7 +160,9 @@
display: flex;
align-items: center;
padding: 10px;
background-color: rgb(29, 185, 84);
/* background-color: rgb(29, 185, 84); */
background-color: #73a585;
}
.search-box input[type="text"] {

View File

@@ -6,6 +6,7 @@ import MusicComponent from "./MusicComponent";
export function MusicPlayer({ socket, shopId, user, isSpotifyNeedLogin }) {
const [currentTime, setCurrentTime] = useState(0);
const [trackLength, setTrackLength] = useState(0);
const [viewing, setViewing] = useState(false); // State for expansion
const [expanded, setExpanded] = useState(false); // State for expansion
const [songName, setSongName] = useState("");
@@ -251,6 +252,9 @@ export function MusicPlayer({ socket, shopId, user, isSpotifyNeedLogin }) {
return `${minutes}:${formattedSeconds}`;
};
const toggleView = () => {
setViewing(!viewing);
};
const toggleExpand = () => {
setExpanded(!expanded);
};
@@ -263,9 +267,47 @@ export function MusicPlayer({ socket, shopId, user, isSpotifyNeedLogin }) {
}
}, [expanded]);
const [text, setText] = useState("Awaiting the next hit");
const textIndex = useRef(0);
const [messages, setMessages] = useState(["Awaiting the next hit", "Click to request your fav song"]);
useEffect(() => {
// Update the messages based on currentSong
const newMessages = [
currentSong != null && currentSong.item != undefined
? `${currentSong.item.artists[0].name} - ${currentSong.item.name}`
: "Awaiting the next hit",
"Click to request your fav song"
];
setMessages(newMessages);
setText(newMessages[0]); // Update the text state to the first message
const element = document.querySelector('.animated-text');
// Check if the element exists before adding the event listener
if (element) {
const handleAnimationIteration = () => {
// Toggle between the two text values based on the current index
textIndex.current = (textIndex.current + 1) % messages.length;
setText(messages[textIndex.current]);
};
element.addEventListener('animationiteration', handleAnimationIteration);
return () => {
element.removeEventListener('animationiteration', handleAnimationIteration);
};
}
}, [currentSong]); // Run effect when currentSong changes
return (
<div className={`music-player ${expanded ? "expanded" : ""}`}>
<div className={`music-player`} style={{ marginBottom: `${viewing? '-10px' : ''}` }}>
<div
onClick={toggleView}
className="current-bgr"
style={{ backgroundImage: `url(${backgroundImage})` }}
>
@@ -286,12 +328,15 @@ export function MusicPlayer({ socket, shopId, user, isSpotifyNeedLogin }) {
))}
</div>
<div className="current-info">
<div className="current-name">
<div className="current-info" >
<div
className={`current-name ${viewing? '' : 'animated-text'}`} style={{margin:`${viewing? '35px 30px' : '13px 30px'}`}}>
{currentSong.item && currentSong.item.name
? currentSong.item.name
: "Awaiting the next hit"}
? (viewing? currentSong.item.name:text)
:
viewing? messages[0]:text}
</div>
{viewing && <>
<div className="current-artist">
{currentSong.item &&
currentSong.item.album &&
@@ -322,8 +367,11 @@ export function MusicPlayer({ socket, shopId, user, isSpotifyNeedLogin }) {
>
{formatTime(trackLength)}
</div>
</div></>
}
</div>
</div>
{viewing &&
<>
<div
className={`expandable-container ${expanded ? "expanded" : ""}`}
ref={expandableContainerRef}
@@ -390,7 +438,7 @@ export function MusicPlayer({ socket, shopId, user, isSpotifyNeedLogin }) {
<div className="expand-button" onClick={toggleExpand}>
<h5>
{expanded
? "collapse"
? "︿"
: currentSong.item &&
currentSong.item.album &&
currentSong.item.album.images[0] &&
@@ -398,7 +446,8 @@ export function MusicPlayer({ socket, shopId, user, isSpotifyNeedLogin }) {
? "expand"
: "request your song"}
</h5>
</div>
</div></>
}
</div>
);
}

View File

@@ -1,6 +1,7 @@
import React, { useState, useEffect } from "react";
import React, {useState} from "react";
import QRCodeWithBackground from "./QR"; // Adjust path as needed
const TableList = ({ shop, tables, onSelectTable, selectedTable }) => {
const TableList = ({ shop, tables, onSelectTable, selectedTable, handleSetTableNo, handleAddTable }) => {
const [initialPos, setInitialPos] = useState({
left: shop.xposition,
top: shop.yposition,
@@ -21,16 +22,16 @@ const TableList = ({ shop, tables, onSelectTable, selectedTable }) => {
}
};
const handleBackgroundUrlChange = (newUrl) => {
setBgImageUrl(newUrl);
};
const handleQrSave = (qrPosition, qrSize, bgImage) => {
setInitialPos(qrPosition);
setInitialSize(qrSize);
setBgImageUrl(bgImage);
};
const handleCreateTable = () => {
handleAddTable();
};
return (
<div
style={{
@@ -71,6 +72,43 @@ const TableList = ({ shop, tables, onSelectTable, selectedTable }) => {
/>
)}
</li>
{/* Add new table input */}
<li
style={{
backgroundColor: "lightgreen",
marginBottom: "10px",
padding: "10px",
borderRadius: "4px",
boxShadow: "0 2px 4px rgba(0,0,0,0.1)",
}}
>
<input
type="text"
placeholder="Enter table number"
onChange={handleSetTableNo} // Directly using the parent function
style={{
width: "100%",
padding: "8px",
marginBottom: "10px",
borderRadius: "4px",
border: "1px solid #ccc",
}}
/>
<button
onClick={handleCreateTable}
style={{
width: "100%",
padding: "10px",
backgroundColor: "#28a745",
color: "white",
borderRadius: "4px",
border: "none",
cursor: "pointer",
}}
>
Add Table
</button>
</li>
{tables &&
tables
.filter((table) => table.tableNo !== 0)

View File

@@ -130,10 +130,10 @@ const TablesPage = ({ shop }) => {
};
const handleSave = async () => {
if (newTable) {
// if (newTable) {
try {
const createdTable = await createTable(shop.cafeId, {
...newTable,
// ...newTable,
tableNo,
});
setTables([...tables, createdTable]);
@@ -143,28 +143,28 @@ const TablesPage = ({ shop }) => {
} catch (error) {
console.error("Error creating table:", error);
}
} else if (selectedTable) {
try {
const updatedTable = await updateTable(shop.cafeId, {
...selectedTable,
tableNo,
});
setTables(
tables.map((table) =>
table.tableId === updatedTable.tableId ? updatedTable : table
)
);
setOriginalTables(
tables.map((table) =>
table.tableId === updatedTable.tableId ? updatedTable : table
)
);
setSelectedTable(null);
setTableNo(""); // Reset table name
} catch (error) {
console.error("Error updating table:", error);
}
}
// } else if (selectedTable) {
// try {
// const updatedTable = await updateTable(shop.cafeId, {
// ...selectedTable,
// tableNo,
// });
// setTables(
// tables.map((table) =>
// table.tableId === updatedTable.tableId ? updatedTable : table
// )
// );
// setOriginalTables(
// tables.map((table) =>
// table.tableId === updatedTable.tableId ? updatedTable : table
// )
// );
// setSelectedTable(null);
// setTableNo(""); // Reset table name
// } catch (error) {
// console.error("Error updating table:", error);
// }
// }
};
const handleSetTableNo = (event) => {
@@ -207,6 +207,8 @@ const TablesPage = ({ shop }) => {
tables={tables}
onSelectTable={handleSelect}
selectedTable={selectedTable}
handleSetTableNo={handleSetTableNo}
handleAddTable={handleSave}
/>
</div>
);

View File

@@ -1,5 +1,5 @@
// src/config.js
const API_BASE_URL = "https://wxf6vz-5000.csb.app"; // Replace with your actual backend URL
const API_BASE_URL = 'https://9qc65z-5000.csb.app';
export default API_BASE_URL;

View File

@@ -165,12 +165,19 @@ export async function updateItemAvalilability(itemId, isAvailable) {
throw error;
}
}
export async function createItemType(shopId, name, selectedImage) {
export async function createItemType(shopId, name, selectedImage, previewUrl) {
try {
const formData = new FormData();
formData.append("name", name);
// Check if selectedImage is provided
if (selectedImage) {
formData.append("image", selectedImage);
} else if (previewUrl) {
// Remove the API_BASE_URL and any leading slashes from previewUrl
const processedPreviewUrl = previewUrl.replace(API_BASE_URL, "").replace(/^\/+/, "");
formData.append("sampleImage", processedPreviewUrl);
}
const response = await fetch(`${API_BASE_URL}/item/createType/${shopId}`, {
method: "POST",
@@ -192,6 +199,7 @@ export async function createItemType(shopId, name, selectedImage) {
throw error;
}
}
export async function updateItemType(
shopId,
itemTypeId,

View File

@@ -193,12 +193,12 @@ export const getAllCafeOwner = async (formData) => {
}
};
export const createCafeOwner = async (shopId, email, username, password) => {
export const createCafeOwner = async (email, username, password) => {
const token = getLocalStorage("auth");
if (token) {
try {
const response = await fetch(
API_BASE_URL + "/user/create-clerk/" + shopId,
API_BASE_URL + "/user/create-admin/" ,
{
method: "POST",
headers: {
@@ -276,6 +276,7 @@ export const createClerks = async (shopId, email, username, password) => {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
console.log(data)
return data;
} catch (error) {
console.error("Error getting clerk:", error);

View File

@@ -20,7 +20,7 @@ import Header from "../components/Header";
import { ThreeDots } from "react-loader-spinner";
import { updateLocalStorage } from "../helpers/localStorageHelpers";
import { updateLocalStorage, removeLocalStorage } from "../helpers/localStorageHelpers";
import { unsubscribeUser } from "../helpers/subscribeHelpers.js";
import WelcomePage from "./WelcomePage.js";
@@ -108,7 +108,7 @@ function CafePage({
};
const handleLogout = () => {
updateLocalStorage("auth", "");
removeLocalStorage("auth");
unsubscribeUser();
navigate(0);
};
@@ -172,9 +172,12 @@ function CafePage({
setIsEditMode={(e) => setIsEditMode(e)}
isEditMode={isEditMode}
/>
<div style={{ marginTop: "5px" }}></div>
<SearchInput shopId={shopId} tableCode={table.tableCode} />
<div style={{ marginTop: "15px" }}></div>
<MusicPlayer
socket={socket}
shopId={shopId}
user={user}
isSpotifyNeedLogin={isSpotifyNeedLogin}
/>
<ItemTypeLister
user={user}
shopOwnerId={shopOwnerId}
@@ -186,22 +189,8 @@ function CafePage({
beingEditedType={beingEditedType}
setBeingEditedType={setBeingEditedType}
/>
<div style={{ marginTop: "-13px" }}></div>
{filterId === 0 ? (
<>
<h2 className="title">Music Req.</h2>
<MusicPlayer
socket={socket}
shopId={shopId}
user={user}
isSpotifyNeedLogin={isSpotifyNeedLogin}
/>
</>
) : (
<div style={{ marginTop: "35px" }}></div>
)}
<div style={{ marginTop: "-15px" }}></div>
{/* <div style={{ marginTop: "15px" }}></div> */}
{shopItems
.filter(
(itemType) =>

View File

@@ -163,9 +163,10 @@ export default function Invoice({ table, sendParam, deviceType, socket }) {
/>
))}
{table.tableNo != null && (
<div className={styles.OrderTypeContainer}>
<span htmlFor="orderType">Order Type:</span>
<select
<span htmlFor="orderType">Serve to table {table.tableNo}</span>
{/* <select
id="orderType"
value={orderType}
onChange={handleOrderTypeChange}
@@ -175,10 +176,9 @@ export default function Invoice({ table, sendParam, deviceType, socket }) {
)}
<option value="pickup">Pickup</option>
{table == null && <option value="serve">Serve</option>}
{/* tableId harus di check terlebih dahulu untuk mendapatkan tableNo */}
</select>
</select> */}
</div>
)}
{orderType === "serve" && table.length < 1 && (
<div className={styles.OrderTypeContainer}>
<span htmlFor="orderType">Serve to:</span>

111
src/pages/CreateClerk.js Normal file
View File

@@ -0,0 +1,111 @@
import React, { useState } from 'react';
import { createClerks } from '../helpers/userHelpers'; // Adjust the import path as needed
const CreateClerk = ({ shopId }) => {
const [email, setEmail] = useState('');
const [username, setUsername] = useState('');
const [password, setPassword] = useState('');
const [loading, setLoading] = useState(false);
const [message, setMessage] = useState('');
const handleSubmit = async (event) => {
event.preventDefault();
setLoading(true);
setMessage('');
// Basic validation
if (!email || !username || !password) {
setMessage('All fields are required');
setLoading(false);
return;
}
try {
const create = await createClerks(shopId, email, username, password);
if(create) setMessage('Clerk created successfully');
else setMessage('failed')
} catch (error) {
setMessage('Error creating clerk');
} finally {
setLoading(false);
}
};
return (
<div style={styles.container}>
<h2 style={styles.header}>Create Clerk</h2>
<form onSubmit={handleSubmit} style={styles.form}>
<input
type="email"
placeholder="Email"
value={email}
onChange={(e) => setEmail(e.target.value)}
style={styles.input}
/>
<input
type="text"
placeholder="Username"
value={username}
onChange={(e) => setUsername(e.target.value)}
style={styles.input}
/>
<input
type="password"
placeholder="Password"
value={password}
onChange={(e) => setPassword(e.target.value)}
style={styles.input}
/>
<button type="submit" style={styles.button} disabled={loading}>
{loading ? 'Creating...' : 'Create Clerk'}
</button>
{message && <p style={styles.message}>{message}</p>}
</form>
</div>
);
};
// Basic styling to make it mobile-friendly
const styles = {
container: {
width: '100%',
maxWidth: '400px',
margin: '0 auto',
padding: '20px',
boxSizing: 'border-box',
},
header: {
textAlign: 'center',
marginBottom: '20px',
},
form: {
display: 'flex',
flexDirection: 'column',
gap: '15px',
},
input: {
padding: '10px',
fontSize: '16px',
borderRadius: '5px',
border: '1px solid #ccc',
width: '100%',
boxSizing: 'border-box',
},
button: {
padding: '10px',
fontSize: '16px',
borderRadius: '5px',
border: 'none',
backgroundColor: '#28a745',
color: 'white',
cursor: 'pointer',
},
message: {
textAlign: 'center',
color: 'red',
marginTop: '10px',
},
};
export default CreateClerk;

View File

@@ -3,7 +3,7 @@ import styles from "./Dashboard.module.css"; // Import module CSS for styling
import Header from "../components/Header";
import { useNavigate } from "react-router-dom";
import AccountUpdateModal from "../components/AccountUpdateModal";
import { updateLocalStorage } from "../helpers/localStorageHelpers";
import { removeLocalStorage } from "../helpers/localStorageHelpers";
import { getAllCafeOwner, createCafeOwner } from "../helpers/userHelpers";
import { getOwnedCafes, createCafe, updateCafe } from "../helpers/cafeHelpers";
@@ -50,7 +50,7 @@ const Dashboard = ({ user, setModal }) => {
};
const handleLogout = () => {
updateLocalStorage("auth", "");
removeLocalStorage("auth");
unsubscribeUser();
navigate(0);
};
@@ -58,9 +58,9 @@ const Dashboard = ({ user, setModal }) => {
const handleCreateItem = () => {
if (user.roleId < 1) {
// Create admin functionality
createCafeOwner(newItem.name)
createCafeOwner(newItem.email, newItem.username, newItem.password)
.then(() => {
setItems([...items, { name: newItem.name }]);
setItems([...items, { name: newItem.username }]);
setIsCreating(false);
setNewItem({ name: "", type: "" });
})
@@ -84,7 +84,7 @@ const Dashboard = ({ user, setModal }) => {
return (
<>
<Header
HeaderText={"GrooveBrew"}
HeaderText={"kedaimaster"}
isEdit={() => setIsModalOpen(true)}
isLogout={handleLogout}
user={user}
@@ -132,12 +132,31 @@ const Dashboard = ({ user, setModal }) => {
{isCreating && (
<div className={styles.createModal}>
<h2>Create New {user.roleId < 1 ? "Admin" : "Cafe"}</h2>
{user.roleId < 1 ?<>
<input
type="email"
value={newItem.email}
onChange={(e) => setNewItem({ ...newItem, email: e.target.value })}
placeholder="email"
/>
<input
type="text"
value={newItem.username}
onChange={(e) => setNewItem({ ...newItem, username: e.target.value })}
placeholder="username"
/>
<input
type="password"
value={newItem.password}
onChange={(e) => setNewItem({ ...newItem, password: e.target.value })}
placeholder="Password"
/></> :
<input
type="text"
value={newItem.name}
onChange={(e) => setNewItem({ ...newItem, name: e.target.value })}
placeholder="Name"
/>
/>}
<button onClick={handleCreateItem}>Create</button>
<button onClick={() => setIsCreating(false)}>Cancel</button>
</div>