Initial commit

This commit is contained in:
mohan 2026-01-27 18:27:29 +05:30
commit 3d8437ecf6
1555 changed files with 807640 additions and 0 deletions

20
.eslintrc.cjs Normal file
View File

@ -0,0 +1,20 @@
module.exports = {
root: true,
env: { browser: true, es2020: true },
extends: [
"eslint:recommended",
"plugin:react/recommended",
"plugin:react/jsx-runtime",
"plugin:react-hooks/recommended",
],
ignorePatterns: ["dist", ".eslintrc.cjs"],
parserOptions: { ecmaVersion: "latest", sourceType: "module" },
settings: { react: { version: "18.2" } },
plugins: ["react-refresh"],
rules: {
"react-refresh/only-export-components": [
"warn",
{ allowConstantExport: true },
],
},
};

24
.gitignore vendored Normal file
View File

@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

142
index.html Normal file
View File

@ -0,0 +1,142 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/fav.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
rel="preload"
as="font"
href="https://fonts.googleapis.com/css2?family=Poppins:ital,wght@0,100;0,400;0,500;0,600;0,700;1,200&display=swap"
rel="stylesheet"
/>
<link
href="https://fonts.googleapis.com/css2?family=Inter:wght@100;200;300;400;500;600;700;800;900&family=Manrope:wght@200;300;400;500;600;700;800&family=Montserrat:wght@400;500;600;700&family=Poppins:ital,wght@1,200&display=swap"
/>
<link
href="https://fonts.googleapis.com/css2?family=Arimo:ital,wght@0,400..700;1,400..700&family=Crimson+Pro:ital,wght@0,200..900;1,200..900&family=Dhurjati&family=Diplomata+SC&family=Inconsolata:wght@200..900&family=JetBrains+Mono:ital,wght@0,100..800;1,100..800&family=Lexend+Zetta:wght@200;300;400;500;700&family=Libre+Franklin:ital,wght@0,100..900;1,100..900&family=Podkova:wght@400..800&family=Poppins:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&family=Roboto+Slab:wght@200;300;400;500;600;700&family=VT323&family=Cute+Font&family=Kumar+One&family=Lemon&family=Lily+Script+One&family=M+PLUS+Rounded+1c&family=Maiden+Orange&family=Kode+Mono:wght@400..700&display=swap"
rel="stylesheet"
/>
<link
href="https://fonts.googleapis.com/css2?family=Fredoka:wght@300..700&display=swap"
rel="stylesheet"
/>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Freeman&display=swap"
rel="stylesheet"
/>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Concert+One&display=swap"
rel="stylesheet"
/>
<link
href="https://fonts.googleapis.com/css2?family=Calistoga&display=swap"
rel="stylesheet"
/>
<link
href="https://fonts.googleapis.com/css2?family=Calistoga&display=swap"
rel="stylesheet"
/>
<!-- <link href="https://vjs.zencdn.net/8.3.0/video-js.css" rel="stylesheet" /> -->
<!-- <link href="https://unpkg.com/aos@2.3.1/dist/aos.css" rel="stylesheet"> -->
<title>Pozo Retail Software</title>
<!-- mohan -->
<!-- <script>
// Disable right-click menu and common hotkeys
document.addEventListener("contextmenu", (event) => event.preventDefault());
document.addEventListener("keydown", (event) => {
if (
(event.ctrlKey && event.shiftKey && ["I", "J", "C"].includes(event.key.toUpperCase())) ||
(event.ctrlKey && ["U", "S"].includes(event.key.toUpperCase())) ||
event.key === "F12"
) {
event.preventDefault();
return false;
}
});
</script> -->
<!-- <script src="https://cdn.jsdelivr.net/npm/eruda"></script>
<script src="https://cdn.jsdelivr.net/npm/eruda-network"></script>
<script>
(function () {
// Always enable Eruda
eruda.init();
eruda.add(erudaNetwork);
eruda.show();
console.log("✅ Eruda Debug Console Loaded (Always On)");
// Axios interceptor for API logs
setTimeout(() => {
if (window.axios) {
axios.interceptors.request.use((config) => {
console.log(
"[API Request]",
config.method?.toUpperCase(),
config.url,
config.data
);
return config;
});
axios.interceptors.response.use(
(response) => {
console.log(
"[API Response]",
response.config.url,
response.status,
response.data
);
return response;
},
(error) => {
console.error(
"[API Error]",
error.config?.url,
error.message
);
return Promise.reject(error);
}
);
console.log("✅ Axios interceptors attached");
} else {
console.warn("⚠️ Axios not found on window");
}
}, 2000);
})();
</script> -->
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.jsx"></script>
<script
type="module"
href="@import url('https://fonts.googleapis.com/css2?family=Calistoga&display=swap')"
></script>
<!-- <script src="https://vjs.zencdn.net/8.3.0/video.min.js"></script> -->
<!-- <script src="https://unpkg.com/aos@2.3.1/dist/aos.js"></script> -->
</body>
<!-- <iframe id="ifmcontentstoprint" style="
height: 0px;
width: 0px;
position: absolute;
padding: 0px;
margin: 0px;
/* font-family: 'Poppins', sans-serif; */
"></iframe> -->
</html>

1642
ownLib/my-ui-lib.css Normal file

File diff suppressed because it is too large Load Diff

6042
ownLib/my-ui-lib.js Normal file

File diff suppressed because one or more lines are too long

9441
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

98
package.json Normal file
View File

@ -0,0 +1,98 @@
{
"name": "retail-application",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "node --max-old-space-size=4096 node_modules/vite/bin/vite.js build",
"lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0",
"preview": "vite preview",
"format": "prettier --write ."
},
"dependencies": {
"@ant-design/plots": "^1.2.6",
"@autocomplete/material-ui": "0.0.17",
"@dnd-kit/core": "^6.3.1",
"@dnd-kit/sortable": "^10.0.0",
"@emotion/react": "^11.11.4",
"@emotion/styled": "^11.11.5",
"@material-ui/lab": "^4.0.0-alpha.61",
"@mui/material": "^5.15.18",
"@reduxjs/toolkit": "^1.9.5",
"@tanstack/react-query": "^5.90.11",
"@tanstack/react-query-devtools": "^5.91.1",
"antd": "^5.17.4",
"antd-img-crop": "^4.22.0",
"aos": "^2.3.4",
"axios": "^1.7.2",
"browser-image-compression": "^2.0.2",
"classnames": "^2.5.1",
"cropperjs": "^1.6.2",
"crypto-js": "^4.1.1",
"date-fns": "^4.1.0",
"devtools-detect": "^4.0.2",
"exceljs": "^4.3.0",
"google-maps-react": "^2.0.6",
"highcharts": "^11.4.3",
"highcharts-react-official": "^3.2.1",
"history": "^5.3.0",
"html2canvas": "^1.4.1",
"html2pdf": "^0.0.11",
"html2pdf.js": "^0.10.3",
"html5-qrcode": "^2.3.8",
"jquery": "^3.7.1",
"js-cookie": "^3.0.5",
"jsbarcode": "^3.11.6",
"jspdf": "^2.5.1",
"lucide-react": "^0.536.0",
"material-ui": "^0.20.2",
"moment": "^2.30.1",
"mui-autocomplete": "^2.0.1",
"number-to-words": "^1.2.4",
"pdf-lib": "^1.17.1",
"qrcode": "^1.5.3",
"qrcode.react": "^4.2.0",
"react": "^18.3.1",
"react-beautiful-dnd": "^13.1.1",
"react-color": "^2.19.3",
"react-countup": "^6.5.3",
"react-device-detect": "^2.2.3",
"react-devtools": "^5.2.0",
"react-dom": "^18.3.1",
"react-icons": "^4.12.0",
"react-image-crop": "^11.0.10",
"react-qr-code": "^2.0.13",
"react-redux": "^8.1.2",
"react-router-dom": "^6.23.1",
"react-select": "^5.8.0",
"react-signature-canvas": "^1.0.7",
"react-speech-recognition": "^3.10.0",
"react-timer-hook": "^3.0.7",
"react-transition-group": "^4.4.5",
"recharts": "^3.5.0",
"string-similarity": "^4.0.4",
"tesseract.js": "^6.0.0",
"universal-cookie": "^6.1.3",
"webfontloader": "^1.6.28",
"xlsx": "^0.18.5",
"zustand": "^5.0.8"
},
"devDependencies": {
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"@vitejs/plugin-react": "^4.3.0",
"eslint": "^8.57.0",
"eslint-plugin-react": "^7.34.2",
"eslint-plugin-react-hooks": "^4.6.2",
"eslint-plugin-react-refresh": "^0.4.7",
"prettier": "^3.5.3",
"rollup-plugin-obfuscator": "^1.1.0",
"rollup-plugin-terser": "^7.0.2",
"sass": "^1.77.2",
"terser": "^5.31.3",
"vite": "^4.5.3",
"vite-plugin-obfuscator": "^1.0.5",
"vite-plugin-remove-console": "^2.2.0"
}
}

1
public/vite.svg Normal file
View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

17
public/web.config Normal file
View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="React Routes" stopProcessing="true">
<match url=".*" />
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
</conditions>
<action type="Rewrite" url="/" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>

BIN
retail updated jan 27.zip Normal file

Binary file not shown.

31
src/.env.development Normal file
View File

@ -0,0 +1,31 @@
ENV_BASE_URL='/'
ENV_COMMON_BASE_URL='http://192.168.1.16:3000/'
# ENV_API_URL='http://192.168.1.25:8001'
# ENV_API_URL='http://api.pozo.co.in/Retailapi_UnderTest'
# ENV_API_URL='https://api.pozo.dev/pozo-retail-api'
# ENV_API_URL_COMMON='https://api.pozo.dev/pozo-common-api'
# ENV_API_URL_TOKEN='https://api.pozo.dev/JwtToken'
ENV_API_URL='http://192.168.1.37:8012'
ENV_API_URL_COMMON='http://192.168.1.37:8013'
ENV_API_URL_TOKEN='http://192.168.1.37:8001'
ENV_API_URL_OCR='http://192.168.1.37:8070'
# ENV_API_URL='https://api.pozo.app/pozo-retail-api'
# ENV_API_URL_COMMON='https://api.pozo.app/pozo-common-api'
# ENV_API_URL_TOKEN='https://api.pozo.app/JwtToken'
# ENV_API_URL='https://www.pozo.dev/pozo-retail-api'
# ENV_API_URL_COMMON='https://www.pozo.dev/pozo-common-api'
# ENV_API_URL_TOKEN='https://www.pozo.dev/JwtToken'
ENV_IMAGE_UPLOAD_API_URL="http://192.168.1.38/"
ENV_SECRET_KEY="3a939a2eed2cca4b64cd47f51b23b135b2b9b765273f695d47682ea803c8429d"
ENV_URL_SECRET_KEY="f2ef79b8b2d4fc1cc569726a5a753552257b4ff2872d6a71cf3119bce3f07c1b"
ENV_MAIN_BASE_URL='http://192.168.1.22:3015/'
ENV_SIGNALR_SERVER_URL='https://api.pozo.dev/'
ENV_IFSC_API_URL = "https://ifsc.razorpay.com"
ENV_PAYMENT_DEVICE_URL='https://pozo.dev/PaymentDevice/PaymentDevice/api/upload-transaction'
ENV_PAYMENT_STATUS_GET_URL='https://pozo.dev/PaymentDevice/PaymentDevice/api/get-transaction-status'
ENV_ANDROID_PRINTER= 'https://pozo.dev/downloads/resources/POZO%20Printer.apk'
ENV_ANDROID_KIOSK= 'https://pozo.app/downloads/resources/POZO%20KIOSK.apk'
ENV_ANDROID_HANDHELD= 'https://pozo.dev/downloads/resources/Handheld.apk'
ENV_ANDROID_BILLING= 'https://pozo.dev/downloads/resources/PozoBillingApp.apk'
ENV_EMAIL_API='http://192.168.1.37:8014'

67
src/.env.production Normal file
View File

@ -0,0 +1,67 @@
#221 server
# ENV_BASE_URL='/apps/retail/'
# ENV_COMMON_BASE_URL='http://pozo.co.in'
# ENV_API_URL='http://api.pozo.co.in/Retailapi_UnderTest'
# ENV_API_URL_COMMON='http://api.pozo.co.in/Pozocommonapi_UnderTest'
# # ENV_API_URL='http://api.pozo.co.in/Retailapi/'
# # ENV_API_URL_COMMON='http://api.pozo.co.in/Pozocommonapi'
# ENV_IMAGE_UPLOAD_API_URL="https://api.pozo.app/pozo-common-image-api/"
# ENV_SECRET_KEY="3a939a2eed2cca4b64cd47f51b23b135b2b9b765273f695d47682ea803c8429d"
# ENV_URL_SECRET_KEY="f2ef79b8b2d4fc1cc569726a5a753552257b4ff2872d6a71cf3119bce3f07c1b"
# ENV_MAIN_BASE_URL='http://pozo.co.in/apps/retail/'
# ENV_CUSTOM_PAYMENT_URL='https://pozo.app/CustomPaymentGateway/CustomPaymentGateway'
# ENV_IFSC_API_URL = "https://ifsc.razorpay.com"
# ENV_ANDROID_HANDHELD= 'https://pozo.app/downloads/resources/Handheld.apk'
# live Server (173 server)
ENV_BASE_URL='/apps/retail/'
ENV_COMMON_BASE_URL='https://pozo.app'
ENV_API_URL='https://api.pozo.app/pozo-retail-api'
ENV_API_URL_COMMON='https://api.pozo.app/pozo-common-api'
ENV_API_URL_TOKEN='https://api.pozo.app/JwtToken'
ENV_API_URL_OCR='http://192.168.1.37:8070'
ENV_IMAGE_UPLOAD_API_URL="https://api.pozo.app/pozo-common-image-api/"
ENV_SECRET_KEY="3a939a2eed2cca4b64cd47f51b23b135b2b9b765273f695d47682ea803c8429d"
ENV_URL_SECRET_KEY="f2ef79b8b2d4fc1cc569726a5a753552257b4ff2872d6a71cf3119bce3f07c1b"
ENV_MAIN_BASE_URL='https://pozo.app/apps/retail/'
ENV_CUSTOM_PAYMENT_URL='https://pozo.app/CustomPaymentGateway/CustomPaymentGateway'
ENV_IFSC_API_URL = "https://ifsc.razorpay.com"
ENV_PAYMENT_DEVICE_URL='https://pozo.app/PaymentDevice/PaymentDevice/api/upload-transaction'
ENV_PAYMENT_STATUS_GET_URL='https://pozo.app/PaymentDevice/PaymentDevice/api/get-transaction-status'
ENV_ANDROID_PRINTER= 'https://pozo.app/downloads/resources/POZO%20Printer.apk'
ENV_ANDROID_KIOSK= 'https://pozo.app/downloads/resources/POZO%20KIOSK.apk'
ENV_ANDROID_HANDHELD= 'https://pozo.app/downloads/resources/Handheld.apk'
ENV_ANDROID_BILLING= 'https://pozo.app/downloads/resources/PozoApp.apk'
ENV_EMAIL_API='https://api.pozo.app/pozo-sms-email-template-api'
ENV_SIGNALR_SERVER_URL='https://api.pozo.app/'
#(172 server)
# ENV_BASE_URL='/apps/retail/'
# ENV_COMMON_BASE_URL='https://pozo.dev'
# ENV_API_URL='https://api.pozo.dev/pozo-retail-api'
# ENV_API_URL_COMMON='https://api.pozo.dev/pozo-common-api'
# ENV_API_URL_TOKEN='https://api.pozo.dev/JwtToken'
# ENV_API_URL_OCR='https://api.pozo.dev/pozo-scantext-api'
# ENV_IMAGE_UPLOAD_API_URL="https://api.pozo.dev/pozo-common-image-api"
# ENV_SECRET_KEY="3a939a2eed2cca4b64cd47f51b23b135b2b9b765273f695d47682ea803c8429d"
# ENV_URL_SECRET_KEY="f2ef79b8b2d4fc1cc569726a5a753552257b4ff2872d6a71cf3119bce3f07c1b"
# ENV_MAIN_BASE_URL='https://pozo.dev/apps/retail/'
# ENV_SIGNALR_SERVER_URL='https://api.pozo.dev/'
# ENV_CUSTOM_PAYMENT_URL='https://pozo.app/CustomPaymentGateway/CustomPaymentGateway'
# ENV_IFSC_API_URL = "https://ifsc.razorpay.com"
# ENV_PAYMENT_DEVICE_URL='https://pozo.dev/PaymentDevice/PaymentDevice/api/upload-transaction'
# ENV_PAYMENT_STATUS_GET_URL='https://pozo.dev/PaymentDevice/PaymentDevice/api/get-transaction-status'
# # ENV_PAYMENT_DEVICE_URL='https://www.plutuscloudserviceuat.in:8201/API/CloudBasedIntegration/V1/UploadBilledTransaction'
# # ENV_PAYMENT_STATUS_GET_URL='https://www.plutuscloudserviceuat.in:8201/API/CloudBasedIntegration/V1/GetCloudBasedTxnStatus'
# ENV_ANDROID_PRINTER= 'https://pozo.dev/downloads/resources/POZO%20Printer.apk'
# ENV_ANDROID_KIOSK= 'https://pozo.dev/downloads/resources/POZO%20KIOSK.apk'
# ENV_ANDROID_HANDHELD= 'https://pozo.dev/downloads/resources/Handheld.apk'
# ENV_ANDROID_BILLING= 'https://pozo.dev/downloads/resources/PozoApp.apk'
# ENV_EMAIL_API='https://api.pozo.dev/pozo-sms-email-template-api'

7
src/.prettierrc Normal file
View File

@ -0,0 +1,7 @@
{
"semi": true,
"singleQuote": true,
"printWidth": 80,
"tabWidth": 2,
"trailingComma": "es5"
}

265
src/App.jsx Normal file
View File

@ -0,0 +1,265 @@
// AppRoutes.jsx
import React, { useEffect, useState, useRef, } from 'react';
import { Routes, Route } from 'react-router-dom';
import { useNavigate } from 'react-router-dom';
import { useDispatch, useSelector } from 'react-redux';
import ProtectedRoutes from './ProtectedRoutes';
import SelfBooking from './Pages/SelfBooking/SelfBooking.jsx'
import { isMobile, isIOS } from "react-device-detect";
// const { routesConfig }=lazy(()=>import('./routesConfig'));
import { routesConfig } from './routesConfig';
import {
ChangeAppExpDateData,
changeHeightforExpDate,
getAppSubscriptionDate,
GlobalItemCard,
} from './Features/BookingScreen/BookingData/BookingData.js';
import {
checkSession,
GenerateLogout,
} from './Features/BrachLogin/BranchLogin.js';
import {
clearSession,
getSession,
TokendecryptedValuesFun,
} from './Services/Others.js';
import devtools from 'devtools-detect';
import KisokSelBooking from './Pages/SelfBooking/KisokSelBooking.jsx';
import IndividualBooking from './Pages/SelfBooking/IndividualBooking.jsx';
const commonSubDir = import.meta.env.ENV_COMMON_BASE_URL;
const subDirectory = import.meta.env.ENV_BASE_URL;
import "../ownLib/my-ui-lib.css"
import CustomerMenuPage from './Pages/Reports/MenuQRCode/CustomerMenuPage.jsx';
import WeightScaleApp from './Pages/BookingScreen/WeightscaleApp.jsx';
const AppRoutes = () => {
const navigate = useNavigate();
const dispatch = useDispatch();
const ItemCard = useSelector(GlobalItemCard);
const [remainingDays, setRemainingDays] = useState(null);
const prevRemainingDays = useRef(null);
const [sessionData, setSessionData] = useState(null);
const [devToolsOpen, setDevToolsOpen] = useState(false);
useEffect(() => {
const handlePopState = (e) => {
const SessionId = getSession('SessionId');
if (!SessionId) {
alert(
'Session invalid and Unauthorized action detected. Redirecting to login...'
);
clearSession();
window.location.replace(`${commonSubDir}`);
} else {
window.history.go(1);
}
};
// Add event listener on mount
window.addEventListener('popstate', handlePopState);
// Clean up the event listener on unmount
return () => {
window.removeEventListener('popstate', handlePopState);
};
}, []);
//cmd it start
// useEffect(() => {
// sessionCheckFun()
// }, [navigate, ItemCard]);
//cmd it End
useEffect(() => {
const loadSessionData = () => {
const CompId = getSession('CompId');
const AppId = getSession('AppId');
const BranchId = getSession('BranchId');
const UserType = getSession('UserType');
console.log('loadSessionData:', CompId, AppId, BranchId, UserType);
if (CompId && AppId && BranchId) {
setSessionData({ CompId, AppId, BranchId, UserType });
return true; // Indicate that session data is available
}
return false; // Indicate that session data is not yet available
};
if (!loadSessionData()) {
const interval = setInterval(() => {
if (loadSessionData()) {
clearInterval(interval); // Stop checking once data is available
}
}, 1000);
return () => clearInterval(interval); // Cleanup interval on unmount
}
}, []);
useEffect(() => {
const fetchExpDate = async () => {
if (!sessionData) {
console.log('Session data not available, skipping API call...');
return;
}
try {
const { CompId, AppId, BranchId, UserType } = sessionData;
const data = { CompId, BranchId, AppId };
let res = await dispatch(getAppSubscriptionDate(data)).unwrap();
if (res?.data?.statusCode === 1 && res?.data?.data?.length > 0) {
const expData = res?.data?.data?.[0];
if (prevRemainingDays.current !== expData.RemainingDays) {
prevRemainingDays.current = expData.RemainingDays;
setRemainingDays(expData.RemainingDays);
dispatch(ChangeAppExpDateData(expData));
dispatch(changeHeightforExpDate(expData.RemainingDays));
if (
expData.RemainingDays < 1 &&
expData.RemainingHours < 1 &&
expData.RemainingMinutes < 1 &&
expData.RemainingSeconds < 1
) {
if (
UserType !== 'Super Admin' ||
UserType !== 'Super Admin User'
) {
console.log('Subscription expired, logging out...');
alert(
'Subscription expired, logging out. Redirecting to login...'
);
Logout();
}
}
}
} else {
console.log('No subscription data found, logging out...');
alert(
'No subscription data found, logging out. Redirecting to login...'
);
Logout();
}
} catch (error) {
console.error('Error fetching subscription data:', error);
}
};
if (remainingDays === null) {
fetchExpDate();
}
const interval = setInterval(fetchExpDate, 60 * 60 * 1000);
return () => clearInterval(interval);
}, [sessionData, remainingDays]);
const Logout = async () => {
const UserId = getSession('UserId');
const status = 'N';
try {
const res = await dispatch(GenerateLogout({ UserId, status })).unwrap();
if (res?.data?.statusCode === 1) {
sessionStorage.clear();
window.location.replace(`${commonSubDir}`);
}
} catch (error) {
console.error('Logout failed:', error);
}
};
// mohan
// useEffect(() => {
// if (isMobile || isIOS) {
// console.log("📱 Mobile/iOS device → skipping DevTools detection");
// return;
// }
// const checkDevTools = setInterval(() => {
// if (devtools.isOpen && !devToolsOpen) {
// setDevToolsOpen(true);
// document.body.innerHTML =
// "<h1 style='color: red; text-align: center;'>Close Inspect to continue using the application.</h1>";
// }
// else if (!devtools.isOpen && devToolsOpen) {
// setDevToolsOpen(false);
// setTimeout(() => {
// window.location.reload();
// }, 100);
// clearInterval(checkDevTools);
// }
// if (!devtools.isOpen) {
// let before = performance.now();
// let after = performance.now();
// let executionDelay = after - before;
// if (executionDelay > 100) {
// setDevToolsOpen(true);
// document.body.innerHTML =
// "<h1 style='color: red; text-align: center;'>Close Inspect to continue using the application.</h1>";
// } else {
// setDevToolsOpen(false);
// }
// }
// }, 1000);
// return () => clearInterval(checkDevTools);
// }, [devToolsOpen]);
const sessionCheckFun = async () => {
const UserId = getSession('UserId');
const sessionId = getSession('SessionId');
const IsLogout = getSession('Mode');
let encryptedLoginType = TokendecryptedValuesFun(
sessionStorage.getItem('LoginType')
);
if (encryptedLoginType != 'Kiosk') {
const res = await dispatch(checkSession({ UserId, sessionId })).unwrap();
if (res?.data?.statusCode === 1) {
if (res?.data?.response === 'False') {
if (IsLogout !== 'Logout') {
alert('Session invalid. Redirecting to login...');
}
clearSession();
window.location.replace(commonSubDir);
}
}
}
};
return (
<Routes>
<Route
path={`${subDirectory}selfBooking/:SelfBookingId`}
element={<SelfBooking />}
/>
<Route
path={`${subDirectory}MenuQRCode`}
element={<CustomerMenuPage />}
/>
<Route
path={`${subDirectory}weightscaleapp`}
element={<WeightScaleApp />}
/>
<Route path={`${subDirectory}kioskSelfBooking`} element={<KisokSelBooking />} />
<Route
path= {`${subDirectory}kiosk-individual-self-booking`}
element={<IndividualBooking />}
/>
<Route
path="/*"
element={<ProtectedRoutes routesConfig={routesConfig} />}
/>
</Routes>
);
};
export default AppRoutes;

125
src/AuthContext.jsx Normal file
View File

@ -0,0 +1,125 @@
// AuthContext.jsx
import React, { createContext, useContext, useState, useEffect } from 'react';
import { useDispatch } from 'react-redux';
import { getSession } from './Services/Others';
import {
getEmpAccesData,
getSAdminUserAccesData,
PricingAppPricingName,
} from './Features/BrachLogin/BranchLogin.js';
import { changePricingAppPricingName } from './Features/ThemeChange/ThemeChange.js';
import { FeatureAddon } from './Features/BookingScreen/BookingData/BookingData.js';
export const AuthContext = createContext();
export const useAuth = () => useContext(AuthContext);
export const AuthProvider = ({ children }) => {
const AppId = getSession('AppId');
const CompId = getSession('CompId');
const BranchId = getSession('BranchId');
const UserId = getSession('UserId');
const UserType = getSession('UserType');
const dispatch = useDispatch();
const [Access, setAccess] = useState([]);
const [SadminuserAccess, setSadminuserAccess] = useState([]);
const [FeatureAddonData, setFeatureAddonData] = useState([]);
const [ProORAdvance, setProORAdvance] = useState(false);
const [Advance, setAdvance] = useState(false);
const [freeProductsCount, setFreeProductsCount] = useState(0);
let featureaddDetails = FeatureAddonData?.FeatureDtls || [];
useEffect(() => {
getPricingName();
if (UserType !== 'Super Admin' && UserType !== 'Super Admin User') {
getFeatureAddonData();
}
}, []);
useEffect(() => {
if (UserType === 'Employee') {
getEmpAccess();
}
if (UserType === 'Super Admin User') {
getSadminUserAccess();
}
}, [UserType]);
const getPricingName = async () => {
if (!AppId || !UserId) return;
const data = {
appId: AppId,
userId: UserId,
};
try {
const response = await dispatch(PricingAppPricingName(data)).unwrap();
const responseData = response?.data;
if (responseData?.statusCode !== 1) return setAdvance(false);
const pricingData = responseData?.data;
await dispatch(changePricingAppPricingName(pricingData));
const hasAdvance = pricingData.some(
(item) => item.PricingName === 'Premium'
);
setAdvance(hasAdvance);
const hasProOrAdvance =
hasAdvance || pricingData.some((item) => item.PricingName === 'Customized');
setProORAdvance(hasProOrAdvance);
} catch (error) {
console.error('Error fetching pricing name:', error);
}
};
const getEmpAccess = async () => {
let data = {
UserId: UserId,
AppId: AppId,
CompId: CompId,
BranchId: BranchId,
};
const response = await dispatch(getEmpAccesData(data)).unwrap();
if (response?.data?.statusCode === 1) {
setAccess(response?.data?.data?.[0]?.EmpAccessDetails);
}
};
const getSadminUserAccess = async () => {
let data = {
UserId: UserId,
AppId: AppId,
};
const response = await dispatch(getSAdminUserAccesData(data)).unwrap();
if (response?.data?.statusCode === 1) {
setSadminuserAccess(response?.data?.data?.[0]?.AppMenuAccessDetails);
}
};
const getFeatureAddonData = async () => {
let featureAddon = await dispatch(
FeatureAddon({ AppId: AppId, UserId: UserId })
).unwrap();
if (featureAddon?.data?.statusCode === 1) {
await setFeatureAddonData(
featureAddon?.data?.data?.[0]?.FeatAddonHdr?.[0]
);
} else {
await setFeatureAddonData([]);
}
};
return (
<AuthContext.Provider
value={{
UserType,
Access,
SadminuserAccess,
Advance,
ProORAdvance,
featureaddDetails,
freeProductsCount,
setFreeProductsCount,
}}
>
{children}
</AuthContext.Provider>
);
};

View File

@ -0,0 +1,141 @@
import React, { useState, useEffect } from 'react';
import { Select } from 'antd';
import { FiTrash2 } from 'react-icons/fi';
import { uomDataSelector } from '../../Features/ProductPage/ProductPage';
import { useSelector } from 'react-redux';
import { ApplicationPreferences } from '../../Features/BrachLogin/BranchLogin';
import './AddProduct.scss';
export default function AddProduct({ products, setProducts }) {
const UomData = useSelector(uomDataSelector);
const ApplicationPreferenceData = useSelector(ApplicationPreferences);
const UomTypePreference = ApplicationPreferenceData?.find(
(preference) => preference?.PreferredCatName === 'Product Uom'
)?.PreferenceCatDetails;
console.log(UomData,"UomData",UomTypePreference)
const UomPreference = UomData?.filter((item) =>
UomTypePreference?.some?.(
(e) =>
e?.PreferredSubCatName?.toLowerCase() ==
item?.ConfigName?.toLowerCase() && e?.PreferredStatus == 'Y'
)
);
const defaultUomId = UomPreference?.find((cat) => cat?.ConfigName?.toLowerCase() === 'pcs')?.ConfigId || '';
const defaultUomName = UomPreference?.find((cat) => cat?.ConfigName?.toLowerCase() === 'pcs')?.ConfigName || '';
useEffect(() => {
if (defaultUomId) {
setProducts((prev) => prev.map((p) => ({ ...p, UOM: p.UOM || defaultUomId, size: p.size || '1' , UOMName: p.UOMName || defaultUomName })));
}
}, [defaultUomId]);
const handleInputChange = (id, field, value, displayValue) => {
setProducts(products.map(product => {
if (product.id !== id) return product;
if (field === 'UOM') {
return { ...product, UOM: value, UOMName: displayValue || product.UOMName };
}
return { ...product, [field]: value };
}));
};
const addRow = () => {
const newId = products.length > 0 ? Math.max(...products.map(p => p.id)) + 1 : 1;
setProducts([{ id: newId, name: '', price: '', code: '', size: '1', UOM: defaultUomId || '' , UOMName: defaultUomName || ''}, ...products]);
};
const deleteRow = (id) => {
if (products.length > 1) {
setProducts(products.filter(product => product.id !== id));
}
};
return (
<div className="add-product__container">
<div className="add-product__header">
<button className="add-product__add-btn" onClick={addRow}>+ Add Row</button>
</div>
<div className="add-product__table-wrapper">
<table className="add-product__table">
<thead>
<tr>
<th>Name</th>
<th>Price</th>
<th>Code</th>
<th>Size</th>
<th>UOM</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{products.map((product) => (
<tr key={product.id}>
<td>
<input
type="text"
value={product.name}
onChange={(e) => handleInputChange(product.id, 'name', e.target.value)}
placeholder=" product name"
className="add-product__input-field"
/>
</td>
<td>
<input
type="number"
value={product.price}
onChange={(e) => handleInputChange(product.id, 'price', e.target.value)}
placeholder="$0.00"
className="add-product__input-field"
/>
</td>
<td>
<input
type="text"
value={product.code}
onChange={(e) => handleInputChange(product.id, 'code', e.target.value)}
placeholder="PRD-000"
className="add-product__input-field add-product__input-field--code"
/>
</td>
<td>
<input
type="number"
value={product.size}
onChange={(e) => handleInputChange(product.id, 'size', e.target.value)}
placeholder="Enter size"
className="add-product__input-field"
/>
</td>
<td>
<Select
// size="small"
value={product.UOM}
onChange={(val, option) => handleInputChange(product.id, 'UOM', val, option?.label)}
options={UomPreference?.map((cat) => ({ label: cat.ConfigName, value: cat.ConfigId }))}
// placeholder="Select Category"
style={{ width: '100%' }}
// allowClear
/>
</td>
<td>
<button
className="add-product__delete-btn"
onClick={() => deleteRow(product.id)}
disabled={products.length === 1}
aria-label="Delete row"
title="Delete"
>
<FiTrash2 />
</button>
</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
);
}

View File

@ -0,0 +1,228 @@
.add-product {
&__container {
padding: 6px;
max-width: 1200px;
margin: 0 auto;
}
&__header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 1.5rem;
flex-direction: row-reverse;
}
&__title {
font-size: 1.875rem;
font-weight: bold;
color: #1f2937;
margin: 0;
font-family: "Poppins", sans-serif;
}
&__add-btn {
background-color: #333;
color: white;
padding: 0.625rem 1.25rem;
border: none;
border-radius: 0.375rem;
font-weight: 400;
cursor: pointer;
transition: background-color 0.2s ease;
font-family: "Poppins", sans-serif;
&:hover {
background-color: #1f2937;
}
&:active {
transform: scale(0.98);
}
}
&__table-wrapper {
max-height: 60vh;
overflow: auto;
border-radius: 0.5rem;
scrollbar-width: thin;
&::-webkit-scrollbar {
width: 10px;
height: 10px;
}
&::-webkit-scrollbar-track {
background: transparent;
border-radius: 8px;
}
&::-webkit-scrollbar-thumb {
background: rgba(107, 114, 128, 0.35);
border-radius: 8px;
}
scrollbar-width: thin;
scrollbar-color: rgba(107, 114, 128, 0.35) transparent;
}
&__table {
width: 100%;
background-color: white;
border-collapse: collapse;
.ant-select-selection-item {
padding-top: unset !important;
}
.ant-select-selector {
height: 40px !important;
}
input {
height: 40px !important;
font-weight: 400 !important;
}
thead {
background-color: #f1f5f9 !important;
color: #111827;
position: sticky;
top: 0;
z-index: 10;
tr th {
padding: 8px 8px;
text-align: left;
font-weight: 500;
font-size: 0.75rem;
text-transform: uppercase;
position: sticky;
top: 0;
z-index: 2;
font-family: "Poppins", sans-serif;
}
}
tbody {
color: #374151;
font-family: "Poppins", sans-serif;
tr {
border-bottom: 1px solid #e5e7eb;
transition: background-color 0.2s ease;
&:nth-child(even) {
background-color: #f9fafb;
}
&:hover {
background-color: #f3f4f6;
}
td {
padding: 8px 8px;
}
}
}
}
&__input-field {
width: 100%;
padding: 0.5rem;
border: 1px solid #d1d5db;
border-radius: 0.25rem;
font-size: 0.875rem;
transition: border-color 0.2s ease, box-shadow 0.2s ease;
font-family: "Poppins", sans-serif;
font-weight: 400 !important;
&:focus {
outline: none;
border-color: #6b7280;
}
&::placeholder {
color: #9ca3af;
}
&--code {
font-family: "Poppins", sans-serif;
}
}
&__delete-btn {
background-color: #ffdcdc;
color: #ee3333;
width: 2rem !important;
height: 2rem;
padding: 0.35rem 0.5rem;
border: none;
border-radius: 0.25rem;
font-size: 0.95rem;
font-weight: 500;
cursor: pointer;
transition: background-color 0.2s ease, transform 0.08s ease;
display: inline-flex;
align-items: center;
justify-content: center;
line-height: 1;
font-family: "Poppins", sans-serif;
&:hover:not(:disabled) {
background-color: #ffb3b3;
}
&:disabled {
background-color: #d1d5db;
cursor: not-allowed;
opacity: 0.9;
display: flex;
justify-content: center;
}
&:active:not(:disabled) {
transform: scale(0.98);
}
svg {
width: 1rem;
height: 1rem;
}
}
@media (max-width: 768px) {
&__container {
padding: 6px;
}
&__header {
flex-direction: column;
align-items: flex-start;
gap: 1rem;
}
&__title {
font-size: 1.5rem;
}
&__table {
thead tr th,
tbody tr td {
padding: 0.5rem;
font-size: 0.8rem;
}
}
&__input-field {
padding: 0.375rem;
font-size: 0.8rem;
}
}
}
.add-product__delete-btn {
width: 50px !important;
text-align: center !important;
}

View File

@ -0,0 +1,168 @@
import { Calendar as CalendarLibrary} from"../../../ownLib/my-ui-lib"
const Calendar = CalendarLibrary
export default Calendar;
// import { useState } from 'react';
// import {
// format,
// startOfWeek,
// addDays,
// isSameDay,
// setMonth,
// setYear,
// getWeeksInMonth,
// startOfMonth,
// differenceInCalendarWeeks,
// addWeeks,
// subWeeks
// } from 'date-fns';
// import './Calendar.scss';
// import { HiDotsHorizontal } from "react-icons/hi";
// import { FiChevronLeft, FiChevronRight } from 'react-icons/fi';
// const Calendar = () => {
// // To match the image, set the date to Saturday, May 3, 2025
// const initialDate = new Date('2025-06-29T12:00:00');
// const [currentDate, setCurrentDate] = useState(initialDate);
// const [showYearPicker, setShowYearPicker] = useState(false);
// const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
// const handleMonthClick = (monthIndex) => {
// const newDate = setMonth(currentDate, monthIndex);
// setCurrentDate(newDate);
// };
// const handleDayClick = (day) => {
// setCurrentDate(day);
// };
// const toggleYearPicker = () => {
// setShowYearPicker(!showYearPicker);
// };
// const handleYearChange = (year) => {
// const newDate = setYear(currentDate, year);
// setCurrentDate(newDate);
// setShowYearPicker(false);
// };
// const handlePrevWeek = () => {
// setCurrentDate(subWeeks(currentDate, 1));
// };
// const handleNextWeek = () => {
// setCurrentDate(addWeeks(currentDate, 1));
// };
// const renderDays = () => {
// const weekStart = startOfWeek(currentDate, { weekStartsOn: 0 }); // Sunday
// const days = [];
// for (let i = 0; i < 5; i++) {
// days.push(addDays(weekStart, i));
// }
// // Hardcoded event dots to match UI
// const eventDays = {
// '29': ['yellow', 'orange'],
// '30': ['yellow'],
// };
// return days.map((day) => (
// <div
// key={day}
// className={`calendar-day-item ${isSameDay(day, currentDate) ? 'active' : ''}`}
// onClick={() => handleDayClick(day)}
// >
// <div className="event-dots-container">
// {(eventDays[format(day, 'd')] || []).map((color, index) => (
// <div key={index} className={`event-dot ${color}`}></div>
// ))}
// </div>
// <div className={`day-number ${isSameDay(day, currentDate) ? 'active' : ''}`} >
// {format(day, 'd')}</div>
// <div
// // className="day-name"
// className={`day-name ${isSameDay(day, currentDate) ? 'active' : ''}`}
// >{format(day, 'EEE')}</div>
// </div>
// ));
// };
// const renderPagination = () => {
// const monthStart = startOfMonth(currentDate);
// const totalWeeks = getWeeksInMonth(currentDate, { weekStartsOn: 0 });
// const currentWeek = differenceInCalendarWeeks(currentDate, monthStart, { weekStartsOn: 0 });
// return Array.from({ length: totalWeeks }, (_, i) => (
// <span key={i} className={`pagination-dot ${i === currentWeek ? 'active-dot' : ''}`}></span>
// ));
// };
// const renderYearPicker = () => {
// const currentYear = currentDate.getFullYear();
// const years = Array.from({ length: 10 }, (_, i) => currentYear - 5 + i);
// return (
// <div className="year-picker">
// {years.map(year => (
// <div
// key={year}
// className={`year-item ${year === currentYear ? 'active' : ''}`}
// onClick={() => handleYearChange(year)}
// >
// {year}
// </div>
// ))}
// </div>
// );
// };
// return (
// <div className="calendar-widget-wrapper">
// <div className="calendar-header">
// <div className="calendar-title-main">Calendar for Bills & Events</div>
// <div className="calendar-event-notes">
// Pending bills due tomorrow<br />
// Scheduled delivery/purchase<br />
// Staff birthdays/notes
// </div>
// </div>
// <div className="calendar-body-content">
// {showYearPicker ? (
// renderYearPicker()
// ) : (
// <>
// <div className="calendar-controls">
// <div className="calendar-year-display">{format(currentDate, 'yyyy')}</div>
// <button className="calendar-more-btn" onClick={toggleYearPicker}><HiDotsHorizontal /></button>
// </div>
// <div className="calendar-months-nav">
// {months.slice(0, 6).map((month, index) => (
// <button
// key={month}
// className={`month-nav-btn ${currentDate.getMonth() === index ? 'active' : ''}`}
// onClick={() => handleMonthClick(index)}
// >
// {month}
// </button>
// ))}
// </div>
// <div className="calendar-week-view">
// <button className="week-nav-btn prev" onClick={handlePrevWeek}>
// <FiChevronLeft />
// </button>
// <div className="calendar-days-grid">{renderDays()}</div>
// <button className="week-nav-btn next" onClick={handleNextWeek}>
// <FiChevronRight />
// </button>
// </div>
// {/* <div className="calendar-pagination-dots">
// {renderPagination()}
// </div> */}
// </>
// )}
// </div>
// </div>
// );
// };
// export default Calendar;

View File

@ -0,0 +1,451 @@
.calendar-widget-wrapper {
border-radius: 12px;
padding: 18px;
width: 100%;
height: 100%;
font-family: 'Poppins', sans-serif;
display: flex;
flex-direction: column;
flex: 1.2;
/* Makes it slightly wider than other widgets */
}
.calendar-header {
display: flex;
justify-content: space-between;
margin-bottom: 12px;
}
.calendar-title-main {
font-weight: 500;
font-size: 14px;
color: #222;
}
.calendar-event-notes {
font-size: 12px;
color: #888;
text-align: right;
line-height: 1.4;
}
.calendar-body-content {
background: #ffffff;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.05);
border-radius: 10px;
padding: 16px;
flex-grow: 1;
position: relative;
height: 37vh;
overflow: auto;
}
.calendar-controls {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 12px;
}
.calendar-year-display {
font-size: 24px;
font-weight: 600;
color: #222;
}
.calendar-more-btn {
background: none;
border: none;
cursor: pointer;
font-size: 24px;
color: #888;
}
.calendar-months-nav {
display: flex;
justify-content: space-between;
margin-bottom: 16px;
padding-bottom: 8px;
border-bottom: 1px solid #e6eaf0;
}
.month-nav-btn {
background: none;
border: none;
cursor: pointer;
font-size: 15px;
color: #888;
font-weight: 500;
padding: 4px 8px;
border-radius: 6px;
&.active {
background: #e3f2fd;
color: #1976d2;
font-weight: 600;
}
}
.calendar-days-grid {
display: flex;
justify-content: space-between;
gap: 8px;
width: 95%;
}
.calendar-day-item {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 8px 4px;
border-radius: 10px;
background: #fff;
cursor: pointer;
position: relative;
min-height: 70px;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.05);
transition: all 0.2s ease-in-out;
border: 1px solid #EEEEEE;;
&.active {
background: #1976d2;
color: #fff;
font-weight: 600;
}
}
.event-dots-container {
position: absolute;
top: 6px;
display: flex;
gap: 3px;
}
.event-dot {
width: 5px;
height: 5px;
border-radius: 50%;
&.yellow {
background: #ffca28;
}
&.orange {
background: #ff9800;
}
}
.day-number {
font-size: 20px;
font-weight: 600;
color: #333;
&.active{
color: #fff;
}
}
.day-name {
font-size: 12px;
color: #888;
&.active{
color: #fff;
}
}
.calendar-pagination-dots {
display: flex;
justify-content: center;
align-items: center;
gap: 6px;
margin-top: 16px;
.pagination-dot {
width: 6px;
height: 6px;
border-radius: 50%;
background: #d0d0d0;
transition: all 0.3s ease;
&.active-dot {
background: #1976d2;
width: 18px;
border-radius: 4px;
}
}
}
.modal-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
.modal {
background: white;
border-radius: 12px;
padding: 2rem;
width: 90%;
max-width: 400px;
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.2);
h3 {
margin: 0 0 1.5rem 0;
color: #2d3748;
}
.event-input {
width: 100%;
padding: 0.75rem;
border: 2px solid #e2e8f0;
border-radius: 6px;
font-size: 1rem;
margin-bottom: 1rem;
transition: border-color 0.2s ease;
&:focus {
outline: none;
border-color: #667eea;
}
}
.event-type-select {
width: 100%;
padding: 0.75rem;
border: 2px solid #e2e8f0;
border-radius: 6px;
font-size: 1rem;
margin-bottom: 1.5rem;
background: white;
cursor: pointer;
&:focus {
outline: none;
border-color: #667eea;
}
}
.modal-actions {
display: flex;
gap: 1rem;
justify-content: flex-end;
.cancel-btn {
padding: 0.75rem 1.5rem;
border: 2px solid #e2e8f0;
background: white;
color: #4a5568;
border-radius: 6px;
cursor: pointer;
font-weight: 500;
transition: all 0.2s ease;
&:hover {
border-color: #cbd5e0;
background: #f7fafc;
}
}
.save-btn {
padding: 0.75rem 1.5rem;
background: #667eea;
color: white;
border: none;
border-radius: 6px;
cursor: pointer;
font-weight: 500;
transition: background-color 0.2s ease;
&:hover {
background: #5a67d8;
}
}
}
}
}
.year-picker {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100%;
overflow-y: auto;
gap: 8px;
}
.year-item {
font-size: 18px;
font-weight: 500;
color: #888;
cursor: pointer;
padding: 4px 16px;
border-radius: 6px;
transition: all 0.2s ease;
&:hover {
background: #e3f2fd;
color: #1976d2;
}
&.active {
background: #1976d2;
color: #fff;
font-weight: 600;
}
}
.calendar-week-view {
display: flex;
align-items: center;
gap: 8px;
margin-top: 16px;
justify-content: space-between;
}
.week-nav-btn {
background: #f0f2f5;
border: none;
border-radius: 50%;
width: 28px;
height: 28px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
color: #555;
font-size: 20px;
transition: all 0.2s ease;
&:hover {
background: #e4e6e9;
transform: scale(1.05);
}
}
// Responsive design
@media (max-width: 768px) {
.calendar-container {
margin: 1rem;
padding: 1rem;
}
.calendar-header {
.header-top {
flex-direction: column;
gap: 1rem;
align-items: stretch;
.header-controls {
justify-content: space-between;
}
}
.calendar-title {
font-size: 1.125rem;
}
}
.calendar-body {
.year-header {
.year {
font-size: 2rem;
}
}
.month-navigation {
.month-tab {
padding: 0.625rem 0.75rem;
font-size: 0.8125rem;
}
}
.week-view {
gap: 0.375rem;
.day-card {
padding: 0.75rem 0.5rem;
min-height: 70px;
.date-number {
font-size: 1.25rem;
}
.day-name {
font-size: 0.6875rem;
}
}
}
.month-view {
.month-grid {
gap: 0.25rem;
.month-day {
min-height: 60px;
padding: 0.25rem;
}
}
}
.navigation-controls {
.current-period {
font-size: 1rem;
}
}
}
}
@media (max-width: 480px) {
.calendar-header {
.calendar-title {
font-size: 1rem;
}
.calendar-legend {
.legend-item {
font-size: 0.8125rem;
}
}
}
.calendar-body {
.year-header {
.year {
font-size: 1.75rem;
}
}
.week-view {
.day-card {
padding: 0.5rem 0.25rem;
min-height: 60px;
.date-number {
font-size: 1.125rem;
}
.day-name {
font-size: 0.625rem;
}
}
}
.month-view {
.month-grid {
.month-day {
min-height: 50px;
}
}
}
}
}

View File

@ -0,0 +1,59 @@
import React, { useState, useRef, useEffect } from "react";
import { FiCalendar } from "react-icons/fi";
import { MdKeyboardArrowDown } from "react-icons/md";
const RANGE_OPTIONS = [
{ label: 'Today', value: 'today' },
{ label: 'This Week', value: 'week' },
{ label: 'This Month', value: 'month' },
{ label: 'This Year', value: 'year' },
];
const CalendarDropdown = ({ value, onChange }) => {
const [open, setOpen] = useState(false);
const ref = useRef();
useEffect(() => {
function handleClickOutside(event) {
if (ref.current && !ref.current.contains(event.target)) {
setOpen(false);
}
}
document.addEventListener('mousedown', handleClickOutside);
return () => document.removeEventListener('mousedown', handleClickOutside);
}, []);
const selected = RANGE_OPTIONS.find(opt => opt.value === value) || RANGE_OPTIONS[0];
return (
<div ref={ref} style={{ position: 'relative' }}>
<button
className="calendar-btn"
onClick={() => setOpen(o => !o)}
type="button"
>
<FiCalendar style={{ marginRight: 4 }} />
{selected.label}
<MdKeyboardArrowDown style={{ marginLeft: 2 }} />
</button>
{open && (
<div className="calendar-dropdown">
{RANGE_OPTIONS.map(option => (
<div
key={option.value}
className={`calendar-dropdown-item${selected.value === option.value ? ' selectedd' : ''}`}
onClick={() => {
onChange(option.value);
setOpen(false);
}}
>
{option.label}
</div>
))}
</div>
)}
</div>
);
};
export default CalendarDropdown;

68
src/Components/Chart/Chart.js vendored Normal file
View File

@ -0,0 +1,68 @@
import React from 'react';
import { Column } from '@ant-design/plots';
const DemoColumn = () => {
const data = [
{
type: '家具家电',
sales: 38,
},
{
type: '粮油副食',
sales: 52,
},
{
type: '生鲜水果',
sales: 61,
},
{
type: '美容洗护',
sales: 145,
},
{
type: '母婴用品',
sales: 48,
},
{
type: '进口食品',
sales: 38,
},
{
type: '食品饮料',
sales: 38,
},
{
type: '家庭清洁',
sales: 38,
},
];
const config = {
data,
xField: 'type',
yField: 'sales',
label: {
position: 'middle',
style: {
fill: '#FFFFFF',
opacity: 0.6,
},
},
xAxis: {
label: {
autoHide: true,
autoRotate: false,
},
},
meta: {
type: {
alias: '类别',
},
sales: {
alias: '销售额',
},
},
};
return React.createElement(Column, config);
};
export default DemoColumn;

View File

@ -0,0 +1,20 @@
import React from 'react';
import { Liquid } from '@ant-design/plots';
const DemoLiquid = () => {
const config = {
percent: 0.25,
shape: 'rect',
outline: {
border: 2,
distance: 4,
},
wave: {
length: 128,
},
};
return React.createElement(Liquid, config);
};
export default DemoLiquid;

View File

@ -0,0 +1,17 @@
import { Drawer } from 'antd';
export const Drawers = ({ open, placement, title, children, onClose }) => {
return (
<>
<Drawer
title={title}
placement={placement}
onClose={onClose}
open={open}
key={placement}
>
{children}
</Drawer>
</>
);
};

View File

@ -0,0 +1,41 @@
// import { Button } from 'antd';
// import './main.scss';
// import { forwardRef } from 'react'; //Add for shifayath
import { Buttons as ButtonLibrary } from '../../../ownLib/my-ui-lib.js';
const Buttons = ButtonLibrary
// forwardRef(
// ({ buttonText, handleSubmit, icon, disabled, htmlType, prefix }, ref) => (
// <Button
// ref={ref}
// type="primary"
// className="primary_Button"
// onClick={handleSubmit}
// htmlType={htmlType ? 'submit' : ''}
// disabled={disabled ? disabled : false}
// >
// {prefix}
// {buttonText}
// {icon}
// </Button>
// )
// );
export default Buttons;
// const Buttons = forwardRef(
// ({ buttonText, handleSubmit, icon, disabled, htmlType, prefix }, ref) => (
// <Button
// ref={ref}
// type="primary"
// className="primary_Button"
// onClick={handleSubmit}
// htmlType={htmlType ? 'submit' : ''}
// disabled={disabled ? disabled : false}
// >
// {prefix}
// {buttonText}
// {icon}
// </Button>
// )
// );
// export default Buttons;

View File

@ -0,0 +1,56 @@
// import { Checkbox, Divider } from 'antd';
// import { useState } from 'react';
import { CheckBoxGroup as CheckboxGroupLibrary } from '../../../ownLib/my-ui-lib.js';
export const CheckBoxGroup = CheckboxGroupLibrary
// export const CheckBoxGroup = ({
// fieldState,
// fieldApi,
// faClass,
// style,
// ListOfCheckBox,
// defaultCheckedList,
// ...props
// }) => {
// const plainOptions = ListOfCheckBox;
// const {
// field,
// onBlur,
// initialValue,
// forwardedRef,
// className,
// content,
// ...rest
// } = props.props;
// const [checkedList, setCheckedList] = useState(defaultCheckedList);
// const [indeterminate, setIndeterminate] = useState(true);
// const [checkAll, setCheckAll] = useState(false);
// const onChange = (list) => {
// setCheckedList(list);
// setIndeterminate(!!list?.length && list?.length < plainOptions?.length);
// setCheckAll(list?.length === plainOptions?.length);
// };
// const onCheckAllChange = (e) => {
// setCheckedList(e.target.checked ? plainOptions : []);
// setIndeterminate(false);
// setCheckAll(e.target.checked);
// };
// return (
// <>
// <Checkbox
// indeterminate={indeterminate}
// onChange={onCheckAllChange}
// checked={checkAll}
// >
// Check all
// </Checkbox>
// <Divider />
// <CheckboxGroup
// options={plainOptions}
// value={checkedList}
// onChange={onChange}
// />
// </>
// );
// };

View File

@ -0,0 +1,30 @@
import React from 'react';
const ColorPicker = ({ value, onChange, style, placeholder = "Select a color" }) => {
const handleColorChange = (e) => {
onChange(e.target.value);
};
return (
<div style={{ display: 'flex', alignItems: 'center', gap: '8px', ...style }}>
<input
type="color"
value={value || '#000000'}
onChange={handleColorChange}
style={{
width: '40px',
height: '40px',
border: 'none',
borderRadius: '8px',
cursor: 'pointer',
boxShadow: '0 2px 4px rgba(0,0,0,0.1)'
}}
/>
<span style={{ fontSize: '14px', color: '#666' }}>
{value || '#000000'}
</span>
</div>
);
};
export default ColorPicker;

View File

@ -0,0 +1,522 @@
import React, { useState, useEffect, useCallback } from 'react';
import { Upload, Modal } from 'antd';
import { uploadImage } from '../../Features/upload/upload';
import { useDispatch } from 'react-redux';
import ImageCropper from '../../Components/Forms/Cropper2.jsx';
import ShapeCropper from './ShapeCropper.jsx';
import { PiCropBold } from 'react-icons/pi';
import { FiPenTool } from 'react-icons/fi';
import { DefaultModal } from '../../Components/Modal/DefaultModal.jsx';
import '../../Styles/Product/Product.scss';
import { Messages } from '../Notifications/Messages.jsx';
const allowedTypes = [
'image/jpeg',
'image/png',
'image/webp',
'image/svg+xml',
'image/gif',
'image/avif',
];
const CropUpload = ({
updateImageUrl,
ImageLink,
onlineImage,
isProductList = {},
handleClose = () => {}
}) => {
const dispatch = useDispatch();
const [messageType, setMessageType] = useState(null);
const [messageData, setMessageData] = useState(null);
const [fileList, setFileList] = useState([]);
const [previewVisible, setPreviewVisible] = useState(false);
const [previewImage, setPreviewImage] = useState('');
const [editImageOpen, setEditImageOpen] = useState(false);
const [croppedImage, setCroppedImage] = useState(null);
const [shapedImage, setShapedImage] = useState(false);
const [cropImage, setCropImage] = useState(false);
const [shapedData, setShapedData] = useState(null);
const [resizedImageUrl, setResizedImageUrl] = useState('');
useEffect(() => {
if (ImageLink != '' && ImageLink != null) {
updateImageUrl(ImageLink);
setFileList([
{
uid: `${Date.now()}-${Math.random()}`, // Ensures uniqueness
name: `image${Date.now()}-${Math.random()}.png`,
status: 'done',
url: ImageLink,
},
]);
} else {
updateImageUrl();
// setFileList([]);
// handleRemove()
}
}, [ImageLink]);
useEffect(() => {
if (ImageLink != '' && ImageLink != null) {
if (Object.keys(isProductList)?.length > 0) {
const { isProductListPutapi } = isProductList;
if (isProductListPutapi) {
setFileList([
{
uid: `${Date.now()}-${Math.random()}`, // Ensures uniqueness
name: `image${Date.now()}-${Math.random()}.png`,
status: 'done',
url: ImageLink,
},
]);
} else {
setFileList([]);
}
} else {
// setFileList([]);
}
} else {
// setFileList([]);
}
}, []);
useEffect(() => {
if (onlineImage !== '' && onlineImage != null && onlineImage != undefined) {
setEditImageOpen(true);
handleResizeImage(onlineImage);
} else {
setShapedImage(false);
setCropImage(false);
}
}, [onlineImage]);
useEffect(() => {
if (fileList.length > 0) {
const imageUrl = fileList?.[0]?.url;
if (imageUrl !== '' && imageUrl !== null && imageUrl !== undefined) {
handleResizeImage(imageUrl);
} else {
setShapedImage(false);
setCropImage(false);
}
}
}, [fileList]);
const handleResizeImage = async (imageUrl) => {
try {
const resizedImageUrl = await resizeImage(imageUrl, 300, 150);
setResizedImageUrl(resizedImageUrl);
} catch (error) {
console.error('Error resizing image:', error);
}
};
const SetDefault = async () => {
setEditImageOpen(false);
setCroppedImage(null);
setShapedData(null);
setShapedImage(false);
setCropImage(false);
updateImageUrl(
onlineImage !== '' && onlineImage != null
? onlineImage
: fileList?.[0]?.['url'] != '' && fileList?.[0]?.['url'] != null
? fileList?.[0]?.['url']
: ''
);
if (Object.keys(isProductList)?.length > 0) {
const { isProductListPutapi, record, imagePutFunction } = isProductList;
if (isProductListPutapi) {
imagePutFunction(
onlineImage !== '' && onlineImage != null
? onlineImage
: fileList?.[0]?.['url'] != '' && fileList?.[0]?.['url'] != null
? fileList?.[0]?.['url']
: '',
record
);
handleClose();
setMessageData("Image updated successfully");
setMessageType("success");
}
}
};
const handleEditImageCancle = () => {
setCroppedImage(null);
setShapedData(null);
setEditImageOpen(false);
updateImageUrl('');
setFileList([]);
setShapedImage(false);
setCropImage(false);
};
const handleSubmit = async () => {
const base64 = croppedImage;
const byteCharacters = atob(base64?.split(',')[1]);
const byteNumbers = new Array(byteCharacters.length);
for (let i = 0; i < byteCharacters.length; i++) {
byteNumbers[i] = byteCharacters.charCodeAt(i);
}
const byteArray = new Uint8Array(byteNumbers);
const blob = new Blob([byteArray], { type: 'image/png' });
const file = new File([blob], 'cropped_image.png', { type: 'image/png' });
try {
await handleUpload({
file,
onSuccess: () => console.log('Upload successful'),
onError: () => console.error('Upload failed'),
});
setEditImageOpen(false);
await setCroppedImage(null);
setShapedImage(false);
setCropImage(false);
handleClose();
setMessageData("Image updated successfully");
setMessageType("success");
} catch (error) {
console.error('Error in handleUpload:', error);
}
};
const handleShapeSubmit = async () => {
const base64 = shapedData[0];
const byteCharacters = atob(base64?.split(',')[1]);
const byteNumbers = new Array(byteCharacters.length);
for (let i = 0; i < byteCharacters.length; i++) {
byteNumbers[i] = byteCharacters.charCodeAt(i);
}
const byteArray = new Uint8Array(byteNumbers);
const blob = new Blob([byteArray], { type: 'image/png' });
const file = new File([blob], 'cropped_image.png', { type: 'image/png' });
try {
await handleUpload({
file,
onSuccess: () => console.log('Upload successful'),
onError: () => console.error('Upload failed'),
});
setEditImageOpen(false);
await setShapedData(null);
setShapedImage(false);
setCropImage(false);
handleClose();
setMessageData("Image updated successfully");
setMessageType("success");
} catch (error) {
console.error('Error in handleUpload:', error);
}
};
const handleCancel = () => setPreviewVisible(false);
const onChange = async ({ fileList: newFileList }) => {
setFileList(newFileList);
if (Object.keys(isProductList)?.length > 0) {
const { isProductListPutapi } = isProductList;
if (isProductListPutapi && newFileList?.[0]?.originFileObj) {
const file = newFileList[0].originFileObj;
try {
const res = await dispatch(uploadImage(file)).unwrap();
if (res?.data?.status) {
updateImageUrl(res?.data?.image);
if (res?.data?.image) {
setFileList([
{
uid: `${Date.now()}-${Math.random()}`, // Ensures uniqueness
name: `image${Date.now()}-${Math.random()}.png`,
status: 'done',
url: res?.data?.image,
},
]);
}
}
} catch (error) {
console.error('Image upload failed:', error);
}
}
}
if (newFileList?.length > 0) {
setEditImageOpen(true);
}
};
const onPreview = async (file) => {
let src = file.url;
if (!src) {
src = await new Promise((resolve) => {
const reader = new FileReader();
reader.readAsDataURL(file.originFileObj);
reader.onload = () => resolve(reader.result);
});
}
setPreviewImage(src);
setPreviewVisible(true);
};
const handleCrop = (croppedData) => {
setCroppedImage(croppedData);
};
const handleShape = (shapedData) => {
setShapedData(shapedData);
};
const handleUpload = async ({ file, onSuccess, onError }) => {
try {
if (!file) {
console.error('File object is null or undefined.');
onError();
return;
}
const data = await dispatch(uploadImage(file)).unwrap();
if (data?.data?.status) {
if (Object.keys(isProductList)?.length > 0) {
const { isProductListPutapi, record, imagePutFunction } =
isProductList;
if (isProductListPutapi) {
imagePutFunction(data?.data?.image, record);
setFileList([{ url: data?.data?.image }]);
onSuccess(); // Trigger onSuccess to indicate a successful upload
setCroppedImage(null);
setShapedData(null);
} else {
updateImageUrl(data?.data?.image);
setFileList([{ url: data?.data?.image }]);
onSuccess(); // Trigger onSuccess to indicate a successful upload
setCroppedImage(null);
setShapedData(null);
}
} else {
updateImageUrl(data?.data?.image);
setFileList([{ url: data?.data?.image }]);
onSuccess(); // Trigger onSuccess to indicate a successful upload
setCroppedImage(null);
setShapedData(null);
}
} else {
console.error('API request was not successful:', data?.data?.error);
onError(); // Trigger onError to indicate a failed upload
}
} catch (error) {
console.error('Error calling API:', error);
onError(); // Trigger onError in case of an error
}
};
const handleRemove = () => {
if (Object.keys(isProductList)?.length > 0) {
const { isProductListPutapi, record, imagePutFunction } = isProductList;
if (isProductListPutapi) {
imagePutFunction('', record);
}
}
updateImageUrl('');
setEditImageOpen(false);
setShapedImage(false);
setCropImage(false);
};
const handleShapeCrop = () => {
setShapedImage(true);
setCropImage(false);
setCroppedImage(null);
};
const handleCropTool = () => {
setCropImage(true);
setShapedImage(false);
setShapedData(null);
};
function resizeImage(imageUrl, width, height) {
if (!imageUrl) {
// Handle the case where imageUrl is null or undefined
console.error('Image URL is null or undefined.');
return Promise.reject('Image URL is null or undefined.');
}
return new Promise((resolve, reject) => {
const img = new Image();
img.crossOrigin = 'anonymous'; // Set crossOrigin to handle cross-origin images
img.onload = function () {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.width = width;
canvas.height = height;
ctx.drawImage(img, 0, 0, width, height);
const resizedImageUrl = canvas.toDataURL();
resolve(resizedImageUrl);
};
img.onerror = function (error) {
reject(error);
};
img.src = imageUrl;
});
}
const beforeUpload = (file) => {
const isAllowed = allowedTypes.includes(file.type);
if (!isAllowed) {
Modal.error({
title: 'Invalid File Type',
content:
'Only JPG, JPEG, PNG, WEBP, SVG, GIF, and AVIF files are allowed.',
});
}
return isAllowed || Upload.LIST_IGNORE; // prevents adding to fileList if invalid
};
const onComplete = useCallback(() => {
setMessageData(null);
setMessageType(null);
}, []);
return (
<>
<Messages
messageType={messageType}
messageData={messageData}
onComplete={onComplete}
/>
<div
className={
Object.keys(isProductList)?.length > 0
? fileList.length > 0
? 'cropUploadFieldSmall'
: 'cropUploadFieldSmallNoData'
: ''
}
>
<Upload
action="https://run.mocky.io/v3/435e224c-44fb-4773-9faf-380c5e6a2188"
listType="picture-card"
fileList={fileList}
customRequest={handleUpload} // Use customRequest to handle the upload process manually
onChange={onChange}
onPreview={onPreview}
onRemove={handleRemove}
beforeUpload={beforeUpload}
>
{fileList.length < 1 && '+ Upload'}
</Upload>
</div>
<Modal visible={previewVisible} onCancel={handleCancel} footer={null}>
<img alt="Preview" style={{ width: '100%' }} src={previewImage} />
</Modal>
<DefaultModal
title="Edit Image"
width={800}
open={editImageOpen}
footer={
(cropImage && croppedImage === null) ||
(shapedImage && shapedData === null)
? false
: true
}
buttonText="SUBMIT"
children={
<>
<div className="shape-crop">
{!croppedImage && !cropImage && !shapedImage && (
<div>
<img
src={
onlineImage !== '' && onlineImage != null
? onlineImage
: fileList?.[0]?.['url'] != '' &&
fileList?.[0]?.['url'] != null
? fileList?.[0]?.['url']
: ''
}
style={{ width: '200px', height: '100px' }}
alt="Edit Image"
/>
</div>
)}
<div className="shape-crop-div">
<div
className="crop-button"
style={{ backgroundColor: cropImage && '#52c41a' }}
onClick={() => handleCropTool()}
>
<div>
<PiCropBold className="crop-icon" />
</div>
<div>Crop Tool</div>
</div>
<div
className="crop-button"
style={{ backgroundColor: shapedImage && '#52c41a' }}
onClick={() => handleShapeCrop()}
>
<div>
<FiPenTool className="crop-icon" />
</div>
<div>Pen Tool</div>
</div>
</div>
<div>
{cropImage && (
<ImageCropper
imageUrl={
onlineImage !== '' && onlineImage != null
? onlineImage
: fileList?.[0]?.['url'] != '' &&
fileList?.[0]?.['url'] != null
? fileList?.[0]?.['url']
: ''
}
onCrop={handleCrop}
/>
)}
{croppedImage && cropImage && (
<div
style={{
display: 'flex',
alignItems: 'center',
flexDirection: 'column',
gap: '2rem',
}}
>
<h4 style={{ marginLeft: '-33rem' }}>
Cropped Image Preview
</h4>
<img
src={croppedImage}
alt="Cropped Image"
style={{ width: '200px', height: '100px' }}
/>
</div>
)}
{shapedImage && (
<ShapeCropper
imageUrl={
resizedImageUrl !== '' && resizedImageUrl !== null
? resizedImageUrl
: ''
}
onShape={handleShape}
/>
)}
</div>
</div>
</>
}
handleSubmit={
croppedImage == null && shapedData == null
? SetDefault
: croppedImage != null
? handleSubmit
: handleShapeSubmit
}
handleCancel={handleEditImageCancle}
/>
</>
);
};
export default CropUpload;

View File

@ -0,0 +1,78 @@
import React, { useRef, useEffect, useState } from 'react';
import Cropper from 'cropperjs';
import 'cropperjs/dist/cropper.css';
import { Button, Slider } from 'antd';
const ImageCropper = ({ imageUrl, onCrop }) => {
const imageRef = useRef(null);
const [cropper, setCropper] = useState(null);
const [rotation, setRotation] = useState(0);
useEffect(() => {
if (imageRef.current && imageUrl) {
if (cropper) {
cropper.replace(imageUrl);
} else {
const newCropper = new Cropper(imageRef.current, {});
setCropper(newCropper);
}
}
return () => {
if (cropper) {
cropper.destroy();
}
};
}, [imageUrl]); // Watch for changes in imageUrl
useEffect(() => {
if (cropper) {
cropper.rotateTo(rotation);
}
}, [rotation]); // Watch for changes in rotation
const handleCrop = () => {
if (cropper) {
const croppedData = cropper.getCroppedCanvas().toDataURL();
onCrop(croppedData);
}
};
const handleRotationChange = (value) => {
setRotation(value);
};
return (
<div
style={{
display: 'flex',
alignItems: 'center',
flexDirection: 'column',
gap: '2rem',
}}
>
<img
ref={imageRef}
src={imageUrl}
alt="Crop Preview"
style={{ width: '300px', height: '150px' }}
/>
<div style={{ display: 'flex', alignItems: 'center', gap: '1rem' }}>
<Button danger onClick={handleCrop}>
Crop Image
</Button>
<span>Rotation: {rotation}°</span>
<Slider
min={0}
max={360}
step={1}
value={rotation}
onChange={handleRotationChange}
style={{ width: '200px' }}
/>
</div>
</div>
);
};
export default ImageCropper;

View File

@ -0,0 +1,45 @@
import {DatePic as DatePicLibrary} from"../../../ownLib/my-ui-lib"
export const DatePic = DatePicLibrary
// import { DatePicker, Space } from 'antd';
// export const DatePic = ({ fieldState, ...props }) => {
// const { value } = fieldState;
// const {
// required,
// field,
// onChange,
// onBlur,
// canSelectPast,
// initialValue,
// forwardedRef,
// min,
// className,
// content,
// faClass,
// icon,
// ...rest
// } = props;
// const disabledDate = (current) => {
// var date = new Date();
// date.setDate(date.getDate() + 1);
// return current.valueOf() <= date.setDate(date.getDate() - 2);
// };
// return (
// <Space direction="vertical">
// <DatePicker
// {...rest}
// id={field}
// type="date"
// ref={forwardedRef}
// required={required}
// value={value}
// disabledDate={canSelectPast ? '' : disabledDate}
// format="DD-MM-YYYY"
// onChange={onChange}
// inputReadOnly={true}
// />
// </Space>
// );
// };

View File

@ -0,0 +1,48 @@
import {DatePicEmpMaster} from"../../../ownLib/my-ui-lib"
export const DatePic = DatePicEmpMaster
// import { DatePicker, Space } from 'antd';
// import dayjs from 'dayjs';
// import customParseFormat from 'dayjs/plugin/customParseFormat';
// import FloatLabel from './FloatLabel/index.jsx';
// dayjs.extend(customParseFormat);
// export const DatePic = ({
// onChange,
// label,
// isOnChange,
// canSelectPast,
// valueData,
// }) => {
// const disabledDate = (current) => {
// const today = dayjs().startOf('day');
// if (canSelectPast === undefined) {
// return false;
// } else if (canSelectPast) {
// return current && current > today;
// } else {
// return current && current < today;
// }
// };
// return (
// <Space direction="vertical">
// <FloatLabel label={label} isOnChange={isOnChange}>
// <DatePicker
// style={{ height: '49px' }}
// format="DD-MM-YYYY"
// value={
// valueData != undefined
// ? dayjs(valueData, 'YYYY-MM-DDTHH:mm:ss')
// : ''
// }
// disabledDate={disabledDate}
// onChange={onChange}
// inputReadOnly={true}
// />
// </FloatLabel>
// </Space>
// );
// };

View File

@ -0,0 +1,62 @@
import {DatePicProd as DatePicProdLibrary}from"../../../ownLib/my-ui-lib"
export const DatePicProd = DatePicProdLibrary
// import { DatePicker, Space } from 'antd';
// import dayjs from 'dayjs';
// import customParseFormat from 'dayjs/plugin/customParseFormat';
// dayjs.extend(customParseFormat);
// export const DatePicProd = ({
// onChange,
// canSelectPast,
// valueData,
// disabled,
// cancelFuture,
// minDate,
// dontallowfeature,
// }) => {
// const disabledDate = (current) => {
// var date = new Date();
// date.setDate(date.getDate() + 1);
// return current.valueOf() <= date.setDate(date.getDate() - 2);
// };
// const disabledFutureDate = (current) => {
// // Can not select days before today and today
// return current && current > dayjs().endOf('day');
// };
// const disabledMinDate = (current) => {
// if (minDate) {
// return (
// current &&
// current < dayjs(minDate, 'YYYY-MM-DDTHH:mm:ss').startOf('day')
// );
// }
// return false;
// };
// return (
// <Space direction="vertical">
// <DatePicker
// format="DD-MM-YYYY"
// value={valueData ? dayjs(valueData, 'YYYY-MM-DDTHH:mm:ss') : ''}
// disabledDate={(current) => {
// if (dontallowfeature) {
// return current && current > dayjs().endOf('day');
// } else if (canSelectPast) {
// if (cancelFuture) {
// return disabledFutureDate(current) || disabledMinDate(current);
// }
// return disabledMinDate(current);
// }
// return disabledDate(current) || disabledMinDate(current);
// }}
// disabled={disabled}
// onChange={onChange}
// inputReadOnly={true}
// />
// </Space>
// );
// };

View File

@ -0,0 +1,194 @@
import { Select } from 'antd';
import classnames from 'classnames';
import FloatLabel from './FloatLabel/index';
import React, { forwardRef, useEffect, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import {
changeDropDownStatus,
GlobalfocusStatusCust,
} from '../../Features/BookingScreen/BookingData/BookingData';
import { validateSafeInput } from '../../Services/Others';
export const DropDowns = forwardRef((props, ref) => {
const {
options,
onChangeFunction,
isOnchanges,
className,
defaultValue,
disabled,
alphabetfilter,
label,
valueData,
labelChange,
...rest
} = props;
const [isOnChangeState, setIsOnChangeState] = useState(isOnchanges);
const dispatch = useDispatch();
const selectStatuscust = useSelector(GlobalfocusStatusCust);
useEffect(() => {
setIsOnChangeState(isOnchanges);
}, [isOnchanges]);
const handleMouseEnter = () => {
dispatch(changeDropDownStatus(true));
};
const handleChangeStatus = () => {
dispatch(changeDropDownStatus(false));
setIsOnChangeState(true);
};
return (
<div onMouseEnter={handleMouseEnter}>
<FloatLabel
ref={ref}
label={label}
value={valueData ?? ''}
isOnChange={valueData != null ? true : isOnChangeState}
>
<Select
{...rest}
showSearch
style={{ width: 250 }}
defaultValue={defaultValue ?? null}
optionFilterProp="children"
filterOption={
props.filterOption !== undefined
? props.filterOption
: !labelChange
? (input, option) =>
(option?.label ?? '')
?.toLowerCase()
?.includes(input?.toLowerCase())
: null
}
filterSort={
!labelChange
? (a, b) =>
alphabetfilter === 'No'
? parseInt(a.value, 10) - parseInt(b.value, 10)
: (a?.label ?? '')
?.toLowerCase()
?.localeCompare((b?.label ?? '')?.toLowerCase())
: null
}
value={valueData}
onChange={(e, option) => {
onChangeFunction(e, option);
handleChangeStatus();
}}
options={options}
className={classnames(className)}
disabled={disabled}
// getPopupContainer={(triggerNode) => triggerNode.parentNode}
getPopupContainer={(triggerNode) => document.body}
/>
</FloatLabel>
</div>
);
});
// export const DropDowns = forwardRef(({ options, onChangeFunction, isOnchanges, className, defaultValue, disabled, numberOpt, alphabetfilter, ...props },ref) => {
// const [inpValue, setInputValue] = useState('')
// const [isOnchange, setisOnchange] = useState(isOnchanges)
// const dispatch = useDispatch();
// const selectStatuscust = useSelector(GlobalfocusStatusCust);
// useEffect(() => {
// setisOnchange(isOnchanges)
// }, [isOnchanges])
// const changeStatus = () => {
// dispatch(changeDropDownStatus(false))
// setisOnchange(true)
// }
// const {
// field,
// onChange,
// label,
// onBlur,
// forwardedRef,
// required,
// valueData,
// labelChange,
// ...rest
// } = props;
// const MouseFunction = async (e) => {
// dispatch(changeDropDownStatus(e))
// }
// const openMenuClick = async () => {
// // await dispatch(changefocusStatusCustMouse(true));
// }
// // const HandleClick = async (e) => {
// // MouseFunction(false)
// // if (!e) {
// // dispatch(changefocusStatusCust(!selectStatuscust));
// // }
// // };
// return (
// <div onMouseEnter={() => MouseFunction(true)}
// // onMouseLeave={() => MouseFunction(false)}
// // last i commet this one
// onClick={() => openMenuClick()}>
// <FloatLabel
// label={label}
// value={inpValue}
// isOnChange={valueData != null ? true : isOnchange}
// >
// <Select
// showSearch
// ref={ref}
// style={{
// width: 250
// }}
// defaultValue={defaultValue ? defaultValue : null}
// optionFilterProp="children"
// filterOption={
// !labelChange
// ? (input, option) =>
// (option?.label ?? '')
// .toLowerCase()
// .includes(input?.toLowerCase())
// : null
// }
// filterSort={
// !labelChange
// ? (optionA, optionB) => {
// if (alphabetfilter === "No") {
// return parseInt(optionA.value, 10) - parseInt(optionB.value, 10);
// } else {
// return (optionA?.label ?? '')
// ?.toLowerCase()
// ?.localeCompare((optionB?.label ?? '').toLowerCase());
// }
// }
// : null
// }
// value={valueData}
// onChange={(e) => {
// onChangeFunction(e);
// changeStatus();
// }}
// onSelect={(e) => changeStatus(e)}
// options={options}
// className={classnames(` ${className}`)}
// disabled={disabled ? true : false}
// // onMenuClose={() => HandleClick(false)}
// />
// </FloatLabel>
// </div>
// )
// });

View File

@ -0,0 +1,101 @@
import { Select } from 'antd';
import classnames from 'classnames';
import FloatLabel from './FloatLabel/index';
import React, { useEffect, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import {
changeDropDownStatus,
GlobalfocusStatusCust,
} from '../../Features/BookingScreen/BookingData/BookingData';
export const DropDowns1 = ({
options,
onChangeFunction,
isOnchanges,
className,
defaultValue,
disabled,
numberOpt,
alphabetfilter,
labelChange,
valueData,
label,
...props
}) => {
const [inpValue, setInputValue] = useState('');
const [isOnchange, setisOnchange] = useState(isOnchanges);
const dispatch = useDispatch();
const selectStatuscust = useSelector(GlobalfocusStatusCust);
useEffect(() => {
setisOnchange(isOnchanges);
}, [isOnchanges]);
const changeStatus = () => {
dispatch(changeDropDownStatus(false));
setisOnchange(true);
};
const MouseFunction = (e) => {
dispatch(changeDropDownStatus(e));
};
const openMenuClick = () => {
// You can add logic here if needed
};
return (
<div
onMouseEnter={() => MouseFunction(true)}
// onMouseLeave={() => MouseFunction(false)} // uncomment if needed
onClick={() => openMenuClick()}
>
<FloatLabel
label={label}
value={inpValue}
isOnChange={valueData != null ? true : isOnchange}
>
<Select
showSearch
style={{ width: 250 }}
defaultValue={defaultValue ?? null}
optionFilterProp="children"
filterOption={
!labelChange
? (input, option) => {
// Use searchLabel if available, else empty string (to avoid errors)
const target = option?.searchLabel ?? '';
return target?.toLowerCase().includes(input?.toLowerCase());
}
: null
}
filterSort={
!labelChange
? (optionA, optionB) => {
if (alphabetfilter === 'No') {
return (
parseInt(optionA.value, 10) - parseInt(optionB.value, 10)
);
} else {
const a = optionA?.searchLabel ?? '';
const b = optionB?.searchLabel ?? '';
return a?.toLowerCase()?.localeCompare(b?.toLowerCase());
}
}
: null
}
value={valueData}
onChange={(e) => {
onChangeFunction(e);
changeStatus();
}}
onSelect={(e) => changeStatus(e)}
options={options}
className={classnames(className)}
disabled={!!disabled}
{...props}
/>
</FloatLabel>
</div>
);
};

View File

@ -0,0 +1,66 @@
import { FilterButton as FilterButtonLibrary } from "../../../ownLib/my-ui-lib"
export const FilterButton = FilterButtonLibrary
export default FilterButton;
// import { Select } from 'antd';
// import classnames from 'classnames';
// import FloatLabel from './FloatLabel/index';
// import React, { useState } from 'react';
// export const FilterButton = ({
// options,
// onChangeFunction,
// isOnchanges,
// className,
// defaultValue,
// disabled,
// onSearch,
// onSearchChange,
// ...props
// }) => {
// const [inpValue, setInputValue] = useState('');
// const [isOnchange, setisOnchange] = useState(isOnchanges);
// const changeStatus = async () => {
// await setisOnchange(true);
// };
// const {
// field,
// onChange,
// label,
// onBlur,
// forwardedRef,
// required,
// valueData,
// ...rest
// } = props;
// return (
// <FloatLabel label={label} value={inpValue} isOnChange={isOnchange}>
// <Select
// showSearch
// style={{
// width: 220,
// }}
// defaultValue={defaultValue ? defaultValue : null}
// optionFilterProp="children"
// filterOption={(input, option) => (option?.label ?? '')?.includes(input)}
// filterSort={(optionA, optionB) =>
// (optionA?.label ?? '')
// ?.toLowerCase()
// ?.localeCompare((optionB?.label ?? '')?.toLowerCase())
// }
// value={valueData}
// onChange={(e) => onChangeFunction(e)}
// onSelect={(e) => changeStatus(e)}
// options={options}
// className={classnames(` ${className}`)}
// disabled={disabled ? true : false}
// />
// </FloatLabel>
// );
// };
// export default FilterButton;

View File

@ -0,0 +1,24 @@
.float-label {
position: relative;
margin-bottom: 12px;
}
.label {
font-size: 14px !important;
font-weight: normal;
position: absolute;
pointer-events: none;
left: 12px;
font-family: Arial, Helvetica, sans-serif;
top: 14px;
transition: 0.2s ease all;
}
.label-float {
font-size: 12px !important;
top: 2px;
left: 12px;
font-style: normal;
color: #007eb5;
z-index: 23;
}

View File

@ -0,0 +1,29 @@
// import React, { useState } from 'react';
// import './index.css';
import { FloatLabel as FloatLabelLibrary } from '../../../../ownLib/my-ui-lib.js';
const FloatLabel = FloatLabelLibrary
export default FloatLabel;
// const FloatLabel = (props) => {
// const [focus, setFocus] = useState(false);
// const { children, label, value, isOnChange } = props;
// const labelClass =
// focus || (value && value?.length !== 0) || isOnChange
// ? 'label label-float'
// : 'label';
// return (
// <div
// className="float-label"
// onBlur={() => setFocus(false)}
// onFocus={() => setFocus(true)}
// >
// {children}
// <label className={labelClass}>{label}</label>
// </div>
// );
// };
// export default FloatLabel;

View File

@ -0,0 +1,111 @@
// import React, {useState } from "react";
// import { Input} from "antd";
// import FloatLabel from "./FloatLabel/index.jsx";
// import "./main.scss";
// export const InputField = ({...props}) => {
// const [inpValue , setInputValue] = useState('')
// const {
// onChange,
// isOnChange,
// onBlur,
// onKeyUp,
// label,
// disable=false,
// ...rest
// } = props;
// return (
// <div className="example">
// <FloatLabel
// label={label}
// value = {inpValue}
// isOnChange= {isOnChange}
// >
// <Input
// disabled={disable}
// {...rest}
// onChange={(e) => {
// setInputValue(e?.target?.value)
// if (onChange) {
// onChange(e);
// }
// }}
// onBlur={(e) => {
// if (onBlur) {
// onBlur(e);
// }
// }}
// onKeyUp={(e) => {
// if (onKeyUp) {
// onKeyUp(e);
// }
// }}
// autoComplete="Off"
// />
// </FloatLabel>
// </div>
// );
// };
// import React, {
// forwardRef,
// useImperativeHandle,
// useRef,
// useState,
// } from 'react';
// import { Input } from 'antd';
// import FloatLabel from './FloatLabel/index.jsx';
// import './main.scss';
import { InputField as InputFieldLibrary } from '../../../ownLib/my-ui-lib.js';
export const InputField = InputFieldLibrary
// export const InputField = forwardRef((props, outerRef) => {
// const [inpValue, setInputValue] = useState('');
// const inputRef = useRef(null);
// const wrapperRef = useRef(null);
// const {
// onChange,
// isOnChange,
// onBlur,
// onKeyUp,
// label,
// disable = false,
// ...rest
// } = props;
// useImperativeHandle(outerRef, () => wrapperRef.current);
// return (
// <div className="example" ref={wrapperRef}>
// <FloatLabel label={label} value={inpValue} isOnChange={isOnChange}>
// <Input
// ref={inputRef}
// disabled={disable}
// {...rest}
// onChange={(e) => {
// setInputValue(e?.target?.value);
// if (onChange) {
// onChange(e);
// }
// }}
// onBlur={(e) => {
// if (onBlur) {
// onBlur(e);
// }
// }}
// onKeyUp={(e) => {
// if (onKeyUp) {
// onKeyUp(e);
// }
// }}
// autoComplete="Off"
// />
// </FloatLabel>
// </div>
// );
// });

View File

@ -0,0 +1,20 @@
.ant-radio-wrapper .ant-radio-checked .ant-radio-inner {
border-color: #000000;
background-color: #000000;
}
.ant-radio-wrapper .ant-radio-inner {
box-sizing: border-box;
position: relative;
inset-block-start: 0;
inset-inline-start: 0;
display: block;
width: 16px;
height: 16px;
background-color: #ffffff;
border-color: #000000;
border-style: solid;
border-width: 1px;
border-radius: 50%;
transition: all 0.2s;
}

View File

@ -0,0 +1,56 @@
import {RadioGrpButton as RadioGrpButtonLibrary} from "../../../ownLib/my-ui-lib"
export const RadioGrpButton = RadioGrpButtonLibrary
// import { Radio } from 'antd';
// import { useEffect, useState } from 'react';
// import './RadioBtn.scss';
// export const RadioGrpButton = ({ fieldState, style, ...props }) => {
// const {
// field,
// onBlur,
// initialValue,
// forwardedRef,
// onClickFunction,
// className,
// onSelectFuntion,
// content,
// Header,
// defaultSelect,
// disabled,
// ...rest
// } = props;
// const [value, setValue] = useState(defaultSelect);
// const onChange = (e) => {
// setValue(e?.target?.value);
// if (onSelectFuntion) {
// onSelectFuntion(e?.target?.value);
// }
// };
// const onClickfun = (e) => {
// if (onClickFunction) {
// onClickFunction(e?.target?.value);
// }
// };
// useEffect(() => {
// setValue(defaultSelect);
// }, [props]);
// return (
// <div>
// <p style={{ paddingBottom: '10px', fontWeight: '500' }}>{Header}</p>
// <Radio.Group onChange={onChange} value={value}>
// {content?.map((key, index) => (
// <Radio
// value={key.value}
// key={index}
// onClick={(e) => onClickfun(e)}
// disabled={disabled ? disabled : false}
// >
// {key.label}
// </Radio>
// ))}
// </Radio.Group>
// </div>
// );
// };

View File

@ -0,0 +1,25 @@
import { Radio } from 'antd';
export const RadioButton = ({ faClass, style, ...props }) => {
const { onChange, onBlur, ...rest } = props;
return (
<Radio
{...rest}
name={props.props.name}
value={props.props.value}
onChange={(e) => {
if (onChange) {
onChange(e);
}
}}
onBlur={(e) => {
if (onBlur) {
onBlur(e);
}
}}
>
{props.props.label}
</Radio>
);
};

View File

@ -0,0 +1,37 @@
import {ScannerInputField as ScannerInputFieldLibrary} from "../../../ownLib/my-ui-lib"
export const ScannerInputField = ScannerInputFieldLibrary
// import React, { useState } from 'react';
// import { Input } from 'antd';
// import FloatLabel from './FloatLabel/index.jsx';
// import './main.scss';
// export const ScannerInputField = ({ ...props }) => {
// const [inpValue, setInputValue] = useState('');
// const {
// onChange,
// isOnChange,
// label,
// valueData,
// ...rest
// } = props;
// return (
// <div className="example">
// <FloatLabel label={label} value={inpValue} isOnChange={isOnChange}>
// <Input
// {...rest}
// onChange={(e) => {
// setInputValue(e?.target?.value);
// if (onChange) {
// onChange(e);
// }
// }}
// />
// </FloatLabel>
// </div>
// );
// };

View File

@ -0,0 +1,28 @@
import {Search as SearchLibrary} from "../../../ownLib/my-ui-lib"
export const Search = SearchLibrary
export default Search;
// import { Input } from 'antd';
// import { SearchOutlined } from '@ant-design/icons';
// import './main.scss';
// import React from 'react';
// export const Search = React.forwardRef(({ placeholder, onSearch, onSearchChange, value }, ref) => {
// return (
// <Input
// ref={ref}
// maxLength={50}
// value={value}
// className="searchDiv"
// placeholder={placeholder}
// prefix={<SearchOutlined style={{ color: '#999' }} />}
// onPressEnter={onSearch}
// onChange={onSearchChange}
// />
// )
// })
// export default Search;

View File

@ -0,0 +1,249 @@
import {ShapeCropper as ShapeCropperLibrary} from "../../../ownLib/my-ui-lib"
const ShapeCropper=ShapeCropperLibrary
export default ShapeCropper;
// import React, { useEffect, useRef, useState, useCallback } from 'react';
// import { ReloadOutlined, EyeOutlined, DeleteFilled } from '@ant-design/icons';
// import { Messages } from '../../Components/Notifications/Messages';
// import TooltipWrapper from '../../Components/Tooltip/Tooltip';
// import { isMobile } from 'react-device-detect';
// const ShapeCropper = ({ imageUrl, onShape }) => {
// const canvasRef = useRef(null);
// const imgRef = useRef(null);
// const [messageType, setMessageType] = useState(null);
// const [messageData, setMessageData] = useState(null);
// const [points, setPoints] = useState([]);
// const [imageLoaded, setImageLoaded] = useState(false);
// const [clippedImages, setClippedImages] = useState([]);
// const [definingClippingPath, setDefiningClippingPath] = useState(false);
// const [isPreview, setIsPreview] = useState(false);
// useEffect(() => {
// setPoints([]);
// setClippedImages([]);
// setDefiningClippingPath(true);
// setImageLoaded(false);
// const canvas = canvasRef.current;
// const ctx = canvas.getContext('2d');
// const img = new Image();
// img.crossOrigin = 'anonymous';
// img.onload = () => {
// imgRef.current = img;
// canvas.width = img.width;
// canvas.height = img.height;
// ctx.drawImage(img, 0, 0);
// setImageLoaded(true);
// };
// img.src = imageUrl;
// return () => {
// ctx.clearRect(0, 0, canvas.width, canvas.height);
// setPoints([]);
// setClippedImages([]);
// setImageLoaded(false);
// setDefiningClippingPath(true);
// };
// }, [imageUrl]);
// useEffect(() => {
// if (imageLoaded && definingClippingPath) {
// const canvas = canvasRef.current;
// const ctx = canvas.getContext('2d');
// ctx.clearRect(0, 0, canvas.width, canvas.height);
// ctx.drawImage(imgRef.current, 0, 0);
// drawClippingPath(ctx);
// }
// }, [imageLoaded, definingClippingPath, points]);
// useEffect(() => {
// if (clippedImages.length > 0) {
// onShape(clippedImages);
// }
// }, [clippedImages]);
// const onComplete = useCallback(() => {
// setMessageData(null);
// setMessageType(null);
// }, []);
// const handleMouseDown = (e) => {
// e.preventDefault();
// e.stopPropagation();
// const rect = canvasRef.current.getBoundingClientRect();
// const mx = e.clientX - rect.left;
// const my = e.clientY - rect.top;
// if (
// points.length > 1 &&
// Math.abs(mx - points[0].x) < 10 &&
// Math.abs(my - points[0].y) < 10
// ) {
// clipIt();
// setDefiningClippingPath(false);
// } else {
// setPoints([...points, { x: mx, y: my }]);
// }
// };
// const drawClippingPath = (ctx) => {
// ctx.strokeStyle = '#ff4d4f';
// ctx.beginPath();
// if (points.length > 0) {
// ctx.moveTo(points[0].x, points[0].y);
// for (let i = 1; i < points.length; i++) {
// ctx.lineTo(points[i].x, points[i].y);
// }
// ctx.lineTo(points[0].x, points[0].y);
// }
// ctx.stroke();
// if (points.length > 0) {
// ctx.beginPath();
// ctx.arc(points[0].x, points[0].y, 10, 0, Math.PI * 2);
// ctx.stroke();
// }
// };
// const clipIt = () => {
// const canvas = canvasRef.current;
// const ctx = canvas.getContext('2d');
// const minX = Math.min(...points.map((point) => point.x));
// const minY = Math.min(...points.map((point) => point.y));
// const maxX = Math.max(...points.map((point) => point.x));
// const maxY = Math.max(...points.map((point) => point.y));
// const width = maxX - minX;
// const height = maxY - minY;
// const clippedCanvas = document.createElement('canvas');
// clippedCanvas.width = width;
// clippedCanvas.height = height;
// const clippedCtx = clippedCanvas.getContext('2d');
// clippedCtx.drawImage(
// imgRef.current,
// minX,
// minY,
// width,
// height,
// 0,
// 0,
// width,
// height
// );
// setMessageType('success');
// setMessageData('Image Cropped Successfully');
// setClippedImages((prevImages) => [
// ...prevImages,
// clippedCanvas.toDataURL(),
// ]);
// setPoints([]);
// };
// const setReset = () => {
// if (points?.length > 0) {
// setPoints([]);
// onShape(null);
// const canvas = canvasRef.current;
// const ctx = canvas.getContext('2d');
// ctx.clearRect(0, 0, canvas.width, canvas.height);
// } else {
// setMessageType('error');
// setMessageData('No Clipping Region');
// }
// };
// const setPreview = () => {
// if (clippedImages?.length > 0) {
// setIsPreview(!isPreview);
// } else {
// setMessageType('error');
// setMessageData('No Image Found To Preview');
// }
// };
// const setRemove = () => {
// if (clippedImages?.length > 0) {
// setClippedImages([]);
// setPoints([]);
// setIsPreview(false);
// setDefiningClippingPath(true);
// onShape(null);
// } else {
// setMessageType('error');
// setMessageData('No Image Found To Remove');
// }
// };
// return (
// <div className="shape-crop">
// <Messages
// messageType={messageType}
// messageData={messageData}
// onComplete={onComplete}
// />
// <h4>
// Click to outline clipping region. Click back in starting circle to
// complete the clip.
// </h4>
// <div className="shape-crop-subdiv">
// <div>
// <canvas
// ref={canvasRef}
// width={300}
// height={150}
// style={{ border: '1px solid black' }}
// onMouseDown={handleMouseDown}
// ></canvas>
// </div>
// <div>
// {isPreview &&
// clippedImages?.map((image, index) => (
// <img
// key={index}
// src={image}
// alt={`Clipped image ${index}`}
// style={{ width: '200px', height: '100px' }}
// />
// ))}
// </div>
// </div>
// <div className="shape-crop-subdiv">
// <div>
// <TooltipWrapper title={'Reset'} isMobile={isMobile}>
// <ReloadOutlined
// className="shape-reset"
// onClick={() => setReset()}
// />
// </TooltipWrapper>
// </div>
// <div>
// <TooltipWrapper title={'Preview'} isMobile={isMobile}>
// <EyeOutlined
// className="shape-preview"
// onClick={() => setPreview()}
// />
// </TooltipWrapper>
// </div>
// <div>
// <TooltipWrapper title={'Remove'} isMobile={isMobile}>
// <DeleteFilled
// className="shape-delete"
// onClick={() => setRemove()}
// />
// </TooltipWrapper>
// </div>
// </div>
// </div>
// );
// };
// export default ShapeCropper;

View File

@ -0,0 +1,9 @@
// import { Switch } from 'antd';
import { Toggle as ToggleLibrary } from '../../../ownLib/my-ui-lib';
export const Toggle = ToggleLibrary
// export const Toggle = ({ defaultChecked, functionName }) => {
// return <Switch defaultChecked={defaultChecked} onChange={functionName} />;
// };

View File

@ -0,0 +1,46 @@
import {TextAreaInput as TextAreaInputLibrary } from "../../../ownLib/my-ui-lib"
export const TextAreaInput = TextAreaInputLibrary
export default TextAreaInput;
// import React, { useEffect, useState } from 'react';
// import { Input } from 'antd';
// import FloatLabel from './FloatLabel/index.jsx';
// import './main.scss';
// export const TextAreaInput = ({ ...props }) => {
// const [inpValue, setInputValue] = useState(props?.defaultValue || '');
// const { TextArea } = Input;
// useEffect(() => {
// setInputValue(props?.defaultValue);
// }, [props?.defaultValue]);
// const { onChange, isOnChange, onBlur, label,width = false, ...rest } = props;
// return (
// <div className={width? "" : "example"} style={{ width: width ? '100%' : 'auto' }}>
// <FloatLabel label={label} value={inpValue} isOnChange={isOnChange}>
// <TextArea
// {...rest}
// onChange={(e) => {
// setInputValue(e?.target?.value);
// if (onChange) {
// onChange(e);
// }
// }}
// onBlur={(e) => {
// if (onBlur) {
// onBlur(e);
// }
// }}
// />
// </FloatLabel>
// </div>
// );
// };
// export default TextAreaInput;

View File

@ -0,0 +1,28 @@
import { TimePickers as TimePickerLibrary } from "../../../ownLib/my-ui-lib"
export const TimePickers = TimePickerLibrary
export default TimePickers;
// import { TimePicker } from 'antd';
// import dayjs from 'dayjs';
// import customParseFormat from 'dayjs/plugin/customParseFormat';
// import FloatLabel from './FloatLabel/index.jsx';
// import './main.scss';
// dayjs.extend(customParseFormat);
// export const TimePickers = ({ label, isOnChange, onChange, valueData }) => (
// <div className="example">
// <FloatLabel label={label} isOnChange={isOnChange}>
// <TimePicker
// className="TimePickerDiv"
// use12Hours
// format="h:mm a"
// onChange={onChange}
// value={valueData != undefined ? dayjs(valueData, 'HH:mm:ss') : ''}
// inputReadOnly={true}
// />
// </FloatLabel>
// </div>
// );
// export default TimePickers;

View File

@ -0,0 +1,24 @@
import { TimePickersProduct as TimePickersProductLibrary} from "../../../ownLib/my-ui-lib"
export const TimePickers =TimePickersProductLibrary
export default TimePickers;
// import { TimePicker } from 'antd';
// import dayjs from 'dayjs';
// import customParseFormat from 'dayjs/plugin/customParseFormat';
// dayjs.extend(customParseFormat);
// export const TimePickers = ({ onChange, valueData }) => (
// <div>
// <TimePicker
// use12Hours
// format="h:mm a"
// onChange={onChange}
// value={valueData != undefined ? dayjs(valueData, 'HH:mm:ss') : ''}
// inputReadOnly={true}
// />
// </div>
// );
// export default TimePickers;

View File

@ -0,0 +1,131 @@
import { useEffect, useState } from 'react';
import { useDispatch } from 'react-redux';
import { Modal, Upload } from 'antd';
import { PlusOutlined } from '@ant-design/icons';
import { uploadImage } from '../../Features/upload/upload';
const allowedTypes = [
'image/jpeg',
'image/png',
'image/webp',
'image/svg+xml',
'image/gif',
'image/avif',
];
const getBase64 = (file) =>
new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => resolve(reader.result);
reader.onerror = (error) => reject(error);
});
const App = ({ singleImage, updateImageUrl, ImageLink = '', listType }) => {
const dispatch = useDispatch();
const [previewOpen, setPreviewOpen] = useState(false);
const [previewImage, setPreviewImage] = useState('');
const [previewTitle, setPreviewTitle] = useState('');
const [fileList, setFileList] = useState([]);
useEffect(() => {
// Inside Imageupload.jsx
const safeLink = typeof ImageLink === 'string' ? ImageLink : '';
if (safeLink != '' && safeLink != null) {
setFileList([{ url: safeLink }]);
} else {
setFileList([]);
}
}, [ImageLink]);
const handleCancel = () => setPreviewOpen(false);
const handlePreview = async (file) => {
if (!file.url && !file.preview) {
file.preview = await getBase64(file.originFileObj);
}
setPreviewImage(file.url || file.preview);
setPreviewOpen(true);
setPreviewTitle(
file.name || file.url.substring(file.url.lastIndexOf('/') + 1)
);
};
const handleRemove = () => {
updateImageUrl('');
};
const handleChange = async ({ fileList: newFileList }) => {
if (newFileList?.length > 0) {
let data = await dispatch(
uploadImage(newFileList[0].originFileObj)
).unwrap();
if (data?.data?.status) {
updateImageUrl(data?.data?.image);
setFileList([{ url: data?.data?.image }]);
}
} else {
updateImageUrl('');
setFileList(newFileList);
}
};
const beforeUpload = (file) => {
const isAllowed = allowedTypes.includes(file.type);
if (!isAllowed) {
Modal.error({
title: 'Invalid File Type',
content:
'Only JPG, JPEG, PNG, WEBP, SVG, GIF, and AVIF files are allowed.',
});
}
return isAllowed || Upload.LIST_IGNORE; // prevents adding to fileList if invalid
};
const uploadButton = (
<div>
<PlusOutlined />
<div
style={{
marginTop: 8,
}}
className="uploadText"
>
Upload
</div>
</div>
);
return (
<>
<Upload
action="https://www.mocky.io/v2/5cc8019d300000980a055e76"
listType={listType ? listType : 'picture-circle'}
fileList={fileList}
onPreview={handlePreview}
onChange={handleChange}
onRemove={handleRemove}
beforeUpload={beforeUpload}
>
{singleImage && fileList?.length == 0
? uploadButton
: !singleImage && fileList?.length <= 8
? uploadButton
: null}
</Upload>
<Modal
open={previewOpen}
title={''}
footer={null}
onCancel={handleCancel}
>
<img
alt="example"
style={{
width: '100%',
}}
src={previewImage}
/>
</Modal>
</>
);
};
export default App;

View File

@ -0,0 +1,63 @@
import React, { useEffect, useRef, useState } from 'react';
import { useDispatch } from 'react-redux';
import { uploadImage } from '../../Features/upload/upload';
import videoBg from '../../Images/TemplateImages/videobg.svg';
import './VideoUpload.scss';
export default function VideoInput({ updateVideoUrl, videoUrl }) {
const inputRef = useRef();
const dispatch = useDispatch();
const [source, setSource] = useState();
useEffect(() => {
if (videoUrl) {
setSource(videoUrl);
} else {
if (inputRef?.current) {
inputRef?.current?.value = null;
}
setSource();
}
}, [videoUrl]);
const handleFileChange = async (event) => {
let file = event.target.files[0];
if (event.target.files?.length > 0) {
let data = await dispatch(uploadImage(file)).unwrap();
if (data?.data?.status) {
updateVideoUrl(data?.data?.image);
setSource(data?.data?.image);
}
} else {
updateVideoUrl('');
setSource('');
}
};
const handleChoose = (event) => {
inputRef?.current?.click();
};
return (
<div>
<input
ref={inputRef}
className="VideoInput_input"
type="file"
onChange={handleFileChange}
accept=".mov,.mp4"
/>
{!source && (
<button
type="button"
style={{ backgroundColor: '#cfcfcf', borderColor: '#cfcfcf' }}
onClick={handleChoose}
>
<img src={videoBg} style={{ width: '150px', height: '85px' }}></img>
</button>
)}
{source && <video className="VideoInput_video" controls src={source} />}
</div>
);
}

View File

@ -0,0 +1,18 @@
.VideoInput_input {
display: none;
}
.VideoInput_video {
display: block;
margin: 0;
height: 85px;
width: 150px;
}
.VideoInput_footer {
background: #eee;
width: 100%;
min-height: 40px;
line-height: 40px;
text-align: center;
}

View File

@ -0,0 +1,43 @@
import {InputFieldCustom as InputFieldCustomLibrary} from "../../../ownLib/my-ui-lib"
export const InputFieldCustom = InputFieldCustomLibrary
// import React, { useState } from 'react';
// import { Input } from 'antd';
// import FloatLabel from './FloatLabel/index.jsx';
// import './main.scss';
// export const InputFieldCustom = ({ ...props }) => {
// const [inpValue, setInputValue] = useState('');
// const { onChange, isOnChange, onBlur, label, ...rest } = props;
// return (
// <div
// className={'CustomInputField'}
// style={{ marginLeft: '-40px', width: '70px', fontSize: '14px' }}
// >
// <FloatLabel
// label={label}
// value={inpValue}
// isOnChange={isOnChange}
// style={{ width: '12px !important' }}
// >
// <Input
// {...rest}
// onChange={(e) => {
// setInputValue(e?.target?.value);
// if (onChange) {
// onChange(e);
// }
// }}
// onBlur={(e) => {
// if (onBlur) {
// onBlur(e);
// }
// }}
// autoComplete="Off"
// />
// </FloatLabel>
// </div>
// );
// };

View File

@ -0,0 +1,983 @@
.example {
width: var(--INPUT_FIELD_WIDTH);
}
.ant-input {
padding: 18px 14px 6px 11px;
font-size: 16px;
font-weight: 490;
color: #000;
}
.ant-input:hover {
padding: 18px 14px 6px 11px;
font-size: 16px;
border: var(--DEFAULT_SELECTED_COLOR) solid 1px;
}
.ant-input:focus {
padding: 18px 14px 6px 11px;
font-size: 16px;
border: var(--DEFAULT_SELECTED_COLOR) solid 1px;
}
.ant-select .ant-select-selector {
padding: 16px 10px 4px 11px;
}
.ant-select-single:not(.ant-select-customize-input) .ant-select-selector {
padding: 8px 10px 4px 11px;
height: 53px;
font-size: 16px;
padding: 10px;
font-weight: 600;
}
.ant-select .ant-select-selector {
padding: 16px 10px 4px 11px;
}
.ant-select-single:not(.ant-select-customize-input) .ant-select-selector {
padding: 8px 10px 4px 11px;
height: 48px;
font-size: 16px;
padding: 10px;
font-weight: 600;
}
.ant-select-single .ant-select-selector .ant-select-selection-search {
top: 16px;
font-size: 16px;
}
:where(.css-dev-only-do-not-override-1fviqcj).ant-select-dropdown
.ant-select-item-option-selected:not(.ant-select-item-option-disabled) {
color: rgba(255, 255, 255, 0.88);
font-weight: 600;
background-color: var(--PRIMARY_BUTTON_BG_COLOR);
}
.primary_Button {
width: 170px;
height: 42px;
background-color: var(--PRIMARY_BUTTON_BG_COLOR) !important;
color: #fff;
font-family: var(--HEADING_FONT_FAMILY);
font-style: normal;
font-weight: 500;
font-size: 14px;
border-radius: 8px;
display: flex;
letter-spacing: 0.5px;
justify-content: space-between;
align-items: center;
z-index: 2;
}
.primary_Button {
border: 1px solid;
overflow: hidden;
span {
z-index: 20;
}
&:after {
background: #fff;
content: '';
height: 155px;
left: -75px;
opacity: 0.2;
position: absolute;
top: -50px;
transform: rotate(35deg);
transition: all 550ms cubic-bezier(0.19, 1, 0.22, 1);
width: 50px;
z-index: -10;
}
}
.primary_Button:hover {
&:after {
left: 120%;
transition: all 550ms cubic-bezier(0.19, 1, 0.22, 1);
}
}
.primary_Button:focus {
border: 1.8px solid var(--PRIMARY_BUTTON_BG_COLOR);
background-color: #ffffff !important;
color: #901d77;
font-weight: 600;
font-size: 14px;
}
.primary_Button:focus:hover {
border: 1.8px solid var(--PRIMARY_BUTTON_BG_COLOR);
background-color: white !important;
color: var(--PRIMARY_BUTTON_BG_COLOR);
font-weight: 600;
font-size: 14px;
}
.secondary_Button {
width: 170px;
height: 42px;
background-color: black !important;
color: #fff;
font-family: var(--HEADING_FONT_FAMILY);
font-style: normal;
font-weight: 500;
font-size: 14px;
border-radius: 8px;
display: flex;
letter-spacing: 0.5px;
justify-content: space-between;
align-items: center;
z-index: 2;
}
.secondary_Button {
border: 1px solid;
overflow: hidden;
span {
z-index: 20;
}
&:after {
background: #fff;
content: '';
height: 155px;
left: -75px;
opacity: 0.2;
position: absolute;
top: -50px;
transform: rotate(35deg);
transition: all 550ms cubic-bezier(0.19, 1, 0.22, 1);
width: 50px;
z-index: -10;
}
}
.secondary_Button:hover {
&:after {
left: 120%;
transition: all 550ms cubic-bezier(0.19, 1, 0.22, 1);
}
}
.secondary_Button:focus {
border: 1.8px solid var(--PRIMARY_BUTTON_BG_COLOR);
background-color: #ffffff !important;
color: #901d77;
font-weight: 600;
font-size: 14px;
}
.secondary_Button:focus:hover {
border: 1.8px solid var(--PRIMARY_BUTTON_BG_COLOR);
background-color: white !important;
color: var(--PRIMARY_BUTTON_BG_COLOR);
font-weight: 600;
font-size: 14px;
}
.tertiary_Button {
width: 180px;
height: 42px;
background-color: var(--THIRD_BUTTON_BG_COLOR) !important;
color: #ffffff;
font-family: var(--HEADING_FONT_FAMILY);
font-style: normal;
font-weight: 400;
font-size: 14;
line-height: 18px;
border-radius: 8px;
display: flex;
letter-spacing: 0.5px;
justify-content: center;
align-items: center;
z-index: 2;
// left: 200px;
}
.tertiary_Button {
overflow: hidden;
span {
z-index: 20;
}
&:after {
content: '';
height: 155px;
left: -15px;
opacity: 0.2;
position: absolute;
top: -50px;
transform: rotate(35deg);
transition: all 550ms cubic-bezier(0.19, 1, 0.22, 1);
width: 50px;
z-index: -10;
}
}
.tertiary_Button:hover {
background-color: #000000 !important;
border-color: #fff !important;
font-weight: 500;
&:after {
left: 120%;
transition: all 550ms cubic-bezier(0.19, 1, 0.22, 1);
}
}
// .tertiary_Button{
// width: 100px;
// height:30px;
// background-color: var(--THIRD_BUTTON_BG_COLOR) !important;
// color:#fff;
// font-family: var( --HEADING_FONT_FAMILY );
// font-style: normal;
// font-weight: 400;
// font-size: 14;
// line-height: 18px;
// border-radius:8px;
// display: flex;
// letter-spacing: 0.5px;
// justify-content:center;
// align-items: center;
// z-index:2;
// left: 450px;
// }
// .tertiary_Button {
// border: 1px solid;
// overflow: hidden;
// span {
// z-index: 20;
// }
// &:after {
// content: "";
// height: 155px;
// left: -15px;
// opacity: .2;
// position: absolute;
// top: -50px;
// transform: rotate(35deg);
// transition: all 550ms cubic-bezier(0.19, 1, 0.22, 1);
// width: 50px;
// z-index: -10;
// }
// }
// .tertiary_Button:hover {
// &:after {
// left: 120%;
// transition: all 550ms cubic-bezier(0.19, 1, 0.22, 1);
// }
// }
Button:disabled,
Button[disabled] {
width: 170px;
height: 45px;
background-color: grey;
color: #fff;
font-family: var(--HEADING_FONT_FAMILY);
font-style: normal;
font-weight: 500;
font-size: 14px;
border-radius: 8px;
display: flex;
letter-spacing: 0.5px;
justify-content: space-between;
align-items: center;
z-index: 2;
}
.primary_Button {
background-color: var(--ERROR_COLOR);
color: white;
padding: 15px;
}
.ant-btn-primary:disabled,
.ant-btn-primary:disabled {
width: 170px;
height: 45px;
background-color: grey !important;
color: #fff;
font-family: var(--HEADING_FONT_FAMILY);
font-style: normal;
font-weight: 500;
font-size: 14px;
border-radius: 8px;
display: flex;
letter-spacing: 0.5px;
justify-content: space-between;
align-items: center;
z-index: 2;
}
.ant-btn-primary:disabled {
height: 25px;
background-color: white !important;
color: #fff;
font-family: var(--HEADING_FONT_FAMILY);
font-style: normal;
font-weight: 500;
font-size: 10px;
border-radius: 8px;
display: flex;
letter-spacing: 0.5px;
justify-content: center;
z-index: 2;
}
.ant-btn-primary:disabled {
background-color: var(--ERROR_COLOR);
color: #858585;
}
.ant-picker-dropdown
.ant-picker-cell-in-view.ant-picker-cell-today
.ant-picker-cell-inner::before {
position: absolute;
top: 0;
inset-inline-end: 0;
bottom: 0;
inset-inline-start: 0;
z-index: 1;
border: 1px solid var(--PRIMARY_BUTTON_BG_COLOR);
border-radius: 4px;
}
.ant-picker-dropdown
.ant-picker-cell-in-view.ant-picker-cell-selected
.ant-picker-cell-inner,
:where(.css-dev-only-do-not-override-1fviqcj).ant-picker-dropdown
.ant-picker-cell-in-view.ant-picker-cell-range-start
.ant-picker-cell-inner,
:where(.css-dev-only-do-not-override-1fviqcj).ant-picker-dropdown
.ant-picker-cell-in-view.ant-picker-cell-range-end
.ant-picker-cell-inner {
color: #fff;
background: #901d77;
}
.ant-picker-dropdown .ant-picker-today-btn {
color: var(--DEFAULT_SELECTED_COLOR);
}
.ant-checkbox .ant-checkbox-inner {
box-sizing: border-box;
position: relative;
top: 0;
inset-inline-start: 0;
display: block;
width: 16px;
height: 16px;
direction: ltr;
background-color: #ffffff;
border: 1px solid #000;
border-radius: 4px;
border-collapse: separate;
transition: all 0.3s;
}
.ant-checkbox-checked .ant-checkbox-inner {
background-color: #000;
border-color: #000;
}
.ant-pagination .ant-pagination-item-active {
font-weight: 600;
background-color: #ffffff;
border-color: #000000;
}
.ant-pagination .ant-pagination-item-active a {
color: #000000;
}
.ant-table-wrapper .ant-table-thead > tr > th,
.ant-table-wrapper .ant-table-thead > tr > td {
position: relative;
font-weight: 600;
text-align: start;
font-size: 12px;
color: rgb(118, 118, 118);
background: #fafafa;
border-bottom: 1px solid #f0f0f0;
}
.ant-checkbox-wrapper:not(.ant-checkbox-wrapper-disabled):hover
.ant-checkbox-checked:not(.ant-checkbox-disabled)
.ant-checkbox-inner {
background-color: #000000;
border-color: transparent;
}
.ant-checkbox-wrapper:not(.ant-checkbox-wrapper-disabled):hover
.ant-checkbox-inner,
:where(.css-dev-only-do-not-override-1fviqcj).ant-checkbox:not(
.ant-checkbox-disabled
):hover
.ant-checkbox-inner {
border-color: #000000;
}
.ant-switch.ant-switch-checked {
background: var(--SELECTED_COLOR);
}
.ant-switch.ant-switch-checked:hover:not(.ant-switch-disabled) {
background: var(--SELECTED_COLOR);
}
.ant-table-wrapper .ant-table-thead > tr > th,
.ant-table-wrapper .ant-table-thead > tr > td {
position: relative;
color: rgba(64, 64, 64, 0.88);
font-weight: 600;
text-transform: uppercase;
text-align: start;
background: none;
border-bottom: 1px solid #f0f0f0;
font-family: var(--HEADING_FONT_FAMILY);
transition: background 0.2s ease;
transition-duration: 0.6s;
}
.ant-table-wrapper .ant-table {
box-sizing: border-box;
margin: 0;
padding: 0;
color: rgb(14 14 14 / 88%);
font-size: 14px;
line-height: 1.5714285714285714;
list-style: none;
font-family: var(--HEADING_FONT_FAMILY);
background: none;
background-color: rgba(255, 255, 255, 0.036);
border-radius: 5px;
transition-duration: 0.6s;
}
.ant-table-wrapper table {
width: 100%;
text-align: start;
border-radius: 8px 8px 0 0;
border-collapse: separate;
border-spacing: 0;
}
.ant-table-wrapper .ant-table:hover {
box-sizing: border-box;
margin: 0;
padding: 0;
color: rgb(14 14 14 / 88%);
font-size: 14px;
line-height: 1.5714285714;
list-style: none;
border-radius: 8px 8px 0 0;
transition-duration: 0.6s;
}
.ant-table-cell-row-hover {
font-size: 14px;
font-weight: 600;
transition-duration: 0.6s;
}
.ant-table-wrapper .ant-table-pagination-right {
justify-content: flex-start;
}
.ant-pagination .ant-pagination-item {
display: inline-block;
min-width: 32px;
height: 32px;
margin-inline-end: 8px;
font-family:
-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue',
Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji',
'Segoe UI Symbol', 'Noto Color Emoji';
line-height: 30px;
text-align: center;
vertical-align: middle;
list-style: none;
background-color: white;
border-radius: 6px;
outline: 0;
cursor: pointer;
user-select: none;
}
.ant-menu .ant-menu-item .ant-menu-item-icon,
.ant-menu .ant-menu-submenu-title .ant-menu-item-icon,
:where(.css-dev-only-do-not-override-1fviqcj).ant-menu .ant-menu-item .anticon,
:where(.css-dev-only-do-not-override-1fviqcj).ant-menu
.ant-menu-submenu-title
.anticon {
min-width: 14px;
font-size: 20px;
position: relative;
top: 13px;
transition:
font-size 0.2s cubic-bezier(0.215, 0.61, 0.355, 1),
margin 0.3s cubic-bezier(0.645, 0.045, 0.355, 1),
color 0.3s;
}
:where(.css-2i2tap).ant-menu-vertical
> .ant-menu-submenu
> .ant-menu-submenu-title {
align-items: center;
}
:where(.css-zg0ahe).ant-menu-vertical
> .ant-menu-submenu
> .ant-menu-submenu-title {
align-items: center;
}
.ant-menu-light,
.ant-menu-light > .ant-menu {
color: rgba(0, 0, 0, 0.88);
background: none;
//dhana
// padding: 1vw 0vh;
//
}
.ant-form-item .ant-form-item-explain-error {
color: var(--ERROR_COLOR);
position: relative;
}
.ant-table-cell {
background: #fafafa7a;
//vicky
padding: 1px 8px !important;
}
.ant-input-affix-wrapper > input.ant-input {
font-size: inherit;
border: none;
border-radius: 0;
outline: none;
transition-duration: 0.6s;
}
.ant-input-affix-wrapper:not(.ant-input-affix-wrapper-disabled):hover {
border-color: #4096ff;
border-inline-end-width: 1px;
background-color: none;
z-index: 0;
transition-duration: 0.6s;
}
.ant-input-affix-wrapper {
position: relative;
display: inline-flex;
width: 100%;
min-width: 0;
color: rgba(0, 0, 0, 0.88);
height: 50px;
line-height: 1.5714285714285714;
background-color: #ffffff;
background-image: none;
border-width: 1px;
border-style: solid;
border-color: #acacac;
border-radius: 6px;
font-size: 16px;
transition: all 0.2s;
}
.ant-input-affix-wrapper > input.ant-input {
font-size: inherit;
border: none;
border-radius: 0;
outline: none;
}
.ant-input-affix-wrapper > input.ant-input {
font-size: inherit;
border: none;
padding: 23px 2px;
padding-top: 1rem;
border-radius: 0;
outline: none;
}
.ant-upload-drag-icon {
color: #000;
}
.ant-upload-text {
font-family: var(--HEADING_FONT_FAMILY);
}
.ant-upload-hint {
font-family: var(--PARA_FONT_FAMILY);
}
.ant-upload-wrapper .ant-upload-drag p.ant-upload-drag-icon .anticon {
color: #6a6a6a;
font-size: 48px;
}
.ant-table table {
border-spacing: 0 10px;
transition-duration: 0.6s;
}
.ant-table-wrapper .ant-table-tbody > tr.ant-table-row > td,
.ant-table-wrapper
.ant-table-tbody
> tr
> th.ant-table-cell-row
> td.ant-table-cell-row {
background: #ffffff8e;
box-shadow: rgba(100, 100, 111, 0.018) 0px 7px 29px 0px;
}
.ant-table-wrapper .ant-table-tbody > tr.ant-table-row:hover > td,
.ant-table-wrapper
.ant-table-tbody
> tr
> th.ant-table-cell-row-hover
> td.ant-table-cell-row-hover {
background: rgb(224, 223, 223);
font-size: 15px;
transition-duration: 0.6s;
// transform: translateY(-8px);
}
.ant-modal .ant-modal-content {
position: relative;
background-color: #ffffff;
background-clip: padding-box;
border: 0;
font-family: var(--HEADING_FONT_FAMILY);
border-radius: 8px;
box-shadow:
0 6px 16px 0 rgba(0, 0, 0, 0.08),
0 3px 6px -4px rgba(0, 0, 0, 0.12),
0 9px 28px 8px rgba(0, 0, 0, 0.05);
pointer-events: auto;
padding: 24px 24px;
color: #000;
max-height: 98vh;
overflow: auto;
}
.ant-modal-title {
font-size: 24px !important;
text-wrap: wrap;
font-family: 'Gilroy', sans-serif;
}
.ant-modal-footer {
position: relative;
display: flex;
justify-content: flex-end;
}
.ant-modal-root .ant-modal-mask {
backdrop-filter: blur(10px);
}
.ant-pagination .ant-pagination-next {
font-family: Arial, Helvetica, sans-serif;
outline: 1;
background-color: #fff;
}
.ant-pagination .ant-pagination-prev,
.ant-pagination .ant-pagination-next {
font-family: Arial, Helvetica, sans-serif;
background-color: #fff;
}
.ant-pagination .ant-pagination-item {
min-width: 32px;
height: 32px;
margin-inline-end: 8px;
font-family:
-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue',
Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji',
'Segoe UI Symbol', 'Noto Color Emoji';
line-height: 30px;
text-align: center;
vertical-align: middle;
list-style: none;
background-color: white;
border-radius: 6px;
outline: 0;
cursor: pointer;
user-select: none;
}
.ant-pagination
.ant-pagination-jump-next
.ant-pagination-item-container
.ant-pagination-item-ellipsis {
position: absolute;
top: 0;
inset-inline-end: 0;
bottom: 0;
inset-inline-start: 0;
margin: auto;
color: rgba(0, 0, 0, 0.25);
font-family: Arial, Helvetica, sans-serif;
letter-spacing: 2px;
text-align: center;
text-indent: 0.13em;
opacity: 1;
transition: all 0.2s;
}
.ant-pagination
.ant-pagination-jump-next
.ant-pagination-item-container
.ant-pagination-item-link-icon {
color: var(--ERROR_COLOR);
font-size: 12px;
opacity: 0;
transition: all 0.2s;
display: none;
}
.ant-select-single.ant-select-show-arrow .ant-select-selection-item,
.ant-select-single.ant-select-show-arrow .ant-select-selection-placeholder {
padding-inline-end: 18px;
text-align: initial;
}
.ant-select-single.ant-select-show-arrow .ant-select-selection-item,
.ant-select-single.ant-select-show-arrow .ant-select-selection-placeholder {
padding-inline-end: 59px;
text-align: initial;
font-size: 14px;
color: #626262;
font-weight: 400;
font-family: 'Poppins', sans-serif;
padding-top: 16px;
}
.ant-select .ant-select-arrow {
display: flex;
align-items: center;
color: rgba(0, 0, 0, 0.517);
font-style: normal;
line-height: 1;
text-align: center;
text-transform: none;
vertical-align: -0.125em;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
position: absolute;
top: 50%;
inset-inline-start: auto;
inset-inline-end: 11px;
height: 110p;
margin-top: -6px;
font-size: 16px;
pointer-events: none;
}
.ant-select:not(.ant-select-customize-input)
.ant-select-selector
.ant-select-selection-search-input {
padding: 0;
border: none;
height: 20px;
font-size: 16px;
position: relative;
bottom: 0.5rem;
appearance: none;
}
.ant-table-wrapper .ant-table-column-sorter {
margin-inline-start: 4px;
color: rgba(0, 0, 0, 0.29);
font-size: 0;
transition: color 0.3s;
}
.ant-input:disabled {
color: #000;
}
.ant-form-item-row
.ant-form-item-control
.ant-form-item-control-input
.ant-form-item-control-input-content
.ant-input-textarea-affix-wrapper {
height: 100%;
}
.ant-input-search-button {
display: none;
}
.ant-input-search {
width: var(--INPUT_FIELD_WIDTH) !important;
}
.searchDiv .ant-input {
padding: 0.25rem 0.5rem;
border-radius: 0.25rem !important;
width: 100%;
height: 45px;
font-size: 14px;
}
.radio-buttons {
display: flex;
justify-content: center;
align-items: center;
}
.download-link {
background: none;
border: none;
color: #1292ee;
cursor: pointer;
button {
border: none;
background-color: #dadadaff;
padding: 10px 16px;
width: max-content;
cursor: pointer;
gap: 4px;
align-items: flex-start;
display: flex;
border-radius: 8px;
opacity: 1;
}
span {
font-family: 'Poppins';
font-size: 14px;
font-weight: 400;
}
}
.configMsrMainDiv {
display: flex;
flex-direction: column;
column-gap: 1rem;
flex-wrap: wrap;
}
.configMsrSubDiv {
display: flex;
flex-direction: row;
gap: 1rem;
flex-wrap: wrap;
}
.configMsrSubDiv .ant-form-item .ant-form-item-explain-error {
position: relative;
left: 1rem;
top: 1rem;
}
.shape-crop {
display: flex;
flex-wrap: wrap;
flex-direction: column;
gap: 1rem;
}
.shape-crop-subdiv {
display: flex;
flex-wrap: wrap;
flex-direction: row;
gap: 2.5rem;
}
.shape-crop-div {
display: flex;
flex-wrap: wrap;
flex-direction: row;
gap: 1rem;
}
.shape-reset {
font-size: 25px;
color: var(--SELECTED_COLOR);
}
.shape-preview {
font-size: 25px;
color: var(--DEFAULT_SELECTED_COLOR);
}
.shape-delete {
font-size: 25px;
color: var(--ERROR_COLOR);
}
.crop-icon {
font-size: 20px;
// color: var(--DEFAULT_SELECTED_COLOR);
}
.crop-button {
display: flex;
flex-direction: row;
gap: 0.5rem;
width: 110px;
background-color: var(--DEFAULT_SELECTED_COLOR);
font-size: 14px;
color: white;
border-radius: 5px;
padding: 6px 2px 1px 10px;
font-weight: 400;
}
.viewerExcelupload {
.ant-table-wrapper .ant-table-pagination.ant-pagination {
position: sticky;
bottom: 0;
z-index: 10;
background: white;
padding-top: 10px;
}
}
.formSearch {
.ant-input-affix-wrapper {
height: 42px !important;
}
.searchDiv .ant-input {
height: unset !important;
}
}
// writed by sree lowStock animated
.stock-alert-animation {
// position: relative;
animation: blink 1s infinite;
cursor: pointer;
}
@keyframes blink {
0% { opacity: 1; }
50% { opacity: 0; }
100% { opacity: 1; }
}

View File

@ -0,0 +1,28 @@
import { TertiaryButton as TertiaryButtonLibrary } from "../../../ownLib/my-ui-lib"
const TertiaryButton = TertiaryButtonLibrary
export default TertiaryButton;
// import { Button } from 'antd';
// import './main.scss';
// const TertiaryButton = ({
// buttonText,
// handleSubmit,
// icon,
// htmlType,
// disabled,
// }) => (
// <Button
// type="primary"
// className="tertiary_Button"
// onClick={handleSubmit}
// htmlType={htmlType ? 'submit' : ''}
// disabled={disabled ? disabled : false}
// >
// {buttonText}
// {icon}
// </Button>
// );
// export default TertiaryButton;

View File

@ -0,0 +1,57 @@
// import React from 'react';
// import './Loader.scss';
// import {Loader as LoaderLibrary} from "../../../ownLib/my-ui-lib"
// const Loader = LoaderLibrary
// export default Loader;
// import React from 'react';
// import './Loader.scss';
// const Loader = () => {
// const text = 'POZO';
// return (
// <div className="modern-loader-wrapper">
// <div className="modern-balls-loader">
// {text.split('').map((char, i) => (
// <span className="modern-ball" key={i} style={{ animationDelay: `${i * 0.18}s` }}>{char}</span>
// ))}
// </div>
// <div className="modern-progress-bar">
// <div className="modern-progress-fill"></div>
// </div>
// </div>
// );
// };
// export default Loader;
import React from 'react';
import './Loader.scss';
const Loader = () => {
return (
<div className="LoaderMainPozo">
<div className="card11">
<div className="loader11">
<p>Loading</p>
<div className="words">
<span className="word">PozoApp</span>
<span className="word">BillingApp</span>
<span className="word">PozoApp</span>
<span className="word">BillingApp</span>
<span className="word">PozoApp</span>
</div>
<p></p>
</div>
</div>
<div className="progress-container11">
<div className="progress-bar11">
<div className="progress-fill11"></div>
</div>
</div>
</div>
);
};
export default Loader;

View File

@ -0,0 +1,109 @@
.LoaderMainPozo {
display: flex;
align-content: center;
justify-content: center;
height: 100%;
width: 100%;
flex-direction: column;
}
.card11 {
background-color: var(--bg-color);
border-radius: 1.25rem;
}
.loader11 {
color: rgb(66, 66, 66);
font-family: "Gilroy", sans-serif;
font-weight: 400;
font-size: 25px;
-webkit-box-sizing: content-box;
box-sizing: content-box;
height: 40px;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
border-radius: 8px;
letter-spacing: -0.5px;
justify-content: center;
}
.words {
overflow: hidden;
position: relative;
letter-spacing: -0.3px;
}
.words::after {
content: "";
position: absolute;
inset: 0;
background: linear-gradient(var(--bg-color) 10%, transparent 30%, transparent 70%, var(--bg-color) 90%);
z-index: 20;
}
.word {
display: block;
height: 100%;
padding-left: 6px;
color: #52c41a;
animation: spin_4991 4s infinite;
}
@keyframes spin_4991 {
10% {
-webkit-transform: translateY(-102%);
transform: translateY(-102%);
}
25% {
-webkit-transform: translateY(-100%);
transform: translateY(-100%);
}
50% {
-webkit-transform: translateY(-200%);
transform: translateY(-200%);
}
75% {
-webkit-transform: translateY(-300%);
transform: translateY(-300%);
}
100% {
-webkit-transform: translateY(-400%);
transform: translateY(-400%);
}
}
.progress-container11 {
width: 200px;
margin: 4px auto;
}
.progress-bar11 {
width: 100%;
height: 2px;
background: rgb(136 131 131 / 20%);
border-radius: 3px;
overflow: hidden;
}
.progress-fill11 {
height: 100%;
background: linear-gradient(90deg, #52c41a, #52c41a);
border-radius: 3px;
animation: progress 2s ease-in-out infinite;
}
@keyframes progress {
0% {
width: 0%;
transform: translateX(-100%);
}
50% {
width: 100%;
transform: translateX(0%);
}
100% {
width: 100%;
transform: translateX(100%);
}
}

View File

@ -0,0 +1,46 @@
import * as React from 'react';
import './style.css';
import loadgif from '../../Images/spin3.gif';
const styles = {
text: {
marginTop: 52,
color: '#888',
marginLeft: 6,
},
spinner: {
backgroundColor: 'rgba(255, 255, 255, 0.5)',
width: '100%',
height: '100%',
top: 0,
left: 0,
zIndex: 99999999999999999,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
},
};
export const Loader = ({
loading,
text = 'Loading..',
fullPage,
containerStyle,
textStyle,
}) => {
if (!loading) {
return null;
}
const mergedContainerStyle = {
...styles.spinner,
...containerStyle,
position: fullPage ? 'fixed' : 'absolute',
};
return (
<div style={mergedContainerStyle}>
<div>
<img src={loadgif} className="loadgif" />
</div>
</div>
);
};

View File

@ -0,0 +1,26 @@
@keyframes react-overlay-loader-spinner {
to {
transform: rotate(360deg);
}
}
.react-overlay-loader-spinner:before {
content: '';
box-sizing: border-box;
position: absolute;
top: 50%;
left: 50%;
width: 40px;
height: 40px;
margin-top: -30px;
margin-left: -20px;
border-radius: 50%;
border: 3px solid #eee;
border-top-color: #07d;
animation: react-overlay-loader-spinner 0.8s linear infinite;
}
.loadgif {
width: 570px;
height: 320px;
}

View File

@ -0,0 +1,89 @@
import React, { Component } from 'react';
import { Map, Marker, GoogleApiWrapper } from 'google-maps-react';
class MapView extends Component {
constructor(props) {
super(props);
this.state = {
fields: props.prevlca ? { location: props.prevlca } : { location: {} },
currentLocation: props.prevlca ? props.prevlca : false,
};
}
async componentDidMount() {
if (Object.keys(this.state.fields.location)?.length === 0) {
const { lat, lng } = await this.getcurrentLocation();
this.setState((prev) => ({
fields: {
...prev.fields,
location: {
lat,
lng,
},
},
currentLocation: {
lat,
lng,
},
}));
}
}
getcurrentLocation() {
if (navigator && navigator.geolocation) {
return new Promise((resolve, reject) => {
navigator.geolocation.getCurrentPosition((pos) => {
const coords = pos.coords;
resolve({
lat: coords.latitude,
lng: coords.longitude,
});
});
});
}
return {
lat: 0.0,
lng: 0,
};
}
addMarker = (location, map) => {
this.setState({
fields: { location: { lat: location.lat(), lng: location.lng() } },
});
map.panTo(location);
this.props.onMarkerClick(location);
};
render() {
const { lat = 0, lng = 0 } = this.state.fields.location;
// var bounds = new this.props.google.maps.LatLngBounds();
return (
<div>
<Map
google={this.props.google}
style={{
width: '100%',
height: '100%',
}}
initialCenter={{ lat: lat || 0, lng: lng || 0 }}
center={{ lat: lat || 0, lng: lng || 0 }}
zoom={14}
mapTypeId="roadmap"
onClick={(t, map, c) => {
this.addMarker(c.latLng, map);
}}
// bounds={bounds}
>
<Marker
tooltip={true}
name="Your Position"
position={this.state.fields.location}
onClick={this.props.onMarkerClick}
/>
</Map>
</div>
);
}
}
export default GoogleApiWrapper({
apiKey: 'AIzaSyB6w_WDy6psJ5HPX15Me1-o6CkS5jTYWnE',
})(MapView);

View File

@ -0,0 +1,432 @@
import React, { useState, useRef, useEffect } from 'react';
import { AppstoreOutlined, MailOutlined, SettingOutlined, } from '@ant-design/icons';
import { FaCaretRight } from "react-icons/fa";
import './PozoMenu.scss';
const PozoMenu = ({ items = [], mode = "vertical", style = {}, onClick, collapse = false, selectedKey: propSelectedKey, isBottomMenu = false }) => {
const [openKeys, setOpenKeys] = useState([]);
const [selectedKey, setSelectedKey] = useState('');
const [dropdownPositions, setDropdownPositions] = useState({});
console.log(dropdownPositions, "dropdownPositions")
const [isMobile, setIsMobile] = useState(window.innerWidth <= 768);
const menuRef = useRef();
// Update selected key when prop changes
useEffect(() => {
if (propSelectedKey !== undefined) {
setSelectedKey(propSelectedKey);
}
}, [propSelectedKey]);
// Close dropdown when clicking outside, window resize, or scroll
useEffect(() => {
const handleClickOutside = (event) => {
if (menuRef.current && !menuRef.current.contains(event.target)) {
setOpenKeys([]);
setDropdownPositions({});
}
};
const handleResize = () => {
// Update mobile detection
setIsMobile(window.innerWidth <= 768);
// Recalculate positions on window resize
if (openKeys.length > 0) {
setOpenKeys([]);
setDropdownPositions({});
}
};
const handleScroll = () => {
// 🎯 FIXED: Recalculate positions on scroll to maintain proper positioning
if (openKeys.length > 0) {
// Find all currently open menu elements and recalculate their positions
const newPositions = {};
openKeys.forEach(key => {
const element = document.querySelector(`[data-menu-key="${key}"]`);
if (element) {
const level = key.split('-').length - 1;
newPositions[key] = calculatePosition(element, level);
}
});
setDropdownPositions(prev => ({ ...prev, ...newPositions }));
}
};
document.addEventListener('mousedown', handleClickOutside);
window.addEventListener('resize', handleResize);
window.addEventListener('scroll', handleScroll, true); // Capture scroll events
return () => {
document.removeEventListener('mousedown', handleClickOutside);
window.removeEventListener('resize', handleResize);
window.removeEventListener('scroll', handleScroll, true);
};
}, [openKeys]);
// 🎯 FIXED: Smart positioning calculation - exactly like your image behavior
const calculatePosition = (element, level = 0) => {
const rect = element.getBoundingClientRect();
const viewportWidth = window.innerWidth;
const viewportHeight = window.innerHeight;
const scrollX = window.pageXOffset || document.documentElement.scrollLeft;
const scrollY = window.pageYOffset || document.documentElement.scrollTop;
// Dynamic dropdown dimensions - responsive
const dropdownWidth = isMobile
? Math.min(280, viewportWidth - 20)
: (level > 0 ? 220 : 250);
const dropdownHeight = Math.min(
isMobile ? viewportHeight * 0.5 : 400,
viewportHeight * 0.6
);
const gap = isMobile ? 2 : 4;
const edgePadding = isMobile ? 10 : 8;
// Calculate available space on both sides
const spaceRight = viewportWidth - rect.right;
const spaceLeft = rect.left;
const spaceNeeded = dropdownWidth + gap + edgePadding;
let position = {
top: rect.top + scrollY,
left: rect.right + gap + scrollX,
direction: 'right',
verticalDirection: 'down'
};
// 🎯 FIXED: HORIZONTAL POSITIONING - Exactly like your images
if (level === 0) {
console.log('🎯 Space Analysis:', {
spaceRight,
spaceLeft,
spaceNeeded,
elementPosition: { left: rect.left, right: rect.right }
});
if (spaceRight >= spaceNeeded) {
// Image 1: Enough space on right - open to RIGHT
position.left = rect.right + gap + scrollX;
position.direction = 'right';
console.log('✅ Opening RIGHT - space available');
} else if (spaceLeft >= spaceNeeded) {
// Image 2: No space on right, space on left - open to LEFT
position.left = rect.left - dropdownWidth - gap + scrollX;
position.direction = 'left';
console.log('✅ Opening LEFT - no space on right');
} else {
// Edge case: Limited space on both sides
if (spaceRight >= spaceLeft) {
position.left = viewportWidth - dropdownWidth - edgePadding + scrollX;
position.direction = 'right-edge';
} else {
position.left = edgePadding + scrollX;
position.direction = 'left-edge';
}
console.log('⚠️ Edge positioning applied');
}
} else {
// Nested menu positioning
const parentKeys = Object.keys(dropdownPositions);
const parentDirection = parentKeys.length > 0
? dropdownPositions[parentKeys[level - 1]]?.direction || 'right'
: 'right';
if (parentDirection.includes('right')) {
if (spaceRight >= spaceNeeded) {
position.left = rect.right + gap + scrollX;
position.direction = 'right';
} else {
position.left = rect.left - dropdownWidth - gap + scrollX;
position.direction = 'left';
}
} else {
if (spaceLeft >= spaceNeeded) {
position.left = rect.left - dropdownWidth - gap + scrollX;
position.direction = 'left';
} else {
position.left = rect.right + gap + scrollX;
position.direction = 'right';
}
}
}
// 🎯 FIXED: VERTICAL POSITIONING
const spaceBelow = viewportHeight - rect.bottom;
const spaceAbove = rect.top;
if (isBottomMenu && level === 0) {
if (spaceAbove >= dropdownHeight + edgePadding) {
position.top = rect.top - dropdownHeight - gap + scrollY;
position.verticalDirection = 'up';
} else {
position.top = rect.bottom + gap + scrollY;
position.verticalDirection = 'down';
}
} else {
if (spaceBelow >= dropdownHeight + edgePadding) {
position.top = rect.top + scrollY;
position.verticalDirection = 'down';
} else if (spaceAbove >= dropdownHeight + edgePadding) {
position.top = rect.bottom - dropdownHeight + scrollY;
position.verticalDirection = 'up';
} else {
position.top = Math.max(edgePadding, (viewportHeight - dropdownHeight) / 2) + scrollY;
position.verticalDirection = 'center';
}
}
// 🎯 FIXED: Final boundary checks
position.left = Math.max(
edgePadding + scrollX,
Math.min(position.left, viewportWidth - dropdownWidth - edgePadding + scrollX)
);
position.top = Math.max(
edgePadding + scrollY,
Math.min(position.top, viewportHeight - dropdownHeight - edgePadding + scrollY)
);
// Store dimensions for reference
position.width = dropdownWidth;
position.height = dropdownHeight;
console.log('🎯 FIXED Position:', {
clicked: { top: rect.top, left: rect.left, right: rect.right, bottom: rect.bottom },
spaces: { right: spaceRight, left: spaceLeft, above: spaceAbove, below: spaceBelow },
calculated: position,
direction: position.direction
});
return position;
};
// Handle menu item click
const handleMenuClick = (item, event, parentKeys = []) => {
event.stopPropagation();
if (item.children && item.children.length > 0) {
// Has children - toggle submenu
const itemKey = item.key;
const isOpen = openKeys.includes(itemKey);
if (isOpen) {
// Close this submenu and all its children
setOpenKeys(prev => prev.filter(key => {
// Keep only keys that are not this item or its descendants
return !key.startsWith(itemKey) && key !== itemKey;
}));
setDropdownPositions(prev => {
const newPos = { ...prev };
Object.keys(newPos).forEach(key => {
if (key.startsWith(itemKey) || key === itemKey) {
delete newPos[key];
}
});
return newPos;
});
} else {
// Close all submenus at the same level or deeper
const currentPath = [...parentKeys, itemKey];
const newOpenKeys = openKeys.filter(key => {
// Keep only parent keys in the current path
return currentPath.some(pathKey => key === pathKey) ||
currentPath.every((pathKey, index) => {
const keyParts = key.split('-');
const pathParts = pathKey.split('-');
return index < keyParts.length && keyParts[index] === pathParts[index];
});
});
// Add current item to open keys
newOpenKeys.push(itemKey);
// Calculate position and add to dropdown positions
const position = calculatePosition(event.currentTarget, parentKeys.length);
console.log('🎯 Setting position for', itemKey, ':', position);
setDropdownPositions(prev => {
// Remove positions for closed items
const newPos = {};
newOpenKeys.forEach(key => {
if (prev[key]) newPos[key] = prev[key];
});
newPos[itemKey] = position;
console.log('🎯 Updated dropdown positions:', newPos);
return newPos;
});
setOpenKeys(newOpenKeys);
}
} else {
// No children - select item and close all dropdowns
setSelectedKey(item.key);
setOpenKeys([]);
setDropdownPositions({});
// Trigger onClick callback if provided
if (onClick) {
onClick({
key: item.key,
keyPath: [...parentKeys, item.key],
item: item,
domEvent: event
});
}
console.log('Menu item clicked:', {
key: item.key,
keyPath: [...parentKeys, item.key],
label: item.label
});
}
};
// Check if item is selected
const isSelected = (key) => selectedKey === key;
// Check if item is open
const isOpen = (key) => openKeys.includes(key);
// Check if item is in active path (has selected child)
const isInActivePath = (item, parentKeys = []) => {
if (!item.children) return false;
const checkChildren = (children, currentPath) => {
return children.some(child => {
const childPath = [...currentPath, child.key];
if (child.key === selectedKey) return true;
if (child.children) {
return checkChildren(child.children, childPath);
}
return false;
});
};
return checkChildren(item.children, [...parentKeys, item.key]);
};
const menuRefs = useRef({});
const submenuRefs = useRef({});
const [positions, setPositions] = useState({});
const renderMenuItems = (items, parentKeys = [], level = 0) => {
return items.map((item) => {
if (!item) return null;
const hasChildren = item.children && item.children.length > 0;
const isItemSelected = isSelected(item.key);
const isItemOpen = isOpen(item.key);
const isItemInActivePath = isInActivePath(item, parentKeys);
const currentKeys = [...parentKeys, item.key];
return (
<div
key={item.key}
className="pozo-menu-item-wrapper"
ref={(el) => {
if (el) menuRefs.current[item.key] = el;
}}
>
<div
className={`pozo-menu-item ${isItemSelected ? 'selected' : ''} ${isItemOpen ? 'open' : ''} ${isItemInActivePath ? 'active-path' : ''} ${hasChildren ? 'has-children' : ''} ${item.type === 'group' ? 'group-item' : ''}`}
onClick={(e) => handleMenuClick(item, e, parentKeys)}
data-menu-key={item.key}
style={{ justifyContent: "flex-start" }}
>
{item.icon && (
<span className="pozo-menu-icon" style={{ fontSize: collapse ? "1.3rem" : "" }}>
{item.icon}
</span>
)}
{!collapse && <span className="pozo-menu-label">{item.label}</span>}
{hasChildren && !collapse && (
// <span className="pozo-menu-arrow"><FaCaretRight /></span>
<span className={`${isItemOpen ? "open " : ""}pozo-menu-arrow`}>
<FaCaretRight />
</span>
)}
</div>
{hasChildren && isItemOpen && !collapse && (
<div
ref={(el) => {
if (el) submenuRefs.current[item.key] = el;
}}
className={`pozo-dropdown-submenu ${level > 0 ? 'nested-submenu' : ''}`}
style={{
position: 'fixed',
top: (() => {
const defaultTop = positions[item.key]?.top || 0;
const submenuHeight =
submenuRefs.current[item.key]?.getBoundingClientRect()?.height || 0;
const screenHeight = window.innerHeight;
// ✅ If submenu would overflow screen bottom, adjust top
if (defaultTop + submenuHeight > screenHeight) {
return Math.max(
8, // padding from top
screenHeight - submenuHeight - 8
);
}
return defaultTop;
})(),
left: positions[item.key]?.left + 5 || 0,
// width: 220,
width: 200,
maxHeight: 400,
zIndex: 1000 + level
}}
>
<div className="pozo-submenu-content">
{renderMenuItems(item.children, currentKeys, level + 1)}
</div>
</div>
)}
</div>
);
});
};
// ✅ Compute positions after render
useEffect(() => {
const updated = {};
for (const [key, el] of Object.entries(menuRefs.current)) {
if (el && typeof el.getBoundingClientRect === "function") {
const rect = el.getBoundingClientRect();
updated[key] = {
top: rect.top + window.scrollY,
left: rect.right + window.scrollX
};
}
}
Object.entries(submenuRefs.current).forEach(([key, el]) => {
if (el) {
const height = el.getBoundingClientRect().height;
console.log(`Total submenu height for ${key}:`, height);
}
});
setPositions(updated);
}, [items, openKeys]);
console.log(submenuRefs, "menuRef")
return (
<div
className={`pozo-menu pozo-menu-${mode}`}
style={style}
>
<div className="pozo-menu-content" ref={menuRef}>
{renderMenuItems(items)}
</div>
</div>
);
};
export default PozoMenu;

View File

@ -0,0 +1,452 @@
// PozoMenu Component Styles - Integrated with SideMenuPozo
.pozo-menu {
font-family: "Poppins", sans-serif !important;
background: transparent;
border-radius: 0;
box-shadow: none;
// overflow: hidden;
overflow: auto;
user-select: none;
@media (max-width: 500px) {
overflow: scroll;
}
&.pozo-menu-vertical {
width: 100% !important;
min-height: auto;
}
&.pozo-menu-horizontal {
width: 100%;
display: flex;
flex-direction: row;
}
}
.pozo-menu-content {
padding: 0;
display: flex;
flex-direction: column;
gap: 0.1rem;
}
.pozo-menu-item-wrapper {
position: relative;
}
.pozo-menu-item {
display: flex;
align-items: center;
justify-content: center;
padding: 8px 8px;
cursor: pointer;
transition:
background 0.2s,
color 0.2s;
border-radius: 8px;
margin: 1px 3px;
font-size: 13px;
font-weight: 500;
color: #ffffff;
position: relative;
min-height: 38px;
font-family: "Poppins", sans-serif !important;
&:hover:not(.selected):not(.active-path) {
background: #394588;
}
&.selected {
background: #050d36 !important;
color: #ffffff !important;
border-right: 3px solid #ffffff;
font-weight: 600;
border-radius: 6px;
border: none !important;
.pozo-menu-icon {
color: #23bbff !important;
}
.pozo-menu-label {
color: #ffffff !important;
}
.pozo-menu-arrow {
color: #ffffff !important;
}
}
&.open {
background: #050d36 !important;
color: #23bbff;
font-weight: 600;
width: 95%;
}
&.active-path {
background: #050d36 !important;
color: #ffffff !important;
font-weight: 600;
border-radius: 6px 4px 4px 6px;
border-right: 2px solid #23bbff !important;
.pozo-menu-icon {
color: #ffffff !important;
}
.pozo-menu-label {
color: #ffffff !important;
font-weight: 500 !important;
}
.pozo-menu-arrow {
color: #ffffff !important;
}
}
&.has-children {
&:after {
content: "";
position: absolute;
right: 16px;
top: 50%;
transform: translateY(-50%);
width: 0;
height: 0;
}
}
&.group-item {
font-weight: 600;
color: #666;
font-size: 12px;
text-transform: uppercase;
letter-spacing: 0.5px;
padding: 8px 16px;
background: #fafafa;
margin: 4px 8px;
&:hover {
background: #fafafa;
color: #666;
cursor: default;
}
}
}
.pozo-menu-icon {
margin-right: 0.3rem;
font-size: 1.3rem;
min-width: 24px;
display: flex;
justify-content: center;
align-items: center;
@media (max-width: 500px) {
font-size: 1rem !important;
margin-right: 0;
}
}
.pozo-menu-label {
flex: 1;
color: #ffffff;
font-size: 12px;
font-weight: 400;
word-break: break-word;
line-height: 1.2;
font-family: "Poppins", sans-serif !important;
}
.pozo-menu-arrow {
margin-left: auto;
font-size: 12px;
display: flex;
align-items: center;
transition: transform 0.2s ease;
color: #999;
}
@media (max-width: 768px) {
.open.pozo-menu-arrow {
transform: rotate(90deg);
}
}
// Dropdown Submenu Styles - SideMenuPozo Style
.pozo-dropdown-submenu {
position: fixed !important;
background: #23378a;
border-radius: 12px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
border: none;
min-width: 200px;
max-width: 300px;
max-height: 54vh;
overflow-y: auto;
animation: dropdownFadeIn 0.2s ease;
scrollbar-width: thin;
z-index: 1050 !important;
// Ensure no transform interference
transform: none !important;
margin: 0 !important;
&.nested-submenu {
background: #23378a;
border-radius: 10px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
padding: 0.2rem 0 0.5rem 0;
width: 200px;
z-index: 10001 !important;
margin-left: -3px !important;
@media (max-width: 768px) {
background-color: #040716;
}
}
&::-webkit-scrollbar {
width: 6px;
}
&::-webkit-scrollbar-track {
background: #f1f1f1;
border-radius: 3px;
}
&::-webkit-scrollbar-thumb {
background: #c1c1c1;
border-radius: 3px;
}
&::-webkit-scrollbar-thumb:hover {
background: #a8a8a8;
}
}
.pozo-submenu-content {
padding: 0.2rem 0 0.5rem 0;
.pozo-menu-item {
margin: 1px 8px;
padding: 0.5rem 0.7rem;
font-size: 1rem;
font-weight: 500;
border-radius: 6px;
background: transparent;
transition:
background 0.18s,
color 0.18s;
&:hover:not(.selected):not(.active-path) {
background: #394588;
color: #182147;
font-weight: 600;
}
&.selected {
background: #050d36 !important;
color: #ffffff !important;
font-weight: 600;
border-radius: 6px;
border-left: 3px solid #ffffff;
.pozo-menu-icon {
color: #ffffff !important;
}
.pozo-menu-label {
color: #ffffff !important;
}
.pozo-menu-arrow {
color: #ffffff !important;
}
}
&.active-path {
background: #050d36 !important;
color: #ffffff !important;
font-weight: 600;
border-radius: 6px;
.pozo-menu-icon {
color: #23bbff !important;
}
.pozo-menu-label {
color: #ffffff !important;
}
.pozo-menu-arrow {
color: #ffffff !important;
}
}
&.group-item {
background: transparent;
border-bottom: none;
margin: 0;
border-radius: 6px;
&:hover {
background: transparent;
color: #fff;
}
}
}
}
// Inline Submenu Styles
.pozo-inline-submenu {
background: #fafafa;
border-left: 2px solid #e8e8e8;
margin-left: 20px;
border-radius: 0 6px 6px 0;
.pozo-menu-item {
margin: 1px 4px;
padding: 8px 12px;
font-size: 13px;
background: transparent;
&:hover {
background: #f0f8ff;
}
&.selected {
background: #e6f7ff;
border-left: 2px solid #1890ff;
}
}
}
// Animation
@keyframes dropdownFadeIn {
from {
opacity: 0;
transform: translateY(-10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
// Bottom menu positioning
.bottom-menu {
.pozo-dropdown-submenu {
// Remove transform for bottom menu - use calculated position
transform: none !important;
margin-top: 0 !important;
}
}
// Responsive Design
@media (max-width: 900px) {
// .pozo-dropdown-submenu {
// // left: 70px !important;
// // min-width: 180px;
// // max-width: calc(100vw - 80px);
// }
// .pozo-dropdown-submenu.nested-submenu {
// // left: 70px !important;
// }
.bottom-menu .pozo-dropdown-submenu {
left: 70px !important;
}
}
@media (max-width: 768px) {
.pozo-menu {
&.pozo-menu-vertical {
width: 100%;
}
}
.pozo-dropdown-submenu {
// min-width: 160px;
// max-width: calc(50vw - 20px);
// left: 30% !important;
// right: 10px !important;
position: unset !important;
width: 100% !important;
min-width: unset !important;
max-width: unset !important;
background-color: #050d36c4;
// border-top: 1px solid #23bbff;
margin-top: 2px !important;
}
.pozo-menu-item {
padding: 10px 8px;
font-size: 15px;
margin: 1px 3px !important;
}
}
@media (max-width: 500px) {
.pozo-menu-item {
// padding: 8px 8px;
padding: 6px 4px 6px 6px;
font-size: 15px;
}
.pozo-menu-label {
font-size: 11px !important;
margin-top: 2px;
}
}
// Dark Theme Support
.pozo-menu.dark-theme {
background: #001529;
color: #fff;
.pozo-menu-item {
color: #ffffffd9;
&:hover {
background: #1890ff;
color: #fff;
}
&.selected {
background: #1890ff;
color: #fff;
border-left-color: #fff;
}
&.group-item {
background: #002140;
color: rgba(255, 255, 255, 0.65);
}
}
.pozo-dropdown-submenu {
background: #001529;
border-color: #303030;
}
.pozo-inline-submenu {
background: #002140;
border-left-color: #303030;
}
}
// High Contrast Mode
@media (prefers-contrast: high) {
.pozo-menu-item {
border: 1px solid transparent;
&:hover {
border-color: #1890ff;
}
&.selected {
border-color: #1890ff;
border-width: 2px;
}
}
}

View File

@ -0,0 +1,275 @@
import { useContext, useEffect, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { useDispatch } from 'react-redux';
import { Menu } from 'antd';
import {
changePreviewComponents,
changeSelectedPrintdummyData,
getTemplate,
} from '../../Features/ThemeChange/ThemeChange';
import {
changeBookingType,
changeOrderCardDetails,
changeReorderHoldDetails,
changeProductCategorie,
changeCustomerID,
changeSelectedCustId,
changeSelectedOption,
ChangeOverAllDiscSales,
ChangeOverAllDiscEstimate,
changeSummeryTotalAmount,
changeSearchedData,
changeBtoBQuickProductTransfer,
changeTipAmount,
changeCommonPaymentOptions,
GlobalDineinDefault,
} from '../../Features/BookingScreen/BookingData/BookingData';
import {
changeWholeSaleAuctionSelectedData,
changeWholeSaleGradeListData,
} from '../../Features/WholeSale/WholesaleData';
import { GiHamburgerMenu } from 'react-icons/gi';
import './sideMenu.scss';
import { getSession } from '../../Services/Others';
import { ChangeTotalAmount } from '../../Features/ExteraCharges/ExtraCharges';
import * as Offer from '../../Features/Offer/Offer';
import { AuthContext } from '../../AuthContext';
import { useSelector } from 'react-redux';
const subDirectory = import.meta.env.BASE_URL;
export const getItem = (label, key, icon, children, ariaExpanded = false) => {
return {
key,
icon,
children,
label,
};
};
export const getsubItem = (
label,
key,
icon,
children,
ariaExpanded = false
) => {
return {
key,
icon,
children,
label,
};
};
const SideMenu = ({ mode, theme, items }) => {
const { freeProductsCount, setFreeProductsCount } = useContext(AuthContext);
const [collapsed, setCollapsed] = useState(true);
const [width, setWidth] = useState(window.innerWidth);
const [openKeys, setOpenKeys] = useState([]);
const [clickedKeys, setClickedKeys] = useState([]);
const dispatch = useDispatch();
const navigate = useNavigate();
const CompId = getSession('CompId');
const BranchId = getSession('BranchId');
const AppId = getSession('AppId');
const DineinDefault = useSelector(GlobalDineinDefault);
const handleMouseEnter = (e) => {
const key = e.key;
if (!openKeys.includes(key)) {
setOpenKeys((prev) => [...prev, key]);
}
};
const handleMouseLeave = (e) => {
const key = e.key;
// Only remove the key if it wasn't clicked
if (!clickedKeys.includes(key)) {
setOpenKeys((prev) => prev.filter((k) => k !== key));
}
};
const handleSubMenuClick = ({ key }) => {
// Toggle clicked state
setClickedKeys((prev) => {
if (prev.includes(key)) {
// If already clicked, remove it and close the menu
setOpenKeys((openKeys) => openKeys.filter((k) => k !== key));
return prev.filter((k) => k !== key);
}
// If not clicked, add it and keep menu open
return [...prev, key];
});
};
const handleMenuItemClick = (e) => {
if(DineinDefault&& e.key == `${subDirectory}sales` ){
navigatefun(`${subDirectory}sales/dine-in`);
// setOpenKeys([]);
}else{
navigatefun(e.key);
}
};
const handleClickOutside = (e) => {
if (!e.target.closest('.ant-menu')) {
setOpenKeys([]);
setClickedKeys([]);
}
};
useEffect(() => {
document.addEventListener('click', handleClickOutside);
return () => {
document.removeEventListener('click', handleClickOutside);
};
}, []);
const navigatefun = async (e) => {
try {
dispatch(changePreviewComponents({}));
dispatch(changeSelectedPrintdummyData(false));
dispatch(changeWholeSaleGradeListData([]));
dispatch(changeWholeSaleAuctionSelectedData([]));
dispatch(changeCommonPaymentOptions([]));
dispatch(
changeBtoBQuickProductTransfer({
action: false,
selectedProducts: [],
})
);
if (e == `${subDirectory}sales/dine-in`) {
dispatch(changeTipAmount(0));
dispatch(changeBookingType('Dine In'));
dispatch(changeOrderCardDetails([]));
dispatch(changeReorderHoldDetails({}));
dispatch(changeProductCategorie(null));
dispatch(changeCustomerID(null));
dispatch(changeSelectedCustId(null));
dispatch(changeSelectedOption(null));
dispatch(ChangeOverAllDiscSales(0));
dispatch(ChangeOverAllDiscEstimate(0));
dispatch(Offer.changeSalesWiseOfferAmount(0));
dispatch(Offer.changeOverallOfferAmount(0));
dispatch(changeSummeryTotalAmount(0));
dispatch(Offer.changeOrderOfferDetail([]));
// await dispatch(Offer.changeFreeProductCount(0));
setFreeProductsCount(0);
dispatch(Offer.changeloyaltyPointsDiscountAmount(0));
dispatch(ChangeTotalAmount([]));
}
if (e == `${subDirectory}sales`) {
// await dispatch(getTemplate({ CompId, BranchId, AppId })).unwrap();
dispatch(changeTipAmount(0));
dispatch(changeSearchedData(''));
dispatch(changeBookingType('TakeAway'));
dispatch(changeOrderCardDetails([]));
dispatch(changeReorderHoldDetails({}));
dispatch(changeProductCategorie(null));
dispatch(changeCustomerID(null));
dispatch(changeSelectedCustId(null));
dispatch(changeSelectedOption(null));
dispatch(ChangeOverAllDiscSales(0));
dispatch(ChangeOverAllDiscEstimate(0));
dispatch(Offer.changeSalesWiseOfferAmount(0));
dispatch(Offer.changeOverallOfferAmount(0));
dispatch(changeSummeryTotalAmount(0));
dispatch(Offer.changeOrderOfferDetail([]));
// dispatch(Offer.changeFreeProductCount(0));
setFreeProductsCount(0);
dispatch(Offer.changeloyaltyPointsDiscountAmount(0));
dispatch(Offer.changeCoupenCodeAmount(0));
dispatch(ChangeTotalAmount([]));
}
if (e == `${subDirectory}saleslayouts/print-selection`) {
dispatch(changeSelectedPrintdummyData(true));
}
// if(e==`${subDirectory}kiosksales`){
// const elem = document.documentElement;
// if (elem.requestFullscreen) {
// elem.requestFullscreen();
// } else if (elem.mozRequestFullScreen) { // Firefox
// elem.mozRequestFullScreen();
// } else if (elem.webkitRequestFullscreen) { // Chrome, Safari and Opera
// elem.webkitRequestFullscreen();
// } else if (elem.msRequestFullscreen) { // IE/Edge
// elem.msRequestFullscreen();
// }
// }else{
// if (document.exitFullscreen) {
// document.exitFullscreen();
// } else if (document.mozCancelFullScreen) { // Firefox
// document.mozCancelFullScreen();
// } else if (document.webkitExitFullscreen) { // Chrome, Safari and Opera
// document.webkitExitFullscreen();
// } else if (document.msExitFullscreen) { // IE/Edge
// document.msExitFullscreen();
// }
// }
navigate(e);
} catch (error) {
console.error('Navigation failed:', error);
}
};
const toggleCollapsed = () => {
setCollapsed(!collapsed);
};
useEffect(() => {
function handleResize() {
setWidth(window.innerWidth);
}
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, [width]);
useEffect(() => {
width < 768 && setCollapsed(true);
width > 768 && setCollapsed(false);
}, [width < 768]);
return (
<>
<div style={{ display: 'flex', justifyContent: 'center' }}>
<button
onClick={toggleCollapsed}
style={{
position: 'fixed',
top: '5px',
border: 'none',
}}
>
{collapsed ? (
<GiHamburgerMenu />
) : (
<GiHamburgerMenu style={{ fontSize: '20px' }} />
)}
</button>
</div>
<div style={{ display: 'flex', justifyContent: 'center' }}>
{/* <img className="sidebarlogo" src={Logo} style={{width:"2rem",}} alt="" /> */}
<p className="sidebarlogo">POZO</p>
</div>
<Menu
className={collapsed ? 'sideMenuantd2' : 'sideMenuantd'}
defaultSelectedKeys={['1']}
openKeys={openKeys}
onOpenChange={setOpenKeys}
onClick={handleMenuItemClick}
onTitleClick={handleSubMenuClick}
inlineCollapsed={collapsed}
mode={mode}
theme={theme}
items={items}
onMouseEnter={(e) => handleMouseEnter(e)}
onMouseLeave={(e) => handleMouseLeave(e)}
triggerSubMenuAction="click"
/>
</>
);
};
export default SideMenu;

View File

@ -0,0 +1,444 @@
import React, { useState, useEffect, useRef } from 'react';
import { useNavigate, useLocation } from 'react-router-dom';
import { useSelector } from 'react-redux';
import {
FaBars, FaThLarge, FaHome, FaCog, FaChartBar, FaFileAlt,
FaMobileAlt, FaSignOutAlt, FaSignInAlt, FaArrowRight,
FaCaretRight
} from 'react-icons/fa';
import { MdSettings, MdOutlineReport, MdOutlineHome, MdOutlineKeyboardArrowDown, MdOutlineKeyboardArrowRight, } from 'react-icons/md';
import { BiLogOut, BiLogIn } from 'react-icons/bi';
import { AiOutlineAppstore, AiOutlineSetting, AiOutlineBarChart, AiOutlineFileText } from 'react-icons/ai';
import { GiHamburgerMenu } from 'react-icons/gi';
import './SideMenuPozo.scss';
import { FaCaretDown } from "react-icons/fa";
import { useDispatch } from 'react-redux';
import { useContext } from 'react';
import { AuthContext } from '../../AuthContext';
import PozoMenu from './PozoMenu';
import { getSession } from '../../Services/Others';
import {
changePreviewComponents,
changeSelectedPrintdummyData,
getTemplate,
} from '../../Features/ThemeChange/ThemeChange';
import {
changeBookingType,
changeOrderCardDetails,
changeReorderHoldDetails,
changeProductCategorie,
changeCustomerID,
changeSelectedCustId,
changeSelectedOption,
ChangeOverAllDiscSales,
ChangeOverAllDiscEstimate,
changeSummeryTotalAmount,
changeSearchedData,
changeBtoBQuickProductTransfer,
changeTipAmount,
GlobalDineinDefault,
} from '../../Features/BookingScreen/BookingData/BookingData';
import {
changeWholeSaleAuctionSelectedData,
changeWholeSaleGradeListData,
} from '../../Features/WholeSale/WholesaleData';
import { ChangeTotalAmount } from '../../Features/ExteraCharges/ExtraCharges';
import * as Offer from '../../Features/Offer/Offer';
import { FiMenu } from 'react-icons/fi';
import POZOMIND from "../../Images/PozomindWLogo.png";
import { ChangeFullFreeProductList, changeFullOfferAppliedProducts, changeLoyaltyConsumedQuantities } from '../../Features/Offer/Offernew/BookingOffernew';
const subDirectory = import.meta.env.BASE_URL;
// Filter functions (copied from AppPage.jsx)
function filterMenuItems(menu, configList) {
if (!Array.isArray(menu)) return [];
return menu.filter((item) => {
if (!item) return false;
if (item.label === "Sign Out") return true;
// For nested children, filter recursively
let filteredChildren = item.children ? filterMenuItems(item.children, configList) : undefined;
// Employee access: ConfigName
const config = configList?.find(
(config) => config.ConfigName === item.label && config.ReadAccess === 'Y'
);
// If this item or any of its children are accessible, include it
return (config || (filteredChildren && filteredChildren.length > 0));
}).map(item => ({
...item,
children: item.children ? filterMenuItems(item.children, configList) : undefined
}));
}
function filterSadminUserMenuItems(menu, configList) {
if (!Array.isArray(menu)) return [];
return menu.filter((item) => {
if (!item) return false;
if (item.label === "Sign Out") return true;
let filteredChildren = item.children ? filterSadminUserMenuItems(item.children, configList) : undefined;
// Super admin user access: MenuName
const config = configList?.find(
(config) => config.MenuName === item.label && config.ReadAccess === 'Y'
);
return (config || (filteredChildren && filteredChildren.length > 0));
}).map(item => ({
...item,
children: item.children ? filterSadminUserMenuItems(item.children, configList) : undefined
}));
}
// Capitalize helper
function capitalizeWords(str) {
if (typeof str !== 'string') return '';
return str.replace(/\w\S*/g, (txt) => txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase());
}
// Recursively capitalize all menu item labels, filtering out falsy items and items without a label
function capitalizeMenuLabels(items) {
return (items || [])
.filter(item => item && typeof item.label === 'string' && item.label.trim() !== '')
.map(item => ({
...item,
label: capitalizeWords(item.label),
children: item.children ? capitalizeMenuLabels(item.children) : undefined
}));
}
const SideMenuPozo = ({ items = [] }) => {
const { freeProductsCount, setFreeProductsCount, UserType, Access, SadminuserAccess } = useContext(AuthContext);
const dispatch = useDispatch();
const navigate = useNavigate();
const location = useLocation();
const [openKeys, setOpenKeys] = useState([]);
const [collapsed, setCollapsed] = useState(window.innerWidth < 768);
const [dropdownPosition, setDropdownPosition] = useState({});
const menuRef = useRef();
const CompId = getSession('CompId');
const BranchId = getSession('BranchId');
const AppId = getSession('AppId');
const DineinDefault = useSelector(GlobalDineinDefault);
const [collapse, setCollapse] = useState(false);
useEffect(() => {
const handleResize = () => {
setCollapse(window.innerWidth < 768);
};
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, []);
useEffect(() => {
const handleResize = () => {
setCollapsed(window.innerWidth < 768);
};
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, []);
useEffect(() => {
const handleClickOutside = (e) => {
if (menuRef.current && !menuRef.current.contains(e.target)) {
setOpenKeys([]);
setDropdownPosition({});
}
};
document.addEventListener('mousedown', handleClickOutside);
return () => document.removeEventListener('mousedown', handleClickOutside);
}, []);
useEffect(() => {
const handleClickOutside = (event) => {
if (window.innerWidth < 768) {
if (menuRef.current && !menuRef.current.contains(event.target)) {
setCollapse(true);
}
}
};
document.addEventListener("mousedown", handleClickOutside);
return () => document.removeEventListener("mousedown", handleClickOutside);
}, []);
// Debug current pathname
useEffect(() => {
console.log('Current pathname:', location.pathname);
}, [location.pathname]);
const isSelected = (key) => location.pathname === key;
const isOpen = (key) => openKeys.includes(key);
// Check if any child of this item is selected (for parent menu highlighting)
const hasSelectedChild = (item) => {
if (!item.children) return false;
return item.children.some(child => {
if (child.children) {
return hasSelectedChild(child);
}
return location.pathname === child.key;
});
};
// Check if a dropdown item is currently selected
const isDropdownItemSelected = (item) => {
return location.pathname === item.key;
};
const navigatefun = async (e) => {
dispatch(changePreviewComponents({}));
dispatch(changeSelectedPrintdummyData(false));
dispatch(changeWholeSaleGradeListData([]));
dispatch(changeWholeSaleAuctionSelectedData([]));
dispatch(
changeBtoBQuickProductTransfer({
action: false,
selectedProducts: [],
})
);
if (e == `${subDirectory}sales/dine-in`) {
dispatch(changeTipAmount(0));
dispatch(changeBookingType('Dine In'));
dispatch(changeOrderCardDetails([]));
dispatch(changeReorderHoldDetails({}));
dispatch(changeProductCategorie(null));
dispatch(changeCustomerID(null));
dispatch(changeSelectedCustId(null));
dispatch(changeSelectedOption(null));
dispatch(ChangeOverAllDiscSales(0));
dispatch(ChangeOverAllDiscEstimate(0));
dispatch(Offer.changeSalesWiseOfferAmount(0));
dispatch(Offer.changeOverallOfferAmount(0));
dispatch(changeSummeryTotalAmount(0));
dispatch(Offer.changeOrderOfferDetail([]));
setFreeProductsCount(0);
dispatch(Offer.changeloyaltyPointsDiscountAmount(0));
dispatch(ChangeTotalAmount([]));
dispatch(ChangeFullFreeProductList([]));
dispatch(changeFullOfferAppliedProducts([]));
dispatch(changeLoyaltyConsumedQuantities({}))
}
if (e == `${subDirectory}sales`) {
dispatch(changeTipAmount(0));
dispatch(changeSearchedData(''));
dispatch(changeBookingType('TakeAway'));
dispatch(changeOrderCardDetails([]));
dispatch(changeReorderHoldDetails({}));
dispatch(changeProductCategorie(null));
dispatch(changeCustomerID(null));
dispatch(changeSelectedCustId(null));
dispatch(changeSelectedOption(null));
dispatch(ChangeOverAllDiscSales(0));
dispatch(ChangeOverAllDiscEstimate(0));
dispatch(Offer.changeSalesWiseOfferAmount(0));
dispatch(Offer.changeOverallOfferAmount(0));
dispatch(changeSummeryTotalAmount(0));
dispatch(Offer.changeOrderOfferDetail([]));
setFreeProductsCount(0);
dispatch(Offer.changeloyaltyPointsDiscountAmount(0));
dispatch(Offer.changeCoupenCodeAmount(0));
dispatch(ChangeFullFreeProductList([]));
dispatch(changeFullOfferAppliedProducts([]));
dispatch(ChangeTotalAmount([]));
dispatch(changeLoyaltyConsumedQuantities({}))
}
if (e == `${subDirectory}saleslayouts/print-selection`) {
dispatch(changeSelectedPrintdummyData(true));
}
navigate(e);
};
const handleMenuClick = (item, parentKeys = [], event, level = 0) => {
if (item.children) {
if (openKeys.includes(item.key)) {
setOpenKeys(openKeys.filter(k => k !== item.key));
const newPositions = { ...dropdownPosition };
delete newPositions[item.key];
setDropdownPosition(newPositions);
} else {
// For top level (level 0), close all other open menus
// For nested levels, keep parent chain but close siblings
let newOpenKeys;
if (level === 0) {
// Close all other top-level menus
newOpenKeys = [];
} else {
// Keep only the parent chain, remove siblings
newOpenKeys = openKeys.filter(key => {
// Keep if it's in the parent chain
return parentKeys.includes(key);
});
}
// Calculate position for dropdown
const rect = event.currentTarget.getBoundingClientRect();
let position;
if (level === 0) {
position = {
top: rect.top,
left: collapsed ? rect.right + 1 : 10
};
} else {
position = {
top: rect.top,
left: rect.right + 1
};
}
setDropdownPosition(prev => ({ ...prev, [item.key]: position }));
setOpenKeys([...newOpenKeys, item.key]);
}
} else {
if (DineinDefault && item.key == `${subDirectory}sales`) {
navigatefun(`${subDirectory}sales/dine-in`);
setOpenKeys([]);
}
else {
navigatefun(item.key);
setOpenKeys([]);
}
}
};
console.log(items, Access, "Employee items")
// Filter menu items based on access
let filteredMenuItems = (items || []).filter(Boolean);
if (UserType === 'Employee' && Array.isArray(Access) && Access.length > 0) {
filteredMenuItems = filterMenuItems(filteredMenuItems, Access);
} else if (UserType === 'Super Admin User' && Array.isArray(SadminuserAccess) && SadminuserAccess.length > 0) {
filteredMenuItems = filterSadminUserMenuItems(filteredMenuItems, SadminuserAccess);
}
// Capitalize all labels, filter out items without a label
const menuItemsWithCapitalizedLabels = capitalizeMenuLabels(filteredMenuItems);
const bottomKeys = ['Support', 'Settings', 'Download', 'Sign Out'];
const bottomMenuItems = menuItemsWithCapitalizedLabels.filter(item =>
bottomKeys.includes(item.label)
);
const mainMenuItems = menuItemsWithCapitalizedLabels.filter(item =>
!bottomKeys.includes(item.label)
);
// Recursive render for menu and submenus
const renderMenuItems = (items, parentKeys = [], level = 0) => (
<div className={`side-menu-list${level > 0 ? ' nested-list' : ''}`}>
{(items || []).filter(Boolean).map((item) => (
<div key={item.key}>
<div
className={`${level > 0 ? 'dropdown-submenu-item' : 'menu-item'}${isSelected(item.key) || (level === 0 && hasSelectedChild(item)) ? ' selecteded' : ''}${isOpen(item.key) ? ' open' : ''}${item.children ? ' has-children' : ''}`}
onClick={(e) => { e.stopPropagation(); handleMenuClick(item, parentKeys, e, level); }}
// style={{ paddingLeft: `${level * 10 + 1}px` }}
>
{item.icon && level === 0 && <span className='menu-icon' style={{
fontSize: collapse ? "1.5rem" : ""
}}>{item.icon}</span>}
{!collapse && <span className='menu-label'>{item.label}</span>}
{!collapse && <span className='menu-labelDot'>{isDropdownItemSelected(item) ? '●' : ''}</span>}
{item.children && !collapse && (
<span className='menu-arrow'>
{level === 0 ? <FaCaretRight size={14} /> : <MdOutlineKeyboardArrowRight />}
</span>
)}
</div>
{item.children && isOpen(item.key) && !collapse && (
<div
className={`dropdown-submenu${level > 0 ? ' nested' : ''}`}
>
{renderMenuItems(item.children, [...parentKeys, item.key], level + 1)}
</div>
)}
</div>
))}
</div>
);
// Custom onClick handler for PozoMenu
const handlePozoMenuClick = (e) => {
console.log('PozoMenu clicked:', e);
navigatefun(e.key);
};
// Get current selected key based on location
const getCurrentSelectedKey = () => {
return location.pathname;
};
const isMobile = /Mobi|Android|iPhone|iPad|iPod/i.test(navigator.userAgent);
const isAndroid = /Android/i.test(navigator.userAgent);
return (
<div className={`SideMenuPozo-Master${collapse ? ' collapsed' : ''}`} ref={menuRef}
style={{ height: isMobile ? "88%" : "" }}
>
<div style={{
width: "100%", display: "flex", flexDirection: "column", gap: "10px",
height: "68vh", overflow: "auto"
}}>
<div className="paypreLogoDiv">
<div className="shopNameNav" style={{ width: "100%" }}>
<div style={{
display: "flex", flexDirection: "row",
alignItems: "center", gap: "4px", padding: "0px 10px", justifyContent: "space-between"
}}>
<FiMenu
size={26}
onClick={() => setCollapse((prev) => !prev)}
style={{ cursor: 'pointer' }}
/>
{collapse ? "" :
// <img src={POZOMIND} alt="PozoMindLogo" width="80px" height={"45px"} className='PozoMindLogo' />
<div>
PozoApp
</div>
}
</div>
{/* <div> */}
{/* <div>{branchName}</div> */}
<p>{/* {'Palacode'} , {'Tamilnadu'} , {'India'} */}</p>
{/* </div> */}
</div>
</div>
{/* Top Menu using PozoMenu */}
<div className='top-menu'>
<PozoMenu
items={mainMenuItems}
mode="vertical"
collapse={collapse}
selectedKey={getCurrentSelectedKey()}
style={{
width: collapse ? '60px' : '200px',
background: 'transparent',
boxShadow: 'none'
}}
onClick={handlePozoMenuClick}
/>
</div>
</div>
{/* Bottom Menu using PozoMenu */}
<div className='bottom-menu' style={{
height: isMobile ? "30vh" : ""
}}>
<PozoMenu
items={bottomMenuItems}
mode="vertical"
collapse={collapse}
selectedKey={getCurrentSelectedKey()}
isBottomMenu={true}
style={{
width: collapse ? '60px' : '200px',
background: 'transparent',
boxShadow: 'none'
}}
onClick={handlePozoMenuClick}
/>
</div>
</div>
);
};
export default SideMenuPozo;

View File

@ -0,0 +1,408 @@
.SideMenuPozo-Master {
// width: 12vw;
// width: 200px;
width: 160px;
height: 100vh;
overflow: hidden;
background-color: #23378a;
padding: 0rem 3px 0 0px;
transition: width 0.2s;
font-family: 'Poppins', sans-serif !important;
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: space-between;
@media (max-width: 500px) {
width: 150px;
overflow: auto;
// padding-bottom: 3rem;
// position: fixed;
left: 0;
top: 0;
height: 100vh !important;
z-index: 10000;
}
@media (max-width: 768px) {
overflow: auto;
}
}
.SideMenuPozo-Master.collapsed {
width: 45px;
min-width: 45px;
position: unset;
@media (max-width: 500px) {
width: 9vw;
}
}
.side-menu-header {
display: flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 1.5rem;
}
.hamburger-btn {
background: none;
border: none;
color: #fff;
font-size: 1.5rem;
cursor: pointer;
margin-right: 0.5rem;
}
.side-menu-logo {
color: #fff;
font-weight: 700;
font-size: 1.2rem;
letter-spacing: 2px;
}
.side-menu {
display: flex;
flex-direction: column;
gap: 1rem;
}
.menu-item {
color: #fff;
padding: 10px 8px;
border-radius: 8px;
cursor: pointer;
font-size: 1rem;
transition:
background 0.2s,
color 0.2s;
position: relative;
display: flex;
align-items: center;
min-height: 38px;
font-family: 'Poppins', sans-serif !important;
@media (max-width: 500px) {
flex-direction: column;
}
}
.menu-item.selecteded,
.menu-item.open {
// background: #25306a;
background: #050d36;
color: #23bbff;
border-right: 2px solid #23bbff;
font-weight: 600;
}
.menu-item:hover {
background: #394588;
}
.menu-icon {
margin-right: 0.3rem;
font-size: 1.3rem;
min-width: 24px;
display: flex;
justify-content: center;
}
.menu-label {
flex: 1;
color: #ffffff;
font-size: 13px;
font-weight: 500;
word-break: break-word;
max-width: 140px;
line-height: 1.2;
font-family: 'Poppins', sans-serif !important;
@media (max-width: 500px) {
font-size: 8px !important;
margin-top: 2px;
}
}
.side-menu-wrapper {
display: flex;
flex-direction: column;
height: 95vh; // Full screen height
overflow: hidden;
}
.side-menu {
display: flex;
flex-direction: column;
height: 100%;
}
.top-menu {
// flex: 1 1 auto;
overflow: hidden; // Prevent scroll
display: flex;
flex-direction: column;
width: 100%;
}
.bottom-menu {
flex-shrink: 0;
padding: 10px 0;
width: 100%;
// height: 32vh;
max-height: 30vh;
overflow: auto;
// padding-bottom: 5rem;
}
.menu-arrow {
margin-left: auto;
font-size: 1.2rem;
display: flex;
align-items: center;
}
.submenu {
margin-left: 2.2rem;
display: flex;
flex-direction: column;
gap: 0.3rem;
}
.submenu-item {
color: #fff;
padding: 0.5rem 0.7rem;
border-radius: 6px;
font-size: 0.95rem;
cursor: pointer;
transition: background 0.2s;
}
.submenu-item:hover {
background: #2e397a;
}
.floating-submenu {
display: none !important;
}
.floating-submenu-item {
display: none !important;
}
.reports-parent {
position: relative;
}
// Dropdown submenu styles
.dropdown-submenu {
// position: fixed;
position: absolute;
margin-top: -2rem;
width: 200px;
background: #23378a;
color: #fff;
border-radius: 12px 12px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
// padding: 0.2rem 0 0.5rem 0;
z-index: 9999;
display: flex;
flex-direction: column;
gap: 0.2rem;
opacity: 1;
transform: translateY(0);
transition:
max-height 0.2s ease,
opacity 0.2s;
animation: dropdown-fade-in 0.2s;
// max-height: 350px;
// overflow: auto;
// left: 202px;
left: 12.7rem;
top: auto;
bottom: auto;
}
@keyframes dropdown-fade-in {
from {
opacity: 0;
transform: translateY(-10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.dropdown-submenu.nested {
background: #23378a;
border-radius: 10px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
padding: 0.2rem 0 0.5rem 0;
// position: fixed !important;
width: 200px;
z-index: 10000;
left: 12.7rem;
}
.side-menu-list.nested-list {
padding-left: 0;
height: max-content;
max-height: 54vh;
overflow: auto;
scrollbar-width: thin;
}
.side-menu-list {
margin: 3px 3px;
overflow: auto;
display: flex;
flex-direction: column;
gap: 0.1rem;
}
.dropdown-submenu-item {
color: #fff;
padding: 0.5rem 0.7rem;
border-radius: 6px;
font-size: 1rem;
font-weight: 500;
cursor: pointer;
display: flex;
align-items: center;
justify-content: flex-start;
transition:
background 0.18s,
color 0.18s;
background: transparent;
}
.dropdown-submenu-item:hover {
background: #394588;
color: #182147;
font-weight: 600;
}
.dropdown-submenu-item .open {
background: #050d36;
color: #182147;
font-weight: 600;
border-radius: 10px;
border-left: 3px solid #23bbff;
}
.dropdown-submenu-item.selecteded {
background: #050d36;
color: #182147;
font-weight: 600;
border-radius: 10px;
}
.dropdown-submenu-item.selecteded {
border-left: 3px solid #394588;
position: relative;
}
// .dropdown-submenu-item.selecteded::after {
// content: '';
// position: absolute;
// right: 8px;
// top: 50%;
// transform: translateY(-50%);
// width: 6px;
// height: 6px;
// background: #23bbff;
// border-radius: 50%;
// }
.menu-item.has-children {
position: relative;
}
@media (max-width: 900px) {
.dropdown-submenu {
left: 70px;
}
}
.bottom-menu {
.side-menu-list.nested-list {
max-height: 85vh;
}
.dropdown-submenu {
bottom: 8px;
}
}
.menu-labelDot {
position: absolute;
right: 15px;
color: #23bbff;
font-size: 14px;
}
.menu-item.open.has-children,
.dropdown-submenu-item.open.has-children {
background-color: #050d36 !important;
border-right: 2px solid #23bbff;
}
.menu-item.selecteded,
.dropdown-submenu-item.selecteded {
background-color: #050d36 !important;
color: #fff !important;
}
.shopNameNav {
display: flex;
flex-direction: row;
align-items: center;
text-transform: capitalize;
gap: 0;
gap: 10px;
div {
font-size: 18px;
font-weight: 500;
display: flex;
align-items: center;
gap: 12px;
@media (max-width: 499px) {
font-size: 14px !important;
svg {
width: 20px;
}
}
}
div:nth-child(2) {
font-size: 22px;
font-weight: 500;
display: unset;
font-family: "Poppins";
letter-spacing: -1.2px;
}
p {
font-size: 10px;
font-weight: 400;
letter-spacing: 0.3px;
@media (max-width: 499px) {
font-size: 7px !important;
}
}
img {
padding-right: 1rem;
@media (max-width: 499px) {
width: 100px;
}
}
}

View File

@ -0,0 +1,196 @@
.ant-menu-title-content {
flex-direction: column;
display: flex;
// shifayath
// align-items: center;
//
font-size: 12px;
}
.ant-menu-vertical > .ant-menu-submenu > .ant-menu-submenu-title {
height: 57px;
line-height: 35px;
font-size: 12px;
font-weight: 600;
display: flex;
flex-direction: column;
// align-items: center;
row-gap: 0.5rem;
}
@media (max-width: 500px) {
.sideNaveParent {
// width: 16vw;
position: relative;
z-index: 100;
}
}
.sideNaveParent .ant-menu-submenu > .ant-menu-submenu-title {
height: 57px;
line-height: 35px;
font-size: 12px;
font-weight: 600;
display: flex;
flex-direction: column;
align-items: center;
row-gap: 0.5rem;
padding-inline-end: 15px;
}
.ant-menu-vertical > .ant-menu-submenu > .ant-menu-submenu-title:hover {
font-size: 12px;
font-weight: 600;
color: var(--PRIMARY_BUTTON_BG_COLOR) !important;
}
:where(.css-dev-only-do-not-override-2i2tap).ant-menu-vertical
> .ant-menu-submenu
> .ant-menu-submenu-title {
align-items: center;
}
:where(.css-2i2tap).ant-menu-vertical
> .ant-menu-submenu
> .ant-menu-submenu-title {
align-items: center;
}
.ant-menu-vertical > .ant-menu-item {
// line-height: 35px;
line-height: 30px;
font-size: 12px;
font-weight: 600;
// height: 70px;
// height: 57px;
height: 50px;
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
row-gap: 0.5rem;
margin-inline: 0px;
margin-block: 0px;
}
.ant-menu-vertical > .ant-menu-item:hover {
font-size: 12px;
font-weight: 700;
color: var(--PRIMARY_BUTTON_BG_COLOR) !important;
}
.ant-menu-light .ant-menu-submenu-selected > .ant-menu-submenu-title,
.ant-menu-light
> .ant-menu
.ant-menu-submenu-selected
> .ant-menu-submenu-title {
color: var(--PRIMARY_BUTTON_BG_COLOR) !important;
}
.ant-menu-light .ant-menu-item-selected,
.ant-menu-light > .ant-menu .ant-menu-item-selected {
color: var(--PRIMARY_BUTTON_BG_COLOR) !important;
}
.ant-menu-light .ant-menu-item-selected,
.ant-menu-light > .ant-menu .ant-menu-item-selected {
color: var(--PRIMARY_BUTTON_BG_COLOR) !important;
}
.ant-menu-light .ant-menu-item-selected,
.ant-menu-light > .ant-menu .ant-menu-item-selected {
background-color: #f4eaf2;
}
.ant-menu .ant-menu-item .ant-menu-item-icon svg {
font-size: 25px;
}
.sideNaveParent .ant-menu .ant-menu-submenu-arrow {
top: 40%;
}
.ant-menu .ant-menu-submenu-title .ant-menu-item-icon svg {
font-size: 25px;
// align-items: center;
}
.ant-menu .ant-menu-item .ant-menu-item-icon + span {
margin-inline-start: 0px;
}
.ant-menu-light,
.ant-menu-light > .ant-menu {
color: rgba(92, 92, 92, 0.88);
background: none;
padding: 2px;
top: 1rem;
justify-content: center;
}
.menuLogos {
fill: #ff4d4f;
background: #ff4d4f;
}
.ant-menu-submenu {
// max-height: 60vh !important;
// june 26
max-height: 56vh !important;
overflow: auto !important;
}
.sideMenuantd {
width: 9vw !important;
height: 100%;
padding: 0px;
padding-inline: 0px;
padding-inline-end: 0px;
padding-left: 0px;
}
.sideMenuantd2 {
width: 5vw !important;
height: 100%;
padding: 0px;
padding-inline: 0px;
padding-inline-end: 0px;
padding-left: 0px;
}
.sidebarlogo {
// margin-bottom: 1rem;
font-weight: 600;
}
@media screen and (max-width: 768px) {
.sideMenuantd {
width: 25vw !important;
height: 100%;
padding: 0px;
padding-inline: 0px;
padding-inline-end: 0px;
padding-left: 0px;
}
.sideMenuantd2 {
width: 10vw !important;
// width: 5rem !important;
height: 100%;
padding: 0px;
padding-inline: 0px;
padding-inline-end: 0px;
padding-left: 0px;
}
.sidebarlogo {
transform: rotate(-90deg);
}
}
@media screen and (max-width: 499px) {
.sideMenuantd2 {
width: 3rem !important;
// width: 5rem !important;
height: 100%;
padding: 0px;
padding-inline: 0px;
padding-inline-end: 0px;
padding-left: 0px;
}
}

View File

@ -0,0 +1,46 @@
import React from 'react';
import { Layout, Menu, theme } from 'antd';
const { Sider } = Layout;
export const SideMenu = ({ items }) => {
items?.map((icon, index) => ({
key: String(index + 1),
icon: React.createElement(
'img',
{ src: icon['menuicon'], height: '200px', width: '300px' },
null
),
label: icon['menuname'],
}));
return (
<Layout hasSider>
<Sider
style={{
overflow: 'auto',
height: '100vh',
position: 'fixed',
left: 0,
top: 0,
bottom: 0,
backgroundColor: '#dbe8f5',
}}
>
<div
style={{
height: 32,
margin: 16,
}}
/>
<Menu
theme="white"
style={{ color: 'black' }}
mode="inline"
defaultSelectedKeys={['4']}
items={items}
/>
</Sider>
</Layout>
);
};

View File

@ -0,0 +1,67 @@
import {DefaultModal as DefaultModalLibrary} from "../../../ownLib/my-ui-lib"
export const DefaultModal = DefaultModalLibrary
// import { useEffect } from 'react';
// import { Modal } from 'antd';
// import Buttons from '../Forms/Buttons';
// import { ArrowRightOutlined, CloseOutlined } from '@ant-design/icons';
// export const DefaultModal = ({
// open,
// title,
// handleCancel,
// children,
// footer,
// handleSubmit,
// width,
// destroyOnClose,
// buttonText,
// maskTransitionName,
// transitionName,
// className,
// }) => {
// // Close modal on pressing 'Escape'
// useEffect(() => {
// const handleKeyDown = (event) => {
// if (event.key === 'Escape' && open) {
// handleCancel();
// }
// };
// window.addEventListener('keydown', handleKeyDown);
// return () => window.removeEventListener('keydown', handleKeyDown);
// }, [open, handleCancel]);
// return (
// <>
// <Modal
// destroyOnClose={destroyOnClose ? destroyOnClose : false}
// open={open}
// title={title}
// top={0}
// width={width ? width : 700}
// maskTransitionName={maskTransitionName}
// transitionName={transitionName}
// className={className}
// centered
// closeIcon={<CloseOutlined onClick={handleCancel} />}
// onCancel={handleCancel} // Handles default close (mask clicks, close icon)
// footer={
// footer
// ? [
// <Buttons
// buttonText={buttonText ? buttonText : 'SUBMIT'}
// color="901D77"
// icon={<ArrowRightOutlined />}
// handleSubmit={handleSubmit}
// >
// {buttonText}
// </Buttons>,
// ]
// : footer
// }
// maskClosable={true} // Ensures clicking outside closes the modal
// >
// {children}
// </Modal>
// </>
// );
// };

View File

@ -0,0 +1,97 @@
import React, { useState } from 'react';
import { Modal, Button } from 'antd';
import { ImportOutlined, ExportOutlined } from '@ant-design/icons';
import * as XLSX from 'xlsx';
import { saveAs } from 'file-saver';
const [excelData, setExcelData] = useState(null);
const [excelFile, setExcelFile] = useState(null);
const [excelFileError, setExcelFileError] = useState(null);
const handleFile = (e) => {
let selectedFile = e.target.files[0];
if (selectedFile) {
if (selectedFile && fileType.includes(selectedFile.type)) {
let reader = new FileReader();
reader.readAsArrayBuffer(selectedFile);
reader.onload = (e) => {
setExcelFileError(null);
setExcelFile(e.target.result);
};
} else {
setExcelFileError('Please select only excel file types');
setExcelFile(null);
}
} else {
console.log('Please select a file');
}
};
const handleSubmit = (e) => {
e.preventDefault();
if (excelFile !== null) {
const workbook = XLSX.read(excelFile, { type: 'buffer' });
const worksheetName = workbook.SheetNames[0];
const worksheet = workbook.Sheets[worksheetName];
const data = XLSX.utils.sheet_to_json(worksheet);
setExcelData(data);
} else {
setExcelData(null);
}
};
const handleExport = () => {
if (excelData !== null) {
const worksheet = XLSX.utils.json_to_sheet(excelData);
const workbook = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(workbook, worksheet, 'Sheet1');
const excelBuffer = XLSX.write(workbook, {
bookType: 'xlsx',
type: 'array',
});
const excelData = new Blob([excelBuffer], {
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
});
saveAs(excelData, 'exported_data.xlsx');
}
};
const Modals = ({ open, title, handleCancel, children, footer }) => {
return (
<Modal
visible={open}
title={title}
onCancel={handleCancel}
footer={
footer
? [
<Button key="submit" type="primary" onClick={handleSubmit}>
Submit
</Button>,
<Button key="cancel" onClick={handleCancel}>
Cancel
</Button>,
]
: footer
}
>
{children}
<div>
<h4>Import Excel</h4>
<input type="file" onChange={handleFile} />
{excelFileError && <div className="error">{excelFileError}</div>}
<Button type="primary" icon={<ImportOutlined />} onClick={handleSubmit}>
Import
</Button>
</div>
<div>
<h4>Export Excel</h4>
<Button type="primary" icon={<ExportOutlined />} onClick={handleExport}>
Export
</Button>
</div>
</Modal>
);
};
export default Modals;

View File

@ -0,0 +1,66 @@
import React from 'react';
import { DefaultModal } from './DefaultModal';
import StockReceived from '../../Pages/StockTransfer/StockReceived';
import Buttons from '../Forms/Buttons';
import { BiPlus } from 'react-icons/bi';
import { ArrowRightOutlined } from '@ant-design/icons';
const ProductDetailsModal = ({
open,
onClose,
productDetails,
headerData,
onDataChange,
onSubmit
}) => {
return (
<DefaultModal
open={open}
title="Product Details"
handleCancel={onClose}
width={800}
footer={false}
>
<div style={{ overflowX: 'auto' }}>
{headerData && (
<div style={{
display: 'flex',
gap: '20px',
marginBottom: '15px',
padding: '10px',
backgroundColor: '#f5f5f5',
borderRadius: '4px'
}}>
<div><strong>Dispatch Id:</strong> <span style={{fontSize:"12px"}}> {headerData.Dispatch_Id} </span> </div>
<div><strong>Date & Time:</strong> <span style={{fontSize:"12px"}}> {headerData.dateTime} </span></div>
<div><strong>From Branch:</strong> <span style={{fontSize:"12px"}}> {headerData.fromBranch} </span> </div>
{/* <div><strong>dispatched By</strong> {headerData.Created_By}</div> */}
</div>
)}
<StockReceived
productDetails={productDetails}
onDataChange={onDataChange}
editable={true}
/>
<div style={{
display: "flex",
alignItems: "center",
paddingTop: "10px",
flexDirection: "row-reverse"
}}>
<Buttons
buttonText={'SUBMIT'}
handleSubmit={onSubmit}
color="901D77"
icon={<ArrowRightOutlined />}
>
OPEN
</Buttons>
</div>
</div>
</DefaultModal>
);
};
export default ProductDetailsModal;

View File

@ -0,0 +1,45 @@
.ReceivedStocksModalMaster {
overflow: auto;
scrollbar-width: thin;
max-height: 70vh;
width: 100%;
.ant-modal .ant-modal-content {
position: relative;
background-color: #fff;
background-clip: padding-box;
border: 0;
font-family: var(--HEADING_FONT_FAMILY);
border-radius: 8px;
box-shadow:
0 6px 16px #00000014,
0 3px 6px -4px #0000001f,
0 9px 28px 8px #0000000d;
pointer-events: auto;
padding: 35px;
color: #000;
}
}
.receive-stocks-modal {
.ant-modal-content {
padding: 24px !important;
}
table {
border-spacing: unset !important;
.ant-table-cell {
font-size: 13px;
font-family: 'Poppins', sans-serif;
}
}
.ant-table
.ant-table-container
.ant-table-content
table
tbody
tr:nth-child(odd):hover
td {
background-color: #cecece49 !important;
font-weight: 400 !important;
}
}

View File

@ -0,0 +1,76 @@
import React from 'react';
import { DefaultModal } from './DefaultModal';
import { Tables } from '../Tables/Table';
import "./ReceivedStockModel.scss"
const ReceivedStocksModal = ({
open,
onClose,
columns,
tableData,
handlePageChange,
customTable = false
}) => {
const renderCell = (column, row, index) => {
if (column.render) {
return column.render(row[column.dataIndex], row, index);
}
return row[column.dataIndex];
};
return (
<DefaultModal
open={open}
title="Receive Stocks"
handleCancel={onClose}
handleSubmit={onClose}
width={900}
footer={false}
className={'receive-stocks-modal'}
>
<>
{!customTable && <div style={{overflowX:"auto"}}>
<Tables
columns={columns}
data={tableData}
dataSource={tableData}
pagination={handlePageChange}
/>
</div>}
{
customTable &&
<div className="ReceivedStocksModalMaster" >
<table style={{ width: "100%" }}>
<thead>
<tr>
{columns.map((column) => (
<th key={column.key} style={{ textAlign: column.align, width: column.width, backgroundColor: '#f0f8ff', fontFamily: "poppins", fontWeight: "450" }}>
{column.title?.toUpperCase()}
</th>
))}
</tr>
</thead>
<tbody>
{tableData.map((row, index) => (
<tr key={row.key || index} style={{ fontSize: "13px" }}>
{columns.map((column) => (
<td key={column.key} style={{ textAlign: column.align, width: column.width }}>
{renderCell(column, row, index)}
</td>
))}
</tr>
))}
</tbody>
</table>
</div>
}
</>
</DefaultModal>
);
};
export default ReceivedStocksModal;

View File

@ -0,0 +1,31 @@
import {Messages as MessagesLibrary} from "../../../ownLib/my-ui-lib"
export const Messages = MessagesLibrary
// import { useEffect } from 'react';
// import { message } from 'antd';
// export const Messages = ({
// messageType,
// messageData,
// duration,
// onComplete,
// }) => {
// const [messageApi, contextHolder] = message.useMessage();
// useEffect(() => {
// if (messageType)
// messageApi
// .open({
// type: messageType,
// content: messageData,
// duration: duration ? duration : 3,
// })
// .then(() => {
// if (onComplete) {
// onComplete();
// }
// });
// }, [messageType]);
// return <>{contextHolder}</>;
// };

View File

@ -0,0 +1,29 @@
import React from "react";
import { FiSend, FiCamera, FiPlus, FiUpload } from "react-icons/fi";
import "./pedalOCR.scss";
const ActionButtons = ({ onOCR, onReset, onAdd, inputMethod }) => {
const isCamera = inputMethod === 'camera';
const handleLeftClick = onAdd || onReset;
return (
<div className="action-buttons">
<button onClick={handleLeftClick} className="action-buttons__btn action-buttons__btn--clear">
{isCamera ? <FiCamera className="action-buttons__icon" /> : <FiUpload className="action-buttons__icon" />}
<span className="action-buttons__text action-buttons__text--mobile">
{isCamera ? 'Scan More' : 'Upload More'}
</span>
<span className="action-buttons__text action-buttons__text--desktop">
{isCamera ? 'Scan More Images' : 'Upload More Images'}
</span>
</button>
<button onClick={onOCR} className="action-buttons__btn action-buttons__btn--process">
<FiSend className="action-buttons__icon" />
<span className="action-buttons__text action-buttons__text--mobile">Process</span>
<span className="action-buttons__text action-buttons__text--desktop">Process Images</span>
</button>
</div>
);
};
export default ActionButtons;

View File

@ -0,0 +1,150 @@
import React, { useState, useEffect, forwardRef, useImperativeHandle } from "react";
import { FiCamera, FiImage, FiUpload } from "react-icons/fi";
const CameraInput = forwardRef(({ fileRef, onFileSelect }, ref) => {
const [isMobile, setIsMobile] = useState(false);
const cameraRef = React.useRef(null);
const fileUploadRef = React.useRef(null);
useEffect(() => {
const checkMobile = () => {
return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
};
setIsMobile(checkMobile());
}, []);
useImperativeHandle(ref, () => ({
openAny: () => {
if (isMobile) {
cameraRef.current && cameraRef.current.click();
} else {
fileRef && fileRef.current && fileRef.current.click();
}
},
openCamera: () => cameraRef.current && cameraRef.current.click(),
openUpload: () => fileUploadRef.current && fileUploadRef.current.click(),
openFileRef: () => fileRef && fileRef.current && fileRef.current.click(),
}));
const buttonStyle = {
padding: "12px 24px",
fontSize: 14,
fontWeight: 500,
cursor: "pointer",
marginTop: 10,
backgroundColor: "#1890ff",
color: "#fff",
border: "none",
borderRadius: 8,
boxShadow: "0 2px 8px rgba(24, 144, 255, 0.3)",
transition: "all 0.3s ease",
display: "flex",
alignItems: "center",
justifyContent: "center",
gap: 8,
width: "100%",
maxWidth: 280,
margin: "10px auto"
};
if (isMobile) {
return (
<>
<input
ref={cameraRef}
type="file"
accept="image/*"
capture="environment"
multiple
hidden
onChange={onFileSelect}
/>
<input
ref={fileUploadRef}
type="file"
accept="image/*"
multiple
hidden
onChange={onFileSelect}
/>
<div style={{ display: "flex", flexDirection: "row", gap: 8, padding: "0 8px" }}>
<button
onClick={() => cameraRef.current.click()}
style={{
...buttonStyle,
backgroundColor: "#52c41a",
fontSize: 12,
padding: "10px 12px",
whiteSpace: "nowrap",
flex: 1
}}
onMouseOver={(e) => {
e.target.style.backgroundColor = "#389e0d";
e.target.style.transform = "translateY(-2px)";
}}
onMouseOut={(e) => {
e.target.style.backgroundColor = "#52c41a";
e.target.style.transform = "translateY(0)";
}}
>
<FiCamera size={16} />
<span>Camera</span>
</button>
<button
onClick={() => fileUploadRef.current.click()}
style={{
...buttonStyle,
fontSize: 12,
padding: "10px 12px",
whiteSpace: "nowrap",
flex: 1
}}
onMouseOver={(e) => {
e.target.style.backgroundColor = "#096dd9";
e.target.style.transform = "translateY(-2px)";
}}
onMouseOut={(e) => {
e.target.style.backgroundColor = "#1890ff";
e.target.style.transform = "translateY(0)";
}}
>
<FiUpload size={16} />
<span>Gallery</span>
</button>
</div>
</>
);
}
return (
<>
<input
ref={fileRef}
type="file"
accept="image/*"
capture="environment"
multiple
hidden
onChange={onFileSelect}
/>
<button
onClick={() => fileRef.current.click()}
style={buttonStyle}
onMouseOver={(e) => {
e.target.style.backgroundColor = "#096dd9";
e.target.style.transform = "translateY(-2px)";
}}
onMouseOut={(e) => {
e.target.style.backgroundColor = "#1890ff";
e.target.style.transform = "translateY(0)";
}}
>
{/* <FiCamera size={20} /> */}
<span style={{ fontFamily: "Poppins", fontWeight: "400" }}>Add Images</span>
<FiImage size={18} />
</button>
</>
);
});
export default CameraInput;

View File

@ -0,0 +1,222 @@
import React, { useState, useRef, useEffect } from "react";
import ReactCrop from "react-image-crop";
import "react-image-crop/dist/ReactCrop.css";
import { FiX, FiScissors } from "react-icons/fi";
const ResizableCropper = ({ imageSrc, onCropComplete, onCancel, onNext, currentIndex, total }) => {
const [crop, setCrop] = useState({ unit: "%", width: 80, height: 100, aspect: 4 / 5 });
const [completedCrop, setCompletedCrop] = useState(null);
const [screenSize, setScreenSize] = useState('desktop');
const imgRef = useRef(null);
useEffect(() => {
const updateScreenSize = () => {
const width = window.innerWidth;
if (width <= 480) setScreenSize('mobile');
else if (width <= 768) setScreenSize('tablet');
else if (width <= 1024) setScreenSize('laptop');
else setScreenSize('desktop');
};
updateScreenSize();
window.addEventListener('resize', updateScreenSize);
return () => window.removeEventListener('resize', updateScreenSize);
}, []);
// Convert crop to base64 image
const getCroppedImage = () => {
if (!imgRef.current || !completedCrop?.width || !completedCrop?.height) return null;
const canvas = document.createElement("canvas");
const scaleX = imgRef.current.naturalWidth / imgRef.current.width;
const scaleY = imgRef.current.naturalHeight / imgRef.current.height;
canvas.width = completedCrop.width * scaleX;
canvas.height = completedCrop.height * scaleY;
const ctx = canvas.getContext("2d");
ctx.drawImage(
imgRef.current,
completedCrop.x * scaleX,
completedCrop.y * scaleY,
completedCrop.width * scaleX,
completedCrop.height * scaleY,
0,
0,
completedCrop.width * scaleX,
completedCrop.height * scaleY
);
return canvas.toDataURL("image/jpeg");
};
const handleNext = () => {
const cropped = getCroppedImage();
if (cropped) onCropComplete(cropped);
if (onNext) onNext();
};
const getResponsiveStyles = () => {
switch (screenSize) {
case 'mobile':
return {
containerPadding: "12px",
imagePadding: 8,
maxHeight: "250px",
buttonPadding: "14px 20px",
fontSize: 13,
iconSize: 16,
gap: 8,
direction: 'row',
borderRadius: 8
};
case 'tablet':
return {
containerPadding: "16px",
imagePadding: 12,
maxHeight: "320px",
buttonPadding: "12px 18px",
fontSize: 13,
iconSize: 16,
gap: 10,
direction: 'row',
borderRadius: 10
};
case 'laptop':
return {
containerPadding: "18px",
imagePadding: 14,
maxHeight: "380px",
buttonPadding: "12px 20px",
fontSize: 14,
iconSize: 16,
gap: 12,
direction: 'row',
borderRadius: 12
};
default:
return {
containerPadding: "20px",
imagePadding: 16,
maxHeight: "400px",
buttonPadding: "12px 20px",
fontSize: 14,
iconSize: 16,
gap: 12,
direction: 'row',
borderRadius: 12
};
}
};
const styles = getResponsiveStyles();
const buttonStyle = {
padding: styles.buttonPadding,
border: "none",
borderRadius: 8,
cursor: "pointer",
fontSize: styles.fontSize,
fontWeight: 500,
transition: "all 0.3s ease",
boxShadow: "0 2px 4px rgba(0,0,0,0.1)",
display: "flex",
alignItems: "center",
gap: 6,
width: screenSize === 'mobile' ? '100%' : 'auto',
justifyContent: 'center',
minHeight: screenSize === 'mobile' ? '48px' : 'auto'
};
return (
<div style={{
textAlign: "center",
marginTop: screenSize === 'mobile' ? 12 : 20,
padding: styles.containerPadding,
backgroundColor: "#f8f9fa",
borderRadius: styles.borderRadius,
margin: screenSize === 'mobile' ? '12px 8px' : '20px auto',
maxWidth: screenSize === 'mobile' ? '100%' : '500px'
}}>
{/* {screenSize !== 'mobile' && (
<div style={{ marginBottom: 16 }}>
<h3 style={{ margin: 0, color: "#333", fontSize: screenSize === 'tablet' ? 16 : 18 }}>
Crop Image {currentIndex + 1} of {total}
</h3>
</div>
)} */}
<div style={{
backgroundColor: "#fff",
padding: styles.imagePadding,
borderRadius: 8,
boxShadow: "0 2px 8px rgba(0,0,0,0.1)",
overflow: 'hidden'
}}>
{screenSize === 'mobile' && (
<div style={{ marginBottom: 8, fontSize: 12, color: "#666" }}>
Image {currentIndex + 1} of {total}
</div>
)}
<ReactCrop
crop={crop}
onChange={(newCrop) => setCrop(newCrop)}
onComplete={(newCrop) => setCompletedCrop(newCrop)}
keepSelection={true}
>
<img
ref={imgRef}
src={imageSrc}
alt="Preview"
style={{
maxWidth: "100%",
maxHeight: styles.maxHeight,
borderRadius: 4,
touchAction: 'none'
}}
/>
</ReactCrop>
</div>
<div style={{
marginTop: screenSize === 'mobile' ? 16 : 20,
display: "flex",
flexDirection: styles.direction,
justifyContent: "center",
gap: styles.gap,
padding: screenSize === 'mobile' ? '0 4px' : '0'
}}>
<button
onClick={onCancel}
style={{
...buttonStyle,
backgroundColor: "#6c757d",
color: "#fff",
fontFamily: "Poppins"
}}
onMouseOver={(e) => e.target.style.backgroundColor = "#5a6268"}
onMouseOut={(e) => e.target.style.backgroundColor = "#6c757d"}
>
<FiX size={styles.iconSize} />
{screenSize === 'mobile' ? 'Cancel' : 'Cancel All'}
</button>
<button
onClick={handleNext}
style={{
...buttonStyle,
backgroundColor: "#1890ff",
color: "#fff",
fontFamily: "Poppins"
}}
onMouseOver={(e) => e.target.style.backgroundColor = "#096dd9"}
onMouseOut={(e) => e.target.style.backgroundColor = "#1890ff"}
>
<FiScissors size={styles.iconSize} />
{screenSize === 'mobile' ? 'Crop' : 'Crop '}
</button>
</div>
</div>
);
};
export default ResizableCropper;

View File

@ -0,0 +1,139 @@
import React, { useState, useRef, useEffect } from "react";
import CameraInput from "./CameraInput";
import ResizableCropper from "./CropperArea";
import ThumbnailsList from "./ThumbnailsList";
import ActionButtons from "./ActionButtons";
import TipsSection from "./TipsSection";
import "./pedalOCR.scss";
const MultiCameraCropOCR = ({ showTips, handleProcessMultipleOCR }) => {
const fileRef = useRef(null);
const cameraInputRef = useRef(null);
const [isMobile, setIsMobile] = useState(false);
const [images, setImages] = useState([]);
const [currentIndex, setCurrentIndex] = useState(null);
const [finalImages, setFinalImages] = useState([]);
console.log(finalImages, "finalImages")
// const [showTips, setShowTips] = useState(false);
const onFileSelect = (e) => {
const files = Array.from(e.target.files);
const newImages = files.map((file, idx) => {
const id = Date.now() + idx;
const reader = new FileReader();
return new Promise((resolve) => {
reader.onload = () => resolve({ id, src: reader.result });
reader.readAsDataURL(file);
});
});
Promise.all(newImages).then((imgs) => {
setImages((prev) => [...prev, ...imgs]);
setCurrentIndex((prev) => (prev === null ? 0 : prev));
});
};
const handleCropComplete = (croppedImage) => {
setFinalImages((prev) => [...prev, croppedImage]);
};
const handleRemoveImage = (index) => {
setFinalImages((prev) => prev.filter((_, i) => i !== index));
};
const handleRecropImage = (index) => {
const imageToRecrop = finalImages[index];
setFinalImages((prev) => prev.filter((_, i) => i !== index));
// Add back to images for re-cropping
const newImage = { id: Date.now(), src: imageToRecrop };
setImages((prev) => [...prev, newImage]);
setCurrentIndex(images.length);
};
const handleSendToOCR = async () => {
if (!finalImages.length) return;
const formDataArray = finalImages.map(base64 => {
const byteString = atob(base64.split(',')[1]);
const ab = new ArrayBuffer(byteString.length);
const ia = new Uint8Array(ab);
for (let i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
const blob = new Blob([ab], { type: 'image/jpeg' });
const formData = new FormData();
formData.append('image', blob, 'cropped.jpg');
return formData;
});
console.log(formDataArray, "formDataArray")
handleProcessMultipleOCR(formDataArray)
resetAll()
};
const resetAll = () => {
setImages([]);
setFinalImages([]);
setCurrentIndex(null);
};
const handleAddMore = () => {
if (cameraInputRef.current && cameraInputRef.current.openAny) {
cameraInputRef.current.openAny();
} else if (fileRef.current) {
fileRef.current.click();
}
};
useEffect(() => {
const checkMobile = () => /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
setIsMobile(checkMobile());
}, []);
return (
<div className="multi-camera-crop-ocr">
<div>
{showTips && <TipsSection />}
</div>
{currentIndex !== null && images[currentIndex] && (
<ResizableCropper
imageSrc={images[currentIndex].src}
currentIndex={currentIndex}
total={images.length}
onCropComplete={handleCropComplete}
onCancel={resetAll}
onNext={() => {
if (currentIndex + 1 < images.length) {
setCurrentIndex(currentIndex + 1);
} else {
setCurrentIndex(null);
setImages([]);
}
}}
/>
)}
{currentIndex === null && (
<>
<CameraInput ref={cameraInputRef} fileRef={fileRef} onFileSelect={onFileSelect} />
</>
)}
{finalImages.length > 0 && currentIndex === null && (
<>
<h4>Cropped Images ({finalImages.length}):</h4>
<ThumbnailsList
images={finalImages}
onRemove={handleRemoveImage}
onRecrop={handleRecropImage}
/>
<ActionButtons onOCR={handleSendToOCR} onAdd={handleAddMore} inputMethod={isMobile ? 'camera' : 'upload'} />
</>
)}
</div>
);
};
export default MultiCameraCropOCR;

View File

@ -0,0 +1,30 @@
import React from 'react';
import './pedalOCR.scss';
const OCRLoader = ({ isVisible, imageCount }) => {
if (!isVisible) return null;
return (
<div className="ocr-loader">
<div className="ocr-loader__content">
<div className="ocr-loader__spinner"></div>
<h3 className="ocr-loader__title">
🔍 Processing Images
</h3>
<p className="ocr-loader__text">
Analyzing {imageCount} image{imageCount > 1 ? 's' : ''}...
</p>
<div className="ocr-loader__dots">
{[1, 2, 3].map((dot) => (
<div key={dot} className={`ocr-loader__dot ocr-loader__dot--${dot}`} />
))}
</div>
</div>
</div>
);
};
export default OCRLoader;

View File

@ -0,0 +1,312 @@
.tips-section {
margin-bottom: 20px;
background-color: #f6ffed;
padding: 16px;
border-radius: 8px;
border: 1px solid #b7eb8f;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
}
.tips-header {
display: flex;
align-items: center;
gap: 8px;
margin-bottom: 12px;
}
.tips-title {
font-size: 14px;
font-weight: 600;
margin: 0;
color: #1890ff;
}
.tips-content {
padding-left: 8px;
}
.tip-item {
display: flex;
align-items: center;
gap: 8px;
margin-bottom: 8px;
font-size: 13px;
color: #555;
}
.tip-verify {
color: #ff4d4f;
font-weight: 600;
}
.tips-section-mobile {
margin-bottom: 12px;
background-color: #f6ffed;
padding: 8px;
border-radius: 6px;
border: 1px solid #b7eb8f;
font-size: 11px;
}
.tips-header-mobile {
display: flex;
align-items: center;
gap: 4px;
margin-bottom: 6px;
font-size: 14px;
}
.tips-title-mobile {
font-size: 12px;
font-weight: 600;
color: #1890ff;
}
.tips-grid-mobile {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 4px;
font-size: 10px;
span {
font-family: "Poppins";
font-size: 12px;
font-weight: 400;
}
}
.tips-verify-mobile {
color: #ff4d4f;
font-weight: 600;
}
// ActionButtons Styles
.action-buttons {
margin-top: 20px;
text-align: center;
display: flex;
justify-content: center;
gap: 16px;
@media (max-width: 480px) {
flex-direction: row;
gap: 8px;
padding: 0 16px;
}
@media (max-width: 768px) {
gap: 12px;
padding: 0 6px;
}
@media (max-width: 1024px) {
gap: 14px;
padding: 0 7px;
}
}
.action-buttons__btn {
padding: 12px 24px;
border: none;
border-radius: 8px;
cursor: pointer;
font-size: 14px;
font-weight: 400;
transition: all 0.3s ease;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
display: flex;
align-items: center;
justify-content: center;
color: #fff;
font-family: "Poppins";
@media (max-width: 480px) {
padding: 10px 16px;
font-size: 12px;
width: 100%;
}
@media (max-width: 768px) {
padding: 11px 20px;
font-size: 13px;
}
@media (max-width: 1024px) {
padding: 12px 22px;
font-size: 14px;
}
&--process {
background-color: #1890ff;
&:hover {
background-color: #096dd9;
}
}
&--clear {
background-color: #6c757d;
&:hover {
background-color: #5a6268;
}
}
}
.action-buttons__icon {
margin-right: 6px;
font-size: 16px;
@media (max-width: 480px) {
font-size: 14px;
}
@media (max-width: 768px) {
font-size: 15px;
}
}
.action-buttons__text {
&--mobile {
display: none;
@media (max-width: 480px) {
display: inline;
white-space: nowrap;
}
}
&--desktop {
display: inline;
@media (max-width: 480px) {
display: none;
}
}
}
// MultiCameraCropOCR Styles
.multi-camera-crop-ocr {
max-width: 500px;
margin: 0 auto;
}
.multi-camera-crop-ocr__scanning-message {
margin-top: 16px;
padding: 12px;
background-color: #f0f8ff;
border-radius: 8px;
text-align: center;
font-size: 14px;
color: #1890ff;
}
// Global Poppins font for all PedalOCR components
.tips-section,
.tips-header,
.tips-title,
.tips-content,
.tip-item,
.tip-verify,
.tips-section-mobile,
.tips-header-mobile,
.tips-title-mobile,
.tips-grid-mobile,
.tips-verify-mobile,
.action-buttons,
.action-buttons__btn,
.action-buttons__text,
.multi-camera-crop-ocr,
.multi-camera-crop-ocr__scanning-message {
font-family: "Poppins", sans-serif;
}
// OCRLoader Styles
.ocr-loader {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.7);
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
z-index: 9999;
font-family: "Poppins", sans-serif;
&__content {
background-color: #fff;
padding: 32px;
border-radius: 12px;
text-align: center;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
max-width: 300px;
}
&__spinner {
width: 60px;
height: 60px;
border: 4px solid #f3f3f3;
border-top: 4px solid #1890ff;
border-radius: 50%;
animation: spin 1s linear infinite;
margin: 0 auto 20px;
}
&__title {
margin: 0 0 8px 0;
color: #333;
font-size: 18px;
font-weight: 600;
font-family: "Poppins", sans-serif;
}
&__text {
margin: 0 0 16px 0;
color: #666;
font-size: 14px;
font-family: "Poppins", sans-serif;
}
&__dots {
display: flex;
justify-content: center;
gap: 4px;
}
&__dot {
width: 8px;
height: 8px;
background-color: #1890ff;
border-radius: 50%;
animation: pulse 1.4s ease-in-out infinite both;
&--1 {
animation-delay: 0.2s;
}
&--2 {
animation-delay: 0.4s;
}
&--3 {
animation-delay: 0.6s;
}
}
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
@keyframes pulse {
0%, 80%, 100% {
transform: scale(0.8);
opacity: 0.5;
}
40% {
transform: scale(1);
opacity: 1;
}
}

View File

@ -0,0 +1,23 @@
import React from "react";
const PreviewImage = ({ finalImage, onOCR, onReset }) => (
<div style={{ marginTop: 20, textAlign: "center" }}>
<img src={finalImage} alt="Cropped" style={{ width: "100%", borderRadius: 8 }} />
<div style={{ marginTop: 10 }}>
<button
onClick={onOCR}
style={{ padding: "10px 20px", backgroundColor: "#1890ff", color: "#fff", border: "none", borderRadius: 5, cursor: "pointer", marginRight: 10 }}
>
🔍 Send to OCR
</button>
<button
onClick={onReset}
style={{ padding: "10px 20px", backgroundColor: "#f5f5f5", border: "1px solid #ccc", borderRadius: 5, cursor: "pointer" }}
>
🔄 Reset
</button>
</div>
</div>
);
export default PreviewImage;

View File

@ -0,0 +1,39 @@
import React from "react";
const ThumbnailsList = ({ images, onRemove, onRecrop }) => (
<div style={{ display: "flex", flexWrap: "wrap", gap: 10, marginTop: 10, }}>
{images.map((img, idx) => (
<div key={idx} style={{ position: "relative", cursor: "pointer" ,width:120 , height:120}}>
<img
src={img}
alt={`Cropped ${idx}`}
style={{ width: "100%", height: "100%", objectFit: "cover", borderRadius: 5 }}
onClick={() => onRecrop && onRecrop(idx)}
/>
<button
onClick={(e) => {
e.stopPropagation();
onRemove && onRemove(idx);
}}
style={{
position: "absolute",
top: -5,
right: -5,
background: "red",
color: "white",
border: "none",
borderRadius: "50%",
width: 20,
height: 20,
fontSize: 12,
cursor: "pointer"
}}
>
×
</button>
</div>
))}
</div>
);
export default ThumbnailsList;

View File

@ -0,0 +1,70 @@
import React, { useState, useEffect } from "react";
import { FiInfo, FiImage, FiEyeOff, FiFileText, FiCheck } from "react-icons/fi";
import "./PedalOCR.scss"
const TipsSection = () => {
const [isMobile, setIsMobile] = useState(false);
useEffect(() => {
const checkMobile = () => {
return window.innerWidth <= 768 || /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
};
setIsMobile(checkMobile());
const handleResize = () => setIsMobile(checkMobile());
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, []);
if (isMobile) {
return (
<div className="tips-section-mobile">
<div className="tips-header-mobile">
<FiInfo size={12} color="#1890ff" />
<span className="tips-title-mobile">Quick Tips</span>
</div>
<div className="tips-grid-mobile">
<span>• Clear images</span>
<span>• No blur/glare</span>
<span>• Flat document</span>
<span>• JPG, PNG only</span>
<span className="tips-verify-mobile">• Verify before adding</span>
</div>
</div>
);
}
return (
<div className="tips-section">
<div className="tips-header">
<FiInfo size={16} color="#1890ff" />
<h4 className="tips-title">Tips for Best Results</h4>
</div>
<div className="tips-content">
<div className="tip-item">
<FiImage size={14} color="#52c41a" />
<span>Upload clear, high-quality images</span>
</div>
<div className="tip-item">
<FiEyeOff size={14} color="#52c41a" />
<span>Avoid blur, shadows, and glare</span>
</div>
<div className="tip-item">
<FiFileText size={14} color="#52c41a" />
<span>Keep the document flat</span>
</div>
<div className="tip-item">
<FiCheck size={14} color="#52c41a" />
<span>Supported formats: JPG, PNG</span>
</div>
<div className="tip-item tip-verify">
<FiInfo size={14} color="#ff4d4f" />
<span>Verify results before adding to products</span>
</div>
</div>
</div>
);
};
export default TipsSection;

View File

@ -0,0 +1,187 @@
import React, { useMemo } from 'react';
import { FiTrash2 } from 'react-icons/fi';
const ScannedProductTable = ({ data, editable, onDataChange }) => {
const handleCellEdit = (categoryIndex, productIndex, field, value) => {
if (!editable || !onDataChange) return;
const newData = [...data];
if (field === 'Category') {
newData[categoryIndex].Category = value;
} else {
newData[categoryIndex].Products[productIndex][field] = value;
}
onDataChange(newData);
};
const allProducts = useMemo(() =>
data?.flatMap((category, categoryIndex) =>
category.Products?.map((product, productIndex) => ({
...product,
categoryIndex,
productIndex,
categoryName: category.Category,
uniqueId: `${categoryIndex}-${productIndex}`
})) || []
) || [], [data]
);
const tableStyle = {
width: '100%',
borderCollapse: 'collapse',
backgroundColor: '#fff',
borderRadius: '8px',
overflow: 'hidden',
boxShadow: '0 2px 8px rgba(0,0,0,0.1)'
};
const headerStyle = {
backgroundColor: '#f8f9fa',
border: '1px solid #e9ecef',
padding: '12px 8px',
fontWeight: 600,
fontSize: '14px',
color: '#0b0b0bff',
textAlign: 'left'
};
const cellStyle = {
border: '1px solid #e9ecef',
padding: '4px',
backgroundColor: '#fff',
transition: 'background-color 0.2s ease'
};
const inputStyle = {
width: '100%',
border: '1px solid transparent',
outline: 'none',
padding: '8px',
fontSize: '14px',
backgroundColor: 'transparent',
borderRadius: '4px',
transition: 'all 0.2s ease'
};
const editableInputStyle = {
...inputStyle,
backgroundColor: '#f8f9ff',
border: '1px solid #d6e3ff',
cursor: 'text'
};
const handleDeleteProduct = (categoryIndex, productIndex) => {
if (!editable || !onDataChange) return;
const newData = [...data];
newData[categoryIndex].Products.splice(productIndex, 1);
onDataChange(newData);
}
return (
<>
<table style={tableStyle}>
<thead>
<tr>
<th style={headerStyle}>Category</th>
<th style={headerStyle}>Product</th>
<th style={headerStyle}>MRP</th>
<th style={headerStyle}>No of Units</th>
<th style={headerStyle}>UOM</th>
<th style={headerStyle}>Delete</th>
</tr>
</thead>
<tbody>
{allProducts.map((product) => (
<tr key={product.uniqueId} style={{ ':hover': { backgroundColor: '#f8f9fa' } }}>
<td style={cellStyle}>
{editable ? (
<input
value={product.categoryName || ''}
onChange={(e) => handleCellEdit(product.categoryIndex, product.productIndex, 'Category', e.target.value)}
style={editableInputStyle}
placeholder="Enter category"
/>
) : (
<span style={{ padding: '8px', display: 'block' }}>{product.categoryName}</span>
)}
</td>
<td style={cellStyle}>
{editable ? (
<input
value={product.Product}
onChange={(e) => handleCellEdit(product.categoryIndex, product.productIndex, 'Product', e.target.value)}
style={editableInputStyle}
placeholder="Enter product name"
/>
) : (
<span style={{ padding: '8px', display: 'block' }}>{product.Product}</span>
)}
</td>
<td style={cellStyle}>
{editable ? (
<input
type="number"
value={product.MRP}
onChange={(e) => handleCellEdit(product.categoryIndex, product.productIndex, 'MRP', e.target.value)}
style={editableInputStyle}
placeholder="0.00"
/>
) : (
<span style={{ padding: '8px', display: 'block', fontWeight: 500, color: '#28a745' }}>₹{product.MRP}</span>
)}
</td>
<td style={cellStyle}>
{editable ? (
<input
type="number"
value={product.NoOfUnits}
onChange={(e) => handleCellEdit(product.categoryIndex, product.productIndex, 'NoOfUnits', parseInt(e.target.value))}
min="1"
style={editableInputStyle}
placeholder="1"
/>
) : (
<span style={{ padding: '8px', display: 'block' }}>{product.NoOfUnits}</span>
)}
</td>
<td style={cellStyle}>
{editable ? (
<input
value={product.UOM}
onChange={(e) => handleCellEdit(product.categoryIndex, product.productIndex, 'UOM', e.target.value)}
style={editableInputStyle}
placeholder="PCS"
/>
) : (
<span style={{ padding: '8px', display: 'block' }}>{product.UOM}</span>
)}
</td>
<td style={cellStyle}>
{editable ? (
<button
onClick={() => handleDeleteProduct(product.categoryIndex, product.productIndex)}
title="Delete"
style={{
background: 'transparent',
border: 'none',
cursor: 'pointer',
color: '#e53935',
padding: '8px',
display: 'inline-flex',
alignItems: 'center'
}}
>
<FiTrash2 />
</button>
) : null}
</td>
</tr>
))}
</tbody>
</table>
</>
);
};
export default ScannedProductTable;

View File

@ -0,0 +1,25 @@
import {ReprintTables as ReprintTablesLibrary } from "../../../ownLib/my-ui-lib"
export const ReprintTables = ReprintTablesLibrary
// import { Table } from 'antd';
// export const ReprintTables = ({ columns, data, onChange, pagination }) => {
// return (
// <>
// <Table
// columns={columns}
// dataSource={data}
// onChange={onChange}
// pagination={
// pagination
// ? false
// : {
// defaultPageSize: 10,
// showSizeChanger: false,
// hideOnSinglePage: true,
// }
// }
// />
// </>
// );
// };

View File

@ -0,0 +1,47 @@
import { Tables as TableLibrary } from "../../../ownLib/my-ui-lib"
export const Tables = TableLibrary
// import { Table } from 'antd';
// export const Tables = ({
// columns,
// data,
// onChange,
// pagination,
// rowSelection,
// rowClassName,
// summary,
// }) => {
// return (
// <>
// <Table
// columns={columns}
// dataSource={data}
// onChange={onChange}
// summary={summary ? summary : null}
// rowSelection={rowSelection ? rowSelection : null}
// pagination={
// pagination
// ? {
// onChange: pagination,
// defaultPageSize: 10,
// showSizeChanger: false,
// hideOnSinglePage: true,
// }
// : false
// }
// rowClassName={rowClassName}
// // pagination={
// // pagination
// // ? pagination
// // : {
// // defaultPageSize: 10,
// // showSizeChanger: false,
// // hideOnSinglePage: true,
// // }
// // }
// />
// </>
// );
// };

View File

@ -0,0 +1,21 @@
import {TooltipWrapper as TooltipWrapperLibrary} from "../../../ownLib/my-ui-lib"
const TooltipWrapper = TooltipWrapperLibrary
export default TooltipWrapper;
// import React from 'react';
// import { Tooltip } from 'antd';
// const TooltipWrapper = ({ children, title, isMobile, placement, onClick }) => {
// if (isMobile) {
// return children; // If isMobile is true, just render the children without a Tooltip
// }
// return (
// <Tooltip title={title} placement={placement} onClick={onClick}>
// {children}
// </Tooltip>
// ); // Otherwise, wrap the children in Tooltip
// };
// export default TooltipWrapper;

View File

@ -0,0 +1,163 @@
import React, { Component } from 'react';
import { isMobile } from 'react-device-detect';
import { FaWeight } from 'react-icons/fa';
class WeightScale extends Component {
constructor(props) {
super(props);
this.state = {
Finalresult: '',
result: '',
amtPerGram: 0,
finalData: [],
portValdata: null,
};
}
// this.myfun
componentDidMount = async () => {
this.portfun(this.props.portval);
if (this.props.WeightScale === false) {
await port.close({ baudRate: 9600 });
port.close(() => {
connected = false;
});
}
};
portfun = async (e) => {
if (e === null) {
const port = await navigator.serial.requestPort();
if (port) {
await this.props.setportfun(port);
await this.myfun(port);
} else {
console.log('portnot closed', port);
}
} else {
this.props.setportfun(e);
this.myfun(e);
}
};
isFloat = (value) => {
const numericValue = parseFloat(value);
return !Number.isNaN(numericValue) && !Number.isInteger(numericValue);
};
myfun = async (port) => {
// const port = await navigator.serial.requestPort();
if (port.readable === null) {
await port.open({ baudRate: 9600 });
}
while (port.readable) {
if (!port.readable.locked) {
const reader = port.readable.getReader();
try {
while (true) {
const { value, done } = await reader.read();
if (done) {
reader.releaseLock();
break;
}
if (value) {
await this.setState({
result: await new TextDecoder('utf-8').decode(value),
});
if (
this.isFloat(new TextDecoder('utf-8').decode(value)) === true
) {
await this.props.testfun(
new TextDecoder('utf-8').decode(value)
);
}
if (this.props.portclose === false) {
reader.cancel();
await port.close({ baudRate: 9600 });
port.close(() => {
connected = false;
});
}
}
}
} catch (error) {
if (error.message === 'The device has been lost.') {
this.props.msg({ type: 'error', msg: 'Weight Scale disconnect' });
// Optionally, you can attempt to reopen the port or take other actions
}
}
} else {
break;
}
}
};
openport = async () => {
const port = await navigator.serial.requestPort();
if (port) {
this.props.setportfun(port);
}
if (port.readable === null) {
await port.open({ baudRate: 9600 });
}
while (port.readable) {
if (!port.readable.locked) {
const reader = port.readable.getReader();
try {
while (true) {
const { value, done } = await reader.read();
if (done) {
reader.releaseLock();
break;
}
if (value) {
await this.setState({
result: await new TextDecoder('utf-8').decode(value),
});
if (
this.isFloat(new TextDecoder('utf-8').decode(value)) === true
) {
await this.props.testfun(
new TextDecoder('utf-8').decode(value)
);
}
if (this.props.portclose === false) {
reader.cancel();
}
}
}
} catch (error) {}
} else {
break;
}
}
};
componentDidUpdate = async () => {
if (this.props.portclose === true) this.portfun(this.props.portval);
};
render() {
return (
<div style={{ display: 'inline' }}>
{/* <FaWeight
style={{fontSize: "22px", cursor: "pointer", margin: "0px 0px 5px 16px",color: "black"}}
onClick={()=>this.openport()}
/> */}
</div>
);
}
}
export default WeightScale;

View File

@ -0,0 +1,61 @@
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';
import { axiosRetailInstanceData } from '../AuthenicationToken/AuthenticationToken';
export const getEmpAccess = createAsyncThunk(
'Home/getEmpAccess',
async (data) => {
if (
data?.CompId != null &&
data?.CompId != undefined &&
data?.BranchId != null &&
data?.BranchId != undefined &&
data?.EmpId != null &&
data?.EmpId != undefined &&
data?.AppId != null &&
data?.AppId != undefined
) {
return await axiosRetailInstanceData.get(
`/empAccess?CompId=${data?.CompId}&BranchId=${data?.BranchId}&EmpId=${data?.EmpId}&AppId=${data?.AppId}`
);
}
}
);
const initialState = {
breadCrumb: [],
RedirectStatus: false,
EmpAccessDetail:[]
};
const centerPageSlice = createSlice({
name: 'centerPage',
initialState,
reducers: {
changeBreadCrumb: (state, action) => {
const { items } = action?.payload;
state.breadCrumb = items;
},
emptyBreadCrumb: (state, action) => {
state.breadCrumb = [];
},
ChangeRedirectStatus: (state, action) => {
state.RedirectStatus = action?.payload;
},
},
extraReducers: (builder) => {
builder.addCase(getEmpAccess.fulfilled, (state, action) => {
if (action?.payload?.data?.statusCode === 1) {
state.EmpAccessDetail = action?.payload?.data?.data[0]?.EmpAccessDetails;
}
})
}
});
export const { changeBreadCrumb, emptyBreadCrumb, ChangeRedirectStatus } =
centerPageSlice.actions;
export const breadCrumbSelector = (state) => state.centerPage?.breadCrumb;
export const GlobalRedirectStatus = (state) => state.centerPage?.RedirectStatus;
export const GlobalEmpAccessDetail = (state)=>state.centerPage?.EmpAccessDetail
export default centerPageSlice.reducer;

View File

@ -0,0 +1,198 @@
import axios from 'axios';
import {
getSession,
clearSession,
TokendecryptedValuesFun,
} from '../../Services/Others';
const apiUrl = import.meta.env.ENV_API_URL;
const apiCommonUrl = import.meta.env.ENV_API_URL_COMMON;
const subDirectory = import.meta.env.ENV_COMMON_BASE_URL;
const EmailApiUrl = import.meta.env.ENV_EMAIL_API;
const apiRetailOcr = import.meta.env.ENV_API_URL_OCR
const axiosRetailInstance = axios.create({
baseURL: apiUrl,
});
const axiosCommonInstance = axios.create({
baseURL: apiCommonUrl,
});
const axiosEmail_SMS = axios.create({
baseURL: EmailApiUrl,
});
const axiosRetailOcr = axios.create({
baseURL: apiRetailOcr,
});
const getToken = () => {
return new Promise((resolve) => {
let token = sessionStorage.getItem('auth');
if (token) {
resolve(token);
} else {
const tokenInterval = setInterval(() => {
token = sessionStorage.getItem('auth');
if (token) {
clearInterval(tokenInterval);
resolve(token);
}
}, 100);
}
});
};
const addAuthHeader = async (config) => {
const token = await getToken();
if (token) {
config.headers['Authorization'] = `Bearer ${token}`;
console.log(config, 'Request config after adding token');
} else {
console.warn('Token is still not available.');
}
let encryptedMobileno = sessionStorage.getItem('MobileNo');
let encryptedUserId = sessionStorage.getItem('UserId');
let encryptedLoginType = TokendecryptedValuesFun(
sessionStorage.getItem('LoginType')
);
console.log(
'encryptedLoginType',
encryptedLoginType,
TokendecryptedValuesFun(encryptedMobileno)
);
// let Mobileno = encryptedUserId && encryptedLoginType != "Kiosk" ? TokendecryptedValuesFun(encryptedMobileno) : '1000000001';
let Mobileno = encryptedUserId
? TokendecryptedValuesFun(encryptedMobileno)
: '1000000001';
console.warn('Mobileno is still not available.');
config.headers['Mobileno'] = Mobileno;
return config;
};
axiosRetailInstance.interceptors.request.use(addAuthHeader, (error) => {
console.error('Error in request interceptor:', error);
return Promise.reject(error);
});
axiosCommonInstance.interceptors.request.use(addAuthHeader, (error) => {
console.error('Error in request interceptor:', error);
return Promise.reject(error);
});
axiosEmail_SMS.interceptors.request.use(addAuthHeader, (error) => {
console.error('Error in request interceptor:', error);
return Promise.reject(error);
});
axiosRetailOcr.interceptors.request.use(
(config) => {
// no auth header needed
return config;
},
(error) => {
console.error('Error in request interceptor:', error);
return Promise.reject(error);
}
);
function showNotification(message) {
const notification = document.createElement('div');
notification.innerText = message;
notification.style.cssText = `
position: fixed;
top: 10%;
left: 50%;
transform: translate(-50%, -50%);
background-color: #f03e3e;
color: white;
padding: 15px 30px;
border-radius: 8px;
font-family: Arial, sans-serif;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
z-index: 1000;
opacity: 0;
transition: opacity 0.3s ease;
`;
document.body.appendChild(notification);
// Show the notification
setTimeout(() => {
notification.style.opacity = 1;
}, 10);
// Remove the notification after 3 seconds
setTimeout(() => {
notification.style.opacity = 0;
setTimeout(() => notification.remove(), 300);
}, 2000);
}
const responseErrorHandler = async (error) => {
if (error.response && error.response.status === 401) {
showNotification(
'Your session has expired. Please log in again to continue.'
);
setTimeout(() => {
if (getSession('UserId')) {
const Generate = 'N';
fetch(`${apiCommonUrl}/Logout`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
Authorization: sessionStorage.getItem('auth')
? sessionStorage.getItem('auth')
: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9',
Mobileno: getSession('MobileNo')
? getSession('MobileNo')
: '1000000001',
},
body: JSON.stringify({
UserId: getSession('UserId'),
Generate: Generate,
RequestMode: 'DW',
}),
})
.then((response) => {
if (!response.ok) {
throw new Error(`Error: ${response.status}`);
}
return response.json();
})
.then((data) => {
if (data?.statusCode === 1) {
clearSession();
window.location.href = `${subDirectory}`;
}
})
.catch((error) => {
console.error('Error:', error);
});
}
// else {
// clearSession();
// window.location.href = `${subDirectory}`;
// }
}, 2000);
}
// else {
// alert("An error occurred. Please try again later.");
// }
return Promise.reject(error);
};
axiosCommonInstance.interceptors.response.use(
(response) => response, // On success, just return the response
// responseErrorHandler // Handle errors
);
axiosRetailInstance.interceptors.response.use(
(response) => response, // On success, just return the response
// responseErrorHandler // Handle errors
);
export const axiosRetailInstanceData = axiosRetailInstance;
export const axiosCommonInstanceData = axiosCommonInstance;
export const axiosEmail_SMSData = axiosEmail_SMS;
export const axiosRetailOcrData = axiosRetailOcr;

View File

@ -0,0 +1,73 @@
import { createAsyncThunk } from '@reduxjs/toolkit';
import { axiosRetailInstanceData } from '../AuthenicationToken/AuthenticationToken';
export const getBarcodeSessionsIDs = createAsyncThunk(
'barcode/getBarcodeSessionsIDs',
async () => {
return await axiosRetailInstanceData.get(
`/ConfigMaster?typeName=Barcode Size`
);
}
);
export const getBarcodeComponent = createAsyncThunk(
'barcode/getBarcodeComponent',
async () => {
return await axiosRetailInstanceData.get(`/BarcodeComponent`);
}
);
export const getBarcodeComponentsBasedOnSessionId = createAsyncThunk(
'barcode/getBarcodeComponent',
async (sessionId) => {
return await axiosRetailInstanceData.get(
`/BarcodeComponent?sessionId=${sessionId}&activeStatus=A`
);
}
);
export const putBarcodeComponent = createAsyncThunk(
'barcode/putBarcodeComponent',
async (putData) => {
return await axiosRetailInstanceData.put('/BarcodeComponent', putData);
}
);
export const postBarcodeComponent = createAsyncThunk(
'barcode/postBarcodeComponent',
async (postData) => {
return await axiosRetailInstanceData.post('/BarcodeComponent', postData);
}
);
export const deleteBarcodeComponent = createAsyncThunk(
'barcode/deleteBarcodeComponent',
async ({ componentId, updatedBy, activeStatus }) => {
return await axiosRetailInstanceData.delete(
`/BarcodeComponent?componentId=${componentId}&updatedBy=${updatedBy}&activeStatus=${activeStatus}`
);
}
);
export const getBarcodeTemplate = createAsyncThunk(
'barcode/getBarcodeComponent',
async ({ compId, appId, branchId }) => {
return await axiosRetailInstanceData.get(
`/BarcodeTemplate?compId=${compId}&appId=${appId}&branchId=${branchId}`
);
}
);
export const putBarcodeTemplate = createAsyncThunk(
'barcode/putBarcodeComponent',
async (putData) => {
return await axiosRetailInstanceData.put('/BarcodeTemplate', putData);
}
);
export const postBarcodeTemplate = createAsyncThunk(
'barcode/postBarcodeComponent',
async (postData) => {
return await axiosRetailInstanceData.post('/BarcodeTemplate', postData);
}
);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,48 @@
//
import { create } from 'zustand';
// Utility: format date as YYYY-MM-DD
const formatDate = (date) => {
const d = new Date(date);
const year = d.getFullYear();
const month = String(d.getMonth() + 1).padStart(2, '0');
const day = String(d.getDate()).padStart(2, '0');
return `${year}-${month}-${day}`;
};
// Utility: get today's and tomorrow's date
const today = new Date();
const tomorrow = new Date();
tomorrow.setDate(today.getDate() + 1);
export const useDateStore = create((set) => ({
selectedDate: [formatDate(today), formatDate(today)], // initial 2 dates
isBulk: false,
setSelectedDate: (dates) => {
// Always store as an array in YYYY-MM-DD format
const formattedDates = (Array.isArray(dates) ? dates : [dates]).map(formatDate);
console.log(formattedDates, "dates useDateStore");
set({ selectedDate: formattedDates });
},
invoiceDate: formatDate(today), // single date instead of array
setInvoiceDate: (date) => {
// Store as single date in YYYY-MM-DD format
const formattedDate = formatDate(date);
console.log(formattedDate, "date useDateStore");
set({ invoiceDate: formattedDate });
},
clearInvoiceDate: () => {
// Reset to today's date in YYYY-MM-DD format
const t1 = formatDate(new Date());
set({ invoiceDate: t1 });
},
clearDates: () => {
// Reset to current + next day in YYYY-MM-DD format
const t1 = formatDate(new Date());
set({ selectedDate: [t1, t1] });
},
setIsBulk: (value) => set({ isBulk: value }),
}));

View File

@ -0,0 +1,523 @@
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';
import axios from 'axios';
import {
axiosRetailInstanceData,
axiosCommonInstanceData,
} from '../../AuthenicationToken/AuthenticationToken';
import { getSession } from '../../../Services/Others';
import { getSelfBooking } from '../../TableBooking/TableBooking';
const Paymentdevice_POST_URL = import.meta.env.ENV_PAYMENT_DEVICE_URL;
const Paymentdevice_GET_URL = import.meta.env.ENV_PAYMENT_STATUS_GET_URL;
const apiCommonUrl = import.meta.env.ENV_API_URL_COMMON;
export const getProductCategories = createAsyncThunk(
'KioskBookingData/getLayoutCategories',
async ({ CompId, BranchId, AppId }) => {
if (
CompId != null &&
CompId != undefined &&
BranchId != null &&
BranchId != undefined &&
AppId != null &&
AppId != undefined
) {
return await axiosRetailInstanceData.get(
`/productCat?CompId=${CompId}&BranchId=${BranchId}&AppId=${AppId}`
);
}
}
);
export const getPaymentVerfication = createAsyncThunk(
'KioskBookingData/getLayoutCategories',
async (OrderId) => {
if (
OrderId != null &&
OrderId != undefined
) {
return await axiosRetailInstanceData.get(
`/PaymentPageStatus?orderId=${OrderId}`
);
}
}
);
export const getCustomerBooking = createAsyncThunk(
'self/CustomerBookings',
({ AppId, CompId, BranchId, CustId, FromDate, ToDate }) => {
if (CompId != null && CompId != undefined && BranchId != null && BranchId != undefined && AppId != null && AppId != undefined && CustId != null && CustId != undefined && FromDate != null && FromDate != undefined && ToDate != null && ToDate != undefined) {
return axiosRetailInstanceData.get(`/CustomerBookings?CompId=${CompId}&BranchId=${BranchId}&AppId=${AppId}&CustId=${CustId}&fromDate=${FromDate}&toDate=${ToDate}`);
}
else if (CompId != null && CompId != undefined && BranchId != null && BranchId != undefined && AppId != null && AppId != undefined && CustId != null && CustId != undefined) {
return axiosRetailInstanceData.get(`/CustomerBookings?CompId=${CompId}&BranchId=${BranchId}&AppId=${AppId}&CustId=${CustId}`);
}
}
);
// get /CustomerMembership
export const getCustomerMembership = createAsyncThunk(
'self/CustomerMembership',
({ AppId, CompId, BranchId, CustId }) => {
if (CompId != null && CompId != undefined && BranchId != null && BranchId != undefined && AppId != null && AppId != undefined && CustId != null && CustId != undefined) {
return axiosRetailInstanceData.get(`/CustomerMembership?CompId=${CompId}&BranchId=${BranchId}&AppId=${AppId}&CustId=${CustId}`);
}
}
);
export const getProductCardListKiosk = createAsyncThunk(
'KioskBookingData/getProductCardListKiosk',
async ({ CompId, BranchId, AppId, ProdCat, ProdSubCat, Search, Dates,fromDate,toDate }) => {
if (
CompId != null &&
CompId != undefined &&
BranchId != null &&
BranchId != undefined &&
AppId != null &&
AppId != undefined &&
ProdCat != null &&
ProdCat != undefined && Search != null && Search != undefined && Search != ""
) {
return await axiosRetailInstanceData.get(
`/productCardList?CompId=${CompId}&BranchId=${BranchId}&AppId=${AppId}&ProdName=${encodeURIComponent(Search)}`
);
}
else if (
CompId != null &&
CompId != undefined &&
BranchId != null &&
BranchId != undefined &&
AppId != null &&
AppId != undefined &&
ProdSubCat != null &&
ProdSubCat != undefined &&
fromDate != null &&
fromDate != undefined &&
toDate != null &&
toDate != undefined
) {
return await axiosRetailInstanceData.get(
`/productCardList?CompId=${CompId}&BranchId=${BranchId}&AppId=${AppId}&ProdSubCat=${ProdSubCat}&fromDate=${fromDate}&toDate=${toDate}`
);
}
else if (
CompId != null &&
CompId != undefined &&
BranchId != null &&
BranchId != undefined &&
AppId != null &&
AppId != undefined &&
ProdSubCat != null &&
ProdSubCat != undefined &&
Dates != null && Dates != undefined
) {
return await axiosRetailInstanceData.get(
`/productCardList?CompId=${CompId}&BranchId=${BranchId}&AppId=${AppId}&ProdSubCat=${ProdSubCat}&date=${Dates}`
);
}
else if (
CompId != null &&
CompId != undefined &&
BranchId != null &&
BranchId != undefined &&
AppId != null &&
AppId != undefined &&
ProdSubCat != null &&
ProdSubCat != undefined
) {
return await axiosRetailInstanceData.get(
`/productCardList?CompId=${CompId}&BranchId=${BranchId}&AppId=${AppId}&ProdSubCat=${ProdSubCat}`
);
}
else {
return await axiosRetailInstanceData.get(
`/ProductCardList?CompId=${CompId}&BranchId=${BranchId}&AppId=${AppId}&prodCat=${ProdCat}`
);
}
}
);
export const PostKioskBookingData = createAsyncThunk(
'BookingData/PostKioskBookingdata',
async (postData) => {
return await axiosRetailInstanceData.post(`/KioskBooking`, postData);
}
);
export const PostSelfBookingCustomer = createAsyncThunk(
'BookingData/PostKioskBookingdata',
async (postData) => {
return await axiosRetailInstanceData.post(`/CustomerSelfBooking`, postData);
}
);
export const PutKioskBookingData = createAsyncThunk(
'BookingData/PutKioskBookingdata',
async (putData) => {
return await axiosRetailInstanceData.put(`/KioskBooking`, putData);
}
);
export const PutBookingPaymentStatusChange = createAsyncThunk(
'BookingData/PutBookingPaymentStatusChange',
async (putData) => {
return await axiosRetailInstanceData.put(`/BookingPaymentStatus`, putData);
}
);
// http://192.168.1.37:8001/ProductCardList?request.compId=1&request.branchId=1&request.appId=2&request.prodCat=224
export const getCompanyData = createAsyncThunk(
'appAccess/getCompanyData',
async ({ CompId }) => {
if (CompId != null && CompId != undefined) {
return await axios.get(`${apiCommonUrl}/company?CompId=${CompId}`);
}
}
);
export const getPaymentGatewayConfig = createAsyncThunk(
'getPaymentGatewayConfig',
async ({ CompId, AppId, BranchId }) => {
if (
CompId != null &&
CompId != undefined &&
BranchId != null &&
BranchId != undefined &&
AppId != null &&
AppId != undefined
) {
return await axiosCommonInstanceData.get(
`/PaymentGatewayConfig?CompId=${CompId}&BranchId=${BranchId}&AppId=${AppId}`
);
}
}
);
export const getPaymentGatewayDetails = createAsyncThunk(
'getPaymentGatewayDetails',
async ({ CompId, AppId, BranchId, DetailType }) => {
if (
CompId != null &&
CompId != undefined &&
BranchId != null &&
BranchId != undefined &&
AppId != null &&
AppId != undefined
) {
return await axiosRetailInstanceData.get(
`/upi?CompId=${CompId}&BranchId=${BranchId}&AppId=${AppId}&detailType=${DetailType}`
);
}
}
);
export const getAllApplications = createAsyncThunk(
'application/getApplicationData',
async ({ AppId }) => {
if (AppId != null && AppId != undefined) {
return axios.get(`${apiCommonUrl}/application?AppId=${AppId}`);
}
}
);
export const getDeviceAccess = createAsyncThunk(
'agetDeviceAccess',
async ({ DeviceAddress }) => {
if (DeviceAddress != null && DeviceAddress != undefined) {
return axiosCommonInstanceData.get(
`/DeviceInfo?DeviceAddress=${DeviceAddress}`
);
}
}
);
export const getPaymentOptionsData = createAsyncThunk(
'getPaymentOptionsData',
({ AppId, CompId, BranchId }) => {
const UserType = getSession('UserType');
if (
CompId != null &&
CompId != undefined &&
BranchId != null &&
BranchId != undefined &&
AppId != null &&
AppId != undefined &&
UserType !== 'Super Admin' &&
UserType !== 'Super Admin User'
) {
return axiosRetailInstanceData.get(
`/paymentOptions?CompId=${CompId}&BranchId=${BranchId}&AppId=${AppId}`
);
}
}
);
export const getPaymentDeviceAccessData = createAsyncThunk(
'getPaymentDeviceAccessData',
({ AppId, CompId, BranchId, UserId }) => {
if (
CompId != null &&
CompId != undefined &&
BranchId != null &&
BranchId != undefined &&
AppId != null &&
AppId != undefined &&
UserId != null &&
UserId != undefined
) {
return axiosRetailInstanceData.get(
`/PaymentDeviceAccess?CompId=${CompId}&BranchId=${BranchId}&AppId=${AppId}&UserId=${UserId}`
);
}
}
);
export const getPaymentGatewayAccessData = createAsyncThunk(
'getPaymentGatewayAccessData',
({ AppId, CompId, BranchId, ActiveStatus }) => {
if (
CompId != null &&
CompId != undefined &&
BranchId != null &&
BranchId != undefined &&
AppId != null &&
AppId != undefined
) {
return axiosCommonInstanceData.get(
`/PaymentGatewayConfig?CompId=${CompId}&BranchId=${BranchId}&AppId=${AppId}&ActiveStatus=${ActiveStatus}`
);
}
}
);
export const postPaymentDevice = createAsyncThunk(
'postPaymentDevice',
async (data, { rejectWithValue }) => {
try {
const response = await axios.post(`${Paymentdevice_POST_URL}`, data, {
headers: {
'Content-Type': 'application/json', // Set the Content-Type header
// Add any other headers here if needed
},
});
console.log('Response Data:', response?.data); // Log the response data
return response?.data;
} catch (error) {
console.error('Request Error:', error);
return rejectWithValue(error.response?.data || error.message);
}
}
);
export const getPaymentDeviceResponse = createAsyncThunk(
'getPaymentDeviceResponse',
async (data, { rejectWithValue }) => {
try {
const response = await axios.post(`${Paymentdevice_GET_URL}`, data, {
headers: {
'Content-Type': 'application/json', // Set the Content-Type header
},
});
console.log('Response Data:', response?.data); // Log the response data
return response?.data;
} catch (error) {
console.error('Request Error:', error);
return rejectWithValue(error.response?.data || error.message);
}
}
);
const initialState = {
BookingType: 'TakeAway',
ProdCat: null,
ProdSubCat: null,
CategorieData: [],
ProductCardList: [],
KioskOrderDetails: [],
OrderbtnClicked: false,
OrderId: null,
SalesId: null,
KioskBookingTypeBoth: false,
PaymentgatewayRedirect: false,
PGFailedTransId: null,
PGFailedAmt: null,
MergeData: [], // Add merge data to global state
LastBuyProducts: [],
changeAddlastPrds: false,
MembershipDetail: [],
OrderOfferDetails: [],
selfBookingCustomerDtls: null,
MembershipNumber: null
};
const KioskBookingData = createSlice({
name: 'KioskBookingData',
initialState,
reducers: {
changeSelfBookingCustomerDtls: (state, action) => {
state.selfBookingCustomerDtls = action?.payload
},
changeOrderOfferDetail: (state, action) => {
state.OrderOfferDetails = action?.payload;
},
changeAddlastPrds: (state, action) => {
state.changeAddlastPrds = action?.payload;
},
changeMembershipDetail: (state, action) => {
state.MembershipDetail = action?.payload;
},
changeAllLastBuyProducts: (state, action) => {
state.LastBuyProducts = action?.payload
},
changeProductCategorie: (state, action) => {
state.ProdCat = action?.payload;
},
changeProductSubCategorie: (state, action) => {
state.ProdSubCat = action?.payload;
},
changeBookingType: (state, action) => {
state.BookingType = action?.payload;
},
changeCategorieData: (state, action) => {
state.CategorieData = action?.payload;
},
changeProductCardListData: (state, action) => {
state.ProductCardList = action?.payload;
},
changePaymentgatewayRedirect: (state, action) => {
state.PaymentgatewayRedirect = action?.payload;
},
changeAllGlbStatustData: (state, action) => {
(state.BookingType = 'TakeAway'),
(state.KioskOrderDetails = []),
(state.OrderbtnClicked = false),
(state.OrderId = null),
(state.ProdCat = null),
state.CategorieData;
// cart clear
},
changeKioskOrderDetails: (state, action) => {
state.KioskOrderDetails = action?.payload;
const result =
action?.payload?.some(
(product) => product.BookingTypeName === 'TakeAway'
) &&
action?.payload?.some(
(product) => product.BookingTypeName === 'Dine In'
);
state.KioskBookingTypeBoth = result ? true : false;
},
changeOrderbtnClicked: (state, action) => {
state.OrderbtnClicked = action?.payload;
},
changeOrderId: (state, action) => {
state.OrderId = action?.payload;
},
changeSalesId: (state, action) => {
state.SalesId = action?.payload;
},
changePGFailedTransId: (state, action) => {
state.PGFailedTransId = action?.payload;
},
changePGFailedAmt: (state, action) => {
state.PGFailedAmt = action?.payload;
},
changeMergeData: (state, action) => {
state.MergeData = action?.payload;
},
changeMembershipNumber: (state, action) => {
state.MembershipNumber = action?.payload;
}
},
extraReducers: (builder) => {
builder.addCase(getProductCategories.fulfilled, (state, action) => {
if (action?.payload?.data?.statusCode == 1) {
state.CategorieData = action?.payload?.data?.data;
// state.ProdCat = action?.payload?.data?.data[0].ProdCat;
} else {
state.CategorieData = action?.payload?.data?.data;
// state.ProdCat = null;
}
}),
builder.addCase(getProductCardListKiosk.fulfilled, (state, action) => {
if (action?.payload?.data?.statusCode == 1) {
state.ProductCardList = action?.payload?.data?.data;
} else {
state.ProductCardList = [];
}
});
builder.addCase(getSelfBooking.fulfilled, (state, action) => {
if (action?.payload?.data?.statusCode == 1) {
state.KioskOrderDetails =
action?.payload?.data?.data?.[0]?.productDetails?.map((item) => ({
...item,
disabled: true,
}));
state.OrderId = action?.payload?.data?.data?.[0]?.OrderId;
state.SalesId = action?.payload?.data?.data?.[0]?.SalesId;
} else {
state.KioskOrderDetails = [];
}
});
},
});
export const {
changeSelfBookingCustomerDtls,
changeProductCategorie,
changeProductSubCategorie,
changeBookingType,
changeCategorieData,
changeProductCardListData,
changeAllGlbStatustData,
changeKioskOrderDetails,
changeOrderbtnClicked,
changeOrderId,
changePaymentgatewayRedirect,
changePGFailedTransId,
changePGFailedAmt,
changeSalesId,
changeMergeData,
changeAllLastBuyProducts, changeAddlastPrds,
changeMembershipDetail, changeOrderOfferDetail, changeMembershipNumber
} = KioskBookingData.actions;
export const GlobalBookingTypeKiosk = (state) =>
state?.KioskBookingData?.BookingType;
export const GlobalProductCategorieKiosk = (state) =>
state?.KioskBookingData?.ProdCat;
export const GlobalProductSubCategorieKiosk = (state) =>
state?.KioskBookingData?.ProdSubCat;
export const GlobalCategorieDataKiosk = (state) =>
state?.KioskBookingData?.CategorieData;
export const GlobalProductCardListKiosk = (state) =>
state?.KioskBookingData?.ProductCardList;
export const GlobalKioskOrderDetails = (state) =>
state?.KioskBookingData?.KioskOrderDetails;
export const GlobalOrderbtnClicked = (state) =>
state?.KioskBookingData?.OrderbtnClicked;
export const GlobalOrderId = (state) => state?.KioskBookingData?.OrderId;
export const GlobalSalesId = (state) => state?.KioskBookingData?.SalesId;
export const GlobalKioskBookingTypeBoth = (state) =>
state?.KioskBookingData?.KioskBookingTypeBoth;
export const GlobalPaymentgatewayRedirect = (state) =>
state?.KioskBookingData?.PaymentgatewayRedirect;
export const GlobalPGFailedTransId = (state) =>
state?.KioskBookingData?.PGFailedTransId;
export const GlobalPGFailedAmt = (state) =>
state?.KioskBookingData?.PGFailedAmt;
export const GlobalMergeData = (state) => state?.KioskBookingData?.MergeData;
export const GlobalLastBuyProducts = (state) => state?.KioskBookingData?.LastBuyProducts;
export const GlobalChangeAddlastPrds = (state) => state?.KioskBookingData?.changeAddlastPrds;
export const GlobalMembershipDetail = (state) => state?.KioskBookingData?.MembershipDetail;
export const GlobalOrderOfferDetails = (state) => state?.KioskBookingData?.OrderOfferDetails;
export const GlobalSelfBookingCustomerDtls = (state) => state?.KioskBookingData?.selfBookingCustomerDtls;
export const GlobalMembershipNumber = (state) => state?.KioskBookingData?.MembershipNumber;
export default KioskBookingData.reducer;

View File

@ -0,0 +1,136 @@
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit';
import { axiosRetailInstanceData } from '../../AuthenicationToken/AuthenticationToken';
export const getAddCustomerDetails = createAsyncThunk(
'addCustomer/getAddCustomerDetails',
async (data) => {
if (
data?.MobileNo != null &&
data?.MobileNo != undefined &&
data?.AppId != null &&
data?.AppId != undefined &&
data?.CompId != null &&
data?.CompId != undefined &&
data?.BranchId != null &&
data?.BranchId != undefined
) {
return await axiosRetailInstanceData.get(
`/customer?MobileNo=${data?.MobileNo}&AppId=${data?.AppId}&CompId=${data?.CompId}&BranchId=${data?.BranchId}`
);
}
}
);
export const postAddCustomerDetails = createAsyncThunk(
'addCustomer/postAddCustomerDetails',
async (postData) => {
return await axiosRetailInstanceData.post(`/customer`, postData);
}
);
export const postRePrintReason = createAsyncThunk(
'rePrint/postRePrintReason',
async (postData) => {
return await axiosRetailInstanceData.post(`/rePrint`, postData);
}
);
export const postDefaultReprintReason = createAsyncThunk(
'rePrint/postDefaultReprintReason',
async (postData) => {
return await axiosRetailInstanceData.post(`/DefaultStatusReprint`, postData);
}
);
export const getRePrintDefault = createAsyncThunk(
'rePrint/getRePrintDefault',
async (data) => {
return await axiosRetailInstanceData.get(`/ReprintHistoryStatus?compId=${data.CompId}&branchId=${data.BranchId}&appId=${data.AppId}&Type=${data?.Type ? data?.Type : 'Reprint'}`);
}
);
export const getDefaultPaymentOptions = createAsyncThunk(
'rePrint/getDefaultPaymentOptions',
async (data) => {
return await axiosRetailInstanceData.get(`/ReprintHistoryStatus?compId=${data.CompId}&branchId=${data.BranchId}&appId=${data.AppId}&Type=PaymentOptions`);
}
);
export const getRePrintReason = createAsyncThunk(
'rePrint/getRePrintReason',
async (data) => {
if (
data?.orderFromDate != null &&
data?.orderFromDate != undefined &&
data?.orderToDate != null &&
data?.orderToDate != undefined &&
data?.appId != null &&
data?.appId != undefined &&
data?.compId != null &&
data?.compId != undefined &&
data?.branchId != null &&
data?.branchId != undefined
) {
return await axiosRetailInstanceData.get(
`/ReprintHistory?compId=${data.compId}&branchId=${data.branchId}&appId=${data.appId}&fromDate=${data.orderFromDate}&toDate=${data.orderToDate}`
);
}
}
);
export const ReprintDetails = createAsyncThunk(
"addCustomer/ReprintDetails",
async (data) => {
const { AppId, CompId, BranchId, OrderFromDate, OrderToDate, OrderId } = data || {};
if (OrderId && !OrderFromDate && !OrderToDate) {
return await axiosRetailInstanceData.get(
`/reprint?CompId=${CompId}&BranchId=${BranchId}&AppId=${AppId}&OrderId=${OrderId}&pageNumber=${data.PageNumber}`
);
}
if (OrderFromDate && OrderToDate) {
return await axiosRetailInstanceData.get(
`/reprint?CompId=${CompId}&BranchId=${BranchId}&AppId=${AppId}&orderFromDate=${OrderFromDate}&orderToDate=${OrderToDate} &pageNumber=${data.PageNumber}`
);
} else {
return await axiosRetailInstanceData.get(
`/reprint?CompId=${CompId}&BranchId=${BranchId}&AppId=${AppId}&pageNumber=${data.PageNumber}`
);
}
}
);
const initialState = {
AddCustomerDetails: [],
refreshTrigger: 0,
};
const addCustomer = createSlice({
name: 'addCustomer',
initialState,
reducers: {
changeCustomerdetails: (state, action) => {
state.AddCustomerDetails = action?.payload;
},
triggerCustomerRefresh: (state) => {
state.refreshTrigger += 1;
},
},
extraReducers: (builder) => {
builder.addCase(getAddCustomerDetails.fulfilled, (state, action) => {
if (action?.payload?.status) {
state.AddCustomerDetails = action?.payload?.data?.data;
} else {
state.AddCustomerDetails = [];
}
});
},
});
export const { changeCustomerdetails, triggerCustomerRefresh } = addCustomer.actions;
export const GlobalAddCustomerDetails = (state) =>
state.addCustomer?.AddCustomerDetails;
export const GlobalCustomerRefreshTrigger = (state) =>
state.addCustomer?.refreshTrigger;
export default addCustomer.reducer;

View File

@ -0,0 +1,21 @@
import axios from 'axios';
import { createAsyncThunk } from '@reduxjs/toolkit';
import { axiosRetailInstanceData } from '../../AuthenicationToken/AuthenticationToken';
export const getSalesInvoices = createAsyncThunk(
'ListOfInvoices/getSalesInvoices',
async (data) => {
if (
data?.CompId != null &&
data?.CompId != undefined &&
data?.BranchId != null &&
data?.BranchId != undefined &&
data?.AppId != null &&
data?.AppId != undefined
) {
return await axiosRetailInstanceData.get(
`/reprint?CompId=${data?.CompId}&BranchId=${data?.BranchId}&AppId=${data?.AppId}&orderFromDate=${data?.orderFromDate}&orderToDate=${data?.orderToDate}`
);
}
}
);

View File

@ -0,0 +1,50 @@
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit';
import { axiosRetailInstanceData } from '../../AuthenicationToken/AuthenticationToken';
export const gettinghold = createAsyncThunk('gettinghold', async (data) => {
if (
data?.AppId != null &&
data?.AppId != undefined &&
data?.CompId != null &&
data?.CompId != undefined &&
data?.BranchId != null &&
data?.BranchId != undefined
) {
return await axiosRetailInstanceData.get(
`/hold?CompId=${data?.CompId}&BranchId=${data?.BranchId}&AppId=${data?.AppId}`
);
}
});
export const puttinghold = createAsyncThunk('puttinghold', async (putData) => {
return await axiosRetailInstanceData.put(`/hold`, putData);
});
const initialState = {
holddata: [],
};
const HoldOption = createSlice({
name: 'HoldOption',
initialState,
reducers: {
changeholddata: (state, action) => {
state.holddata = action?.payload;
},
},
extraReducers: (builder) => {
builder.addCase(gettinghold.fulfilled, (state, action) => {
if (action?.payload?.status) {
state.holddata = action?.payload?.data?.data;
} else {
state.holddata = [];
}
});
},
});
export const { changeholddata } = HoldOption.actions;
export const globalholddata = (state) => state?.HoldOption?.holddata;
export default HoldOption.reducer;

View File

@ -0,0 +1,197 @@
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';
import { axiosRetailInstanceData } from '../../AuthenicationToken/AuthenticationToken';
export const PreOrderBookingData = createAsyncThunk(
'PreOrder/PreOrderBookingData',
async (postData) => {
return await axiosRetailInstanceData.post(`/PreOrder`, postData);
}
);
export const PreOrderGet = createAsyncThunk(
'PreOrder/PreOrderBookingData',
async (data) => {
if (
data?.compId != null &&
data?.compId != undefined &&
data?.branchId != null &&
data?.branchId != undefined &&
data?.appId != null &&
data?.appId != undefined &&
data?.deliveryStatus != null &&
data?.deliveryStatus != undefined
) {
if (data?.toDate && data?.fromDate) {
return await axiosRetailInstanceData.get(
`/PreOrder?compId=${data?.compId}&branchId=${data?.branchId}&appId=${data?.appId}&deliveryStatus=${data?.deliveryStatus}&fromDate=${data?.fromDate}&toDate=${data?.toDate}`
);
} else {
return await axiosRetailInstanceData.get(
`/PreOrder?compId=${data?.compId}&branchId=${data?.branchId}&appId=${data?.appId}&deliveryStatus=${data?.deliveryStatus}`
);
}
}
}
);
export const PreOrderBookingDataCancel= createAsyncThunk(
'PreOrder/PreOrderBookingDataCancel',
async (Data) => {
return await axiosRetailInstanceData.post(`/PreOrderCancel`, Data);
}
);
export const PreOrderBookingDataPut = createAsyncThunk(
'PreOrder/PreOrderBookingDataPut',
async (putData) => {
return await axiosRetailInstanceData.put(`/PreOrder`, putData);
}
);
const initialState = {
preOrder: false,
PreOrderList: [],
PreOrderAdditem: null,
PreOrderCusName: null,
PreOrderCusMobNo: null,
PreOrderDate: null,
PreOrderTime: null,
PreOrderAdvance: 0,
PreOrderMessage: null,
PreOrderAdd1: null,
PreOrderAdd2: null,
PreOrderzip: null,
PreOrderCity: null,
PreOrderDistrict: null,
PreOrderState: null,
PreOrderReferenceMessage: null,
PreOrderSelectedPaymentOption: null,
PreOrderSelectedUPIOption: null,
PreOrderListedit: [],
PreOrderPendingCount: null,
};
const PreOrder = createSlice({
name: 'PreOrder',
initialState,
reducers: {
changepreOrder: (state, action) => {
state.preOrder = action?.payload;
},
changePreOrderMessage: (state, action) => {
state.PreOrderMessage = action?.payload;
},
changePreOrderAdd1: (state, action) => {
state.PreOrderAdd1 = action?.payload;
},
changePreOrderAdd2: (state, action) => {
state.PreOrderAdd2 = action?.payload;
},
changePreOrderzip: (state, action) => {
state.PreOrderzip = action?.payload;
},
changePreOrderCity: (state, action) => {
state.PreOrderCity = action?.payload;
},
changePreOrderDistrict: (state, action) => {
state.PreOrderDistrict = action?.payload;
},
changePreOrderState: (state, action) => {
state.PreOrderState = action?.payload;
},
changePreOrderReferenceMessage: (state, action) => {
state.PreOrderReferenceMessage = action?.payload;
},
changePreOrderSelectedPaymentOption: (state, action) => {
state.PreOrderSelectedPaymentOption = action?.payload;
},
changePreOrderSelectedUPIOptione: (state, action) => {
state.PreOrderSelectedUPIOption = action?.payload;
},
changepreOrderListedit: (state, action) => {
state.PreOrderListedit = action?.payload;
},
changePreOrderPendingCount: (state, action) => {
state.PreOrderPendingCount = action?.payload;
},
changePreOrderAdvance: (state, action) => {
state.PreOrderAdvance = action?.payload;
},
changePreOrderDate: (state, action) => {
state.PreOrderDate = action?.payload;
},
changePreOrderTime: (state, action) => {
state.PreOrderTime = action?.payload;
},
changePreOrderCusName: (state, action) => {
state.PreOrderCusName = action?.payload;
},
changePreOrderCusMob: (state, action) => {
state.PreOrderCusMobNo = action?.payload;
},
changePreOrderAdditem: (state, action) => {
state.PreOrderAdditem = action?.payload;
},
changepreOrderList: (state, action) => {
state.PreOrderList = action?.payload;
},
},
});
export const {
changepreOrder,
changepreOrderList,
changePreOrderAdditem,
changePreOrderCusName,
changePreOrderCusMob,
changePreOrderDate,
changePreOrderTime,
changePreOrderAdvance,
changePreOrderMessage,
changePreOrderAdd1,
changePreOrderAdd2,
changePreOrderzip,
changePreOrderCity,
changePreOrderDistrict,
changePreOrderState,
changePreOrderReferenceMessage,
changePreOrderSelectedPaymentOption,
changePreOrderSelectedUPIOptione,
changepreOrderListedit,
changePreOrderPendingCount,
} = PreOrder.actions;
export const GlobalpreOrderOpen = (state) => state?.PreOrder?.preOrder;
export const GlobalPreOrderMessage = (state) =>
state?.PreOrder?.PreOrderMessage;
export const GlobalPreOrderListedit = (state) =>
state?.PreOrder?.PreOrderListedit;
export const GlobalPreOrderPendingCount = (state) =>
state?.PreOrder?.PreOrderPendingCount;
export const GlobalPreOrderSelectedPaymentOption = (state) =>
state?.PreOrder?.PreOrderSelectedPaymentOption;
export const GlobaPreOrderSelectedUPIOptione = (state) =>
state?.PreOrder?.PreOrderSelectedUPIOption;
export const GlobalPreOrderReferenceMessage = (state) =>
state?.PreOrder?.PreOrderReferenceMessage;
export const GlobalPreOrderAdd1 = (state) => state?.PreOrder?.PreOrderAdd1;
export const GlobalPreOrderAdd2 = (state) => state?.PreOrder?.PreOrderAdd2;
export const GlobalPreOrderzip = (state) => state?.PreOrder?.PreOrderzip;
export const GlobalPreOrderCity = (state) => state?.PreOrder?.PreOrderCity;
export const GlobalPreOrderDistrict = (state) =>
state?.PreOrder?.PreOrderDistrict;
export const GlobalPreOrderState = (state) => state?.PreOrder?.PreOrderState;
export const GlobalPreOrderAdvance = (state) =>
state?.PreOrder?.PreOrderAdvance;
export const GlobalPreOrderDate = (state) => state?.PreOrder?.PreOrderDate;
export const GlobalPreOrderTime = (state) => state?.PreOrder?.PreOrderTime;
export const GlobalPreOrderCusName = (state) =>
state?.PreOrder?.PreOrderCusName;
export const GlobalPreOrderCusMobNo = (state) =>
state?.PreOrder?.PreOrderCusMobNo;
export const GlobalPreOrderAdditem = (state) =>
state?.PreOrder?.PreOrderAdditem;
export const GlobalPreOrderList = (state) => state?.PreOrder?.PreOrderList;
export default PreOrder.reducer;

View File

@ -0,0 +1,87 @@
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';
import {
axiosRetailInstanceData,
axiosCommonInstanceData,
} from '../../AuthenicationToken/AuthenticationToken';
import { getSession } from '../../../Services/Others';
export const getccavenuePaymentDetails = createAsyncThunk(
'getccavenuePaymentDetails1',
async () => {
return await axiosCommonInstanceData.get(
`/ccavenuePaymentDetails?activeStatus=A`
);
}
);
export const getPaymentUpiDetails = createAsyncThunk(
'getPaymentUpiDeatils1',
async () => {
return await axiosCommonInstanceData.get(
`/paymentUpiDetails?activeStatus=A&type=I`
);
}
);
export const postInvoice = createAsyncThunk('postInvoice', async (postData) => {
return await axiosCommonInstanceData.post(`/userAppMap`, postData);
});
export const getPricingType = createAsyncThunk(
'getPricingType/getPricingType',
async (PricingId) => {
if (PricingId) {
return await axiosCommonInstanceData.get(
`/pricingType?PricingId=${PricingId}`
);
}
}
);
export const getUserDetails = createAsyncThunk(
'getUserDetail/getUserDetails',
async (UserId) => {
if (UserId) {
return await axiosCommonInstanceData.get(`/user?UserId=${UserId}`);
}
}
);
export const getPurchasedAppDetails = createAsyncThunk(
'getPurchasedAppDetails',
async ({ UserId, AppId }) => {
return await axiosCommonInstanceData.get(
`/UserAppMap?AppId=${AppId}&UserId=${UserId}`
);
}
);
export const CheckPaymentStatus = createAsyncThunk(
'SendPaymentLink/SendPaymentLink',
async (BookingId) => {
if (BookingId) {
return await axiosCommonInstanceData.get(
`/userAppMap?UniqueId=${BookingId}&PaymentStatus=S`
);
}
}
);
export const getPaymentValidation = createAsyncThunk(
'getPaymentValidation',
async (data) => {
const UserType = getSession('UserType');
if (UserType !== 'Super Admin' && UserType !== 'Super Admin User') {
return await axiosRetailInstanceData.get(
`/PaymentOptions?compId=${data?.CompId}&appId=${data?.AppId}&branchId=${data?.BranchId}`
);
}
}
);
const initialState = {};
const Pricing = createSlice({
name: 'BookingData',
initialState,
});
export default Pricing.reducer;

View File

@ -0,0 +1,38 @@
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit';
import {
axiosRetailInstanceData,
axiosCommonInstanceData,
} from '../AuthenicationToken/AuthenticationToken';
export const getRetailPaymentClosing = createAsyncThunk(
'RetailBookingClose/getRetailPaymentClosing',
async (data) => {
console.log(data, 'datadata');
if (
data?.AppId != null &&
data?.AppId != undefined &&
data?.CompId != null &&
data?.CompId != undefined &&
data?.BranchId != null &&
data?.BranchId != undefined &&
data?.UserId != null &&
data?.UserId != undefined
) {
return await axiosRetailInstanceData.get(
`/BookingClosingBalance?CompId=${data?.CompId}&BranchId=${data?.BranchId}&AppId=${data?.AppId}&UserId=${data?.UserId}`
);
}
}
);
export const PostBookingClose = createAsyncThunk(
'RetailBookingClose/PostBookingClose',
async (postData) => {
return await axiosRetailInstanceData.post(`/BookingClose`, postData);
}
);
export const PutBookingClose = createAsyncThunk(
'RetailBookingClose/PutBookingClose',
async (putData) => {
return await axiosRetailInstanceData.put(`/BookingClose`, putData);
}
);

View File

@ -0,0 +1,275 @@
import axios from 'axios';
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';
import {
axiosRetailInstanceData,
axiosCommonInstanceData,
} from '../AuthenicationToken/AuthenticationToken';
import { getSession } from '../../Services/Others';
const apiCommonUrl = import.meta.env.ENV_API_URL_COMMON;
export const GenerateLogout = createAsyncThunk(
'signInPage/GenerateLogout',
async ({ UserId, status }) => {
if (UserId) {
return await axiosCommonInstanceData.put(`/Logout`, {
UserId: UserId,
Generate: status,
RequestMode: 'DW',
});
}
}
);
export const checkSession = createAsyncThunk(
'signInPage/checkSession',
async ({ UserId, sessionId }) => {
if (UserId) {
return await axiosCommonInstanceData.get(
`/UserSessionId?UserId=${UserId}&sessionId=${sessionId}`
);
}
}
);
export const PublicQrCodepost = createAsyncThunk(
'BranchLogin/PublicQrCodepost',
async (postData) => {
return await axiosCommonInstanceData.get(
`/URLshortener?referenceNo=${postData}`
);
}
);
export const getCompBranchData = createAsyncThunk(
'BranchData/getBranchData',
async ({ CompId, AppId, UserId }) => {
if (
UserId != null &&
UserId != undefined &&
AppId != null &&
AppId != undefined &&
CompId != null &&
CompId != undefined
) {
return await axiosCommonInstanceData.get(
`/Branch?UserId=${UserId}&AppId=${AppId}&CompId=${CompId}`
);
} else if (
CompId != null &&
CompId != undefined &&
AppId != null &&
AppId != undefined
) {
return await axiosCommonInstanceData.get(
`/Branch?CompId=${CompId}&AppId=${AppId}`
);
}
}
);
export const getBranchDetail = createAsyncThunk(
'BranchData/getBranchDetail',
async (data) => {
if (data?.BrId != null && data?.BrId != undefined) {
return await axiosCommonInstanceData.get(`/Branch?BrId=${data?.BrId}`);
}
}
);
export const getAllBranchDetail = createAsyncThunk(
'BranchData/getAllBranchDetail',
async (data) => {
if (data?.AppId != null && data?.AppId != undefined) {
return await axiosCommonInstanceData.get(`/Branch?appId=${data?.AppId}`);
}
}
);
export const getEmpAccesData = createAsyncThunk(
'EmpAccesData/getEmpAccesData',
async (data) => {
if (
data?.AppId != null &&
data?.AppId != undefined &&
data?.UserId != null &&
data?.UserId != undefined &&
data?.CompId != null &&
data?.CompId != undefined &&
data?.BranchId != null &&
data?.BranchId != undefined
) {
return await axiosRetailInstanceData.get(
`/EmpAccess?empId=${data?.UserId}&AppId=${data?.AppId}&CompId=${data?.CompId}&branchId=${data?.BranchId}`
);
}
}
);
export const PricingAppPricingName = createAsyncThunk(
'BranchData/PricingAppPricingName',
async (data) => {
if (
data?.appId != null &&
data?.appId != undefined &&
data?.compId != null &&
data?.compId != undefined &&
data?.branchId != null &&
data?.branchId != undefined
) {
return await axios.get(
`${apiCommonUrl}/PricingAppFeatMap?appId=${data?.appId}&compId=${data?.compId}&branchId=${data?.branchId}`
);
} else if (
data?.appId != null &&
data?.appId != undefined &&
data?.userId != null &&
data?.userId != undefined
) {
return await axios.get(
`${apiCommonUrl}/PricingAppFeatMap?appId=${data?.appId}&userId=${data?.userId}`
);
}
}
);
export const getSAdminUserAccesData = createAsyncThunk(
'Sadmindata/getSAdminUserAccesData',
async (data) => {
if (
data?.AppId != null &&
data?.AppId != undefined &&
data?.UserId != null &&
data?.UserId != undefined
) {
return await axiosCommonInstanceData.get(
`/AppMenuAccess?UserId=${data?.UserId}&AppId=${data?.AppId}`
);
}
}
);
export const getApplicationDetails = createAsyncThunk(
'BranchData/getApplicationDetails',
async ({ AppId }) => {
if (AppId) {
return await axios.get(`${apiCommonUrl}/application?AppId=${AppId}`);
}
}
);
export const PostLoginSuser = createAsyncThunk(
'BranchData/PostLoginSuser',
async (postData) => {
return await axiosCommonInstanceData.post(
`/SuperAdminUserBranchSignIn`,
postData
);
}
);
export const PUTLoginuser = createAsyncThunk(
'BranchData/PostLoginSuser',
async (putData) => {
return await axiosCommonInstanceData.put(
`/SuperAdminUserBranchSignIn`,
putData
);
}
);
export const putSadminUserExit = createAsyncThunk(
'BranchData/putSadminUserExit',
async (putData) => {
return await axiosCommonInstanceData.put(
`/SuperAdminUserBranchSignInEmp`,
putData
);
}
);
export const getLoginuser = createAsyncThunk(
'BranchData/getLoginuser',
async (getdata) => {
return await axiosCommonInstanceData.get(
`/SuperAdminUserBranchSignIn?userId=${getdata.UserId}&sessionId=${getdata.sessionId}&branchId=${getdata.BranchId}`
);
}
);
export const getCommonAppPreference = createAsyncThunk(
'/getAppPreference',
async (AppId) => {
if (
AppId != null &&
AppId != undefined
){
return await axiosCommonInstanceData.get(
`/ApplicationPreferenceMapping?AppId=${AppId}`
);
}
}
);
const initialState = {
SelectedBrachId: null,
CompBranchData: null,
SadminUserPin: [],
SadminUserData: [],
AppPreferences: [],
isWarehouse:false,
};
const BranchLogin = createSlice({
name: 'BranchLogin',
initialState,
reducers: {
changeSelectedBranchId: (state, action) => {
state.SelectedBrachId = action?.payload;
},
changeWarehouse:(state,action)=>{
state.isWarehouse=action?.payload
}
},
extraReducers: (builder) => {
builder.addCase(getCompBranchData.fulfilled, (state, action) => {
if (action?.payload?.status) {
state.CompBranchData = action?.payload?.data?.data;
}
});
builder.addCase(checkSession.fulfilled, (state, action) => {
if (action?.payload?.status) {
if (action?.payload?.data?.data?.length > 0) {
state.SadminUserPin = action?.payload?.data?.data?.filter(
(item) =>
item?.AppId == getSession('AppId') &&
item?.CompId == getSession('CompId') &&
item?.BranchId == getSession('BranchId')
);
state.SadminUserData = action?.payload?.data?.data;
} else {
state.SadminUserPin = [];
}
}
});
builder.addCase(getCommonAppPreference.fulfilled, (state, action) => {
if (action?.payload?.status === 200) {
const { data: result } = action?.payload;
if (result?.data?.length > 0) {
state.AppPreferences = result?.data?.[0]?.PreferenceDetails;
} else {
state.AppPreferences = [];
}
}
});
},
});
export const { changeSelectedBranchId ,changeWarehouse} = BranchLogin.actions;
export const GlobalSelectedBranchId = (state) =>
state?.BranchLogin?.SelectedBrachId;
export const GlobalCompBranchData = (state) =>
state?.BranchLogin?.CompBranchData;
export const GLobalSadminUserPin = (state) => state?.BranchLogin?.SadminUserPin;
export const GLobalSadminUserData = (state) =>
state?.BranchLogin?.SadminUserData;
export const ApplicationPreferences = (state) =>
state?.BranchLogin?.AppPreferences;
export const globalBranchType = (state) =>
state?.BranchLogin?.isWarehouse;
export default BranchLogin.reducer;

View File

@ -0,0 +1,116 @@
import { createAsyncThunk } from '@reduxjs/toolkit';
import { axiosRetailInstanceData } from '../AuthenicationToken/AuthenticationToken';
export const getProdListBasedOnCat = createAsyncThunk(
'CancelApplicableProd/getProdListBasedOnCat',
async (data) => {
if (
data?.CompId != null &&
data?.CompId != undefined &&
data?.BranchId != null &&
data?.BranchId != undefined &&
data?.AppId != null &&
data?.AppId != undefined &&
data?.ProdCat != null &&
data?.ProdCat != undefined &&
data?.type != null &&
data?.type != undefined
) {
return await axiosRetailInstanceData.get(
`/productCardList?CompId=${data?.CompId}&BranchId=${data?.BranchId}&AppId=${data?.AppId}&ProdCat=${data?.ProdCat}&Type=${data?.type}`
);
}
}
);
export const putCancelAppProd = createAsyncThunk(
'CancelApplicableProd/putCancelAppProd',
async (putData) => {
return await axiosRetailInstanceData.put(
`/CancelApplicableProducts`,
putData
);
}
);
export const getSalesReturn = createAsyncThunk(
'CancelApplicableProd/getProdListBasedOnCat',
async (data) => {
const { CompId, BranchId, AppId } = data;
if (
CompId != null &&
CompId != undefined &&
BranchId != null &&
BranchId != undefined &&
AppId != null &&
AppId != undefined
) {
return await axiosRetailInstanceData.get(
`/SalesReturn?appId=${AppId}&compId=${CompId}&branchId=${BranchId}`
);
}
}
);
export const getRescheduledSlot = createAsyncThunk(
'RescheduledSlot/getRescheduledSlot',
async (data) => {
const { CompId, BranchId, AppId } = data;
if (
CompId != null &&
CompId != undefined &&
BranchId != null &&
BranchId != undefined &&
AppId != null &&
AppId != undefined
) {
return await axiosRetailInstanceData.get(
`/Sales/RescheduledSlotGet?appId=${AppId}&compId=${CompId}&branchId=${BranchId}`
);
}
}
);
export const postSalesReturn = createAsyncThunk(
'CancelApplicableProd/postSalesReturn',
async (postData) => {
return await axiosRetailInstanceData.post(
`/SalesReturn`,
postData
);
}
);
export const postRescheduleSlot = createAsyncThunk(
'RescheduleSlot/SlotReschedule',
async (postData) => {
return await axiosRetailInstanceData.post(
`/SlotReschedule`,
postData
);
}
);
export const getProductReturnPolicy = createAsyncThunk(
'CancelApplicableProd/getProductReturnPolicy',
async (data) => {
const { CompId, BranchId, AppId, SalesId } = data;
if (
CompId != null &&
CompId != undefined &&
BranchId != null &&
BranchId != undefined &&
AppId != null &&
AppId != undefined &&
SalesId != null &&
SalesId != undefined
) {
return await axiosRetailInstanceData.get(
`ReturnExchangePolicyMapping/Eligibility?appId=${AppId}&compId=${CompId}&branchId=${BranchId}&salesId=${SalesId}`
);
}
}
);

View File

@ -0,0 +1,165 @@
import { createAsyncThunk } from '@reduxjs/toolkit';
import { axiosRetailInstanceData } from '../AuthenicationToken/AuthenticationToken';
export const productname = createAsyncThunk('productname', async (data) => {
if (
data?.CompId != null &&
data?.CompId != undefined &&
data?.BranchId != null &&
data?.BranchId != undefined &&
data?.AppId != null &&
data?.AppId != undefined
) {
return await axiosRetailInstanceData.get(
`/Offer/ProductDtl?CompId=${data?.CompId}&BranchId=${data?.BranchId}&AppId=${data?.AppId}`
);
}
});
export const getCombolist = createAsyncThunk('getCombo', async (data) => {
if (
data?.CompId != null &&
data?.CompId != undefined &&
data?.BranchId != null &&
data?.BranchId != undefined &&
data?.AppId != null &&
data?.AppId != undefined &&
data?.ActiveStatus != null &&
data?.ActiveStatus != undefined
) {
return await axiosRetailInstanceData.get(
`/comboHdr?CompId=${data?.CompId}&BranchId=${data?.BranchId}&AppId=${data?.AppId}&ActiveStatus=${data?.ActiveStatus}`
);
} else {
return await axiosRetailInstanceData.get(
`/comboHdr?CompId=${data?.CompId}&BranchId=${data?.BranchId}&AppId=${data?.AppId}`
);
}
});
export const getCombo = createAsyncThunk('getCombo', async (data) => {
if (
data?.CompId != null &&
data?.CompId != undefined &&
data?.BranchId != null &&
data?.BranchId != undefined &&
data?.AppId != null &&
data?.AppId != undefined
) {
return await axiosRetailInstanceData.get(
`/comboHdr?CompId=${data?.CompId}&BranchId=${data?.BranchId}&AppId=${data?.AppId}&type=${data?.type}`
);
}
});
export const getComboProddata = createAsyncThunk('getCombo', async (data) => {
if (
data?.CompId != null &&
data?.CompId != undefined &&
data?.BranchId != null &&
data?.BranchId != undefined &&
data?.AppId != null &&
data?.AppId != undefined
) {
return await axiosRetailInstanceData.get(
`/comboHdr?CompId=${data?.CompId}&BranchId=${data?.BranchId}&AppId=${data?.AppId}&comboId=${data?.comboId}`
);
}
});
export const productqrqty = createAsyncThunk('productqrqty', async (data) => {
if (data?.ProdId != null && data?.ProdId != undefined) {
return await axiosRetailInstanceData.get(`/product?ProdId=${data?.ProdId}`);
}
});
export const postCombo = createAsyncThunk(
'postCombo/postCombo',
async (postData) => {
return await axiosRetailInstanceData.post(`/comboHdr`, postData);
}
);
export const putCombo = createAsyncThunk(
'putCombo/putCombo',
async (putData) => {
return await axiosRetailInstanceData.put(`/comboHdr`, putData);
}
);
export const deleteCombo = createAsyncThunk(
'deleteCombo/deleteCombo',
async (putData) => {
return await axiosRetailInstanceData.put(`/DeleteCombo`, putData);
}
);
export const getProdvaraiantdata = createAsyncThunk(
'product/getProdcataloguedata',
async (data) => {
if (
data?.CompId != null &&
data?.CompId != undefined &&
data?.BranchId != null &&
data?.BranchId != undefined &&
data?.AppId != null &&
data?.AppId != undefined &&
data?.prodName != null &&
data?.prodName != undefined
) {
return await axiosRetailInstanceData.get(
`/ProductCardList?CompId=${data?.CompId}&BranchId=${data?.BranchId}&AppId=${data?.AppId} &prodName=${encodeURIComponent(data?.prodName)}`
);
}
}
);
export const getPurProdvaraiantdata = createAsyncThunk(
'PurchaseOrder/getPurProdvaraiantdata',
async (data) => {
if (
data?.CompId !== null &&
data?.CompId !== undefined &&
data?.BranchId !== null &&
data?.BranchId !== undefined &&
data?.AppId !== null &&
data?.AppId !== undefined &&
data?.prodName !== null &&
data?.prodName !== undefined
) {
return await axiosRetailInstanceData.get(
`/ProductCardList?CompId=${data?.CompId}&BranchId=${data?.BranchId}&AppId=${data?.AppId}&prodName=${encodeURIComponent(data?.prodName)}`
);
}
}
);
export const getProdInwarddata = createAsyncThunk(
'getProdInwarddata',
async (data) => {
return await axiosRetailInstanceData.get(
`/InwardDtl?CompId=${data?.CompId}&BranchId=${data?.BranchId}&AppId=${data?.AppId}&prodId=${data?.prodId}`
);
}
);
export const putComboStockdel = createAsyncThunk(
'putComboStockdel/putComboStockdel',
async (putData) => {
return await axiosRetailInstanceData.put(`/ComboStock`, putData);
}
);
export const putComboPriceoffer = createAsyncThunk(
'putComboPriceoffer/putComboPriceoffer',
async (putData) => {
return await axiosRetailInstanceData.put(`/ComboHdr`, putData);
}
);
export const putComboName = createAsyncThunk(
'putComboName',
async (putData) => {
return await axiosRetailInstanceData.put(`/ComboNameChange`, putData);
}
);

Some files were not shown because too many files have changed in this diff Show More