first_push

This commit is contained in:
karimalden 2024-06-09 16:50:07 +03:00
parent 088039da0b
commit eee88e7482
282 changed files with 15675 additions and 0 deletions

24
.gitignore vendored Normal file
View File

@ -0,0 +1,24 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
# testing
/coverage
# production
/build
# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
pnpm-lock.ymal
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-lock.yaml

11
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,11 @@
{
"cSpell.words": [
"aldeen",
"Datepicker",
"formik",
"Karim",
"queryqlent",
"szhsin",
"Viewelement"
]
}

76
db.json Normal file
View File

@ -0,0 +1,76 @@
{
"example": [
{
"id": 1,
"name": "ibrahim",
"email": "ibrahim@gmail.com"
},
{
"id": 2,
"name": "gregr",
"email": "ibrahimgmail.com"
},
{
"id": 3,
"name": "mhmad",
"email": "mhmad@gmial.com"
},
{
"id": 4,
"name": "soso",
"email": "soso@gmail.com"
},
{
"id": 5,
"name": "few",
"email": "jfpwrej"
},
{
"id": 6,
"name": "sos",
"email": "fdwf"
},
{
"id": 7,
"name": "sos",
"email": "fdwf"
},
{
"id": 8,
"name": "sos",
"email": "fdwf"
}
],
"test2":[
{
"id":1,
"email":"admin@adamin.com"
}
,
{
"id":1,
"email":"admin@adamin.com"
}
,
{
"id":1,
"email":"admin@adamin.com"
}
, {
"id":1,
"email":"admin@adamin.com"
}
],
"users": [
{
"id": 1,
"email": "admin@adamin.com",
"password": "password",
"token": "token"
}
]
}

104
package.json Normal file
View File

@ -0,0 +1,104 @@
{
"name": "my-app",
"version": "0.1.0",
"private": true,
"dependencies": {
"@ant-design/icons": "^4.8.3",
"@emotion/styled": "^11.11.0",
"@mui/icons-material": "^5.14.19",
"@mui/x-charts": "^6.19.4",
"@react-google-maps/api": "^2.19.2",
"@szhsin/react-menu": "github:szhsin/react-menu",
"@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"@tinymce/tinymce-react": "^4.3.2",
"@types/jest": "^27.5.2",
"@types/node": "^16.18.60",
"@types/react": "^18.2.33",
"@types/react-dom": "^18.2.14",
"@types/socket.io-client": "^3.0.0",
"@wojtekmaj/react-daterange-picker": "^5.4.4",
"antd": "^5.12.1",
"apexcharts": "^3.44.2",
"axios": "^1.6.0",
"bootstrap": "^5.3.2",
"chart.js": "^4.4.0",
"dayjs": "^1.11.10",
"formik": "^2.4.5",
"history": "^5.3.0",
"i18next": "^23.6.0",
"i18next-browser-languagedetector": "^7.1.0",
"json-server": "^0.17.4",
"moment": "^2.30.1",
"prop-types": "^15.8.1",
"react": "^18.2.0",
"react-apexcharts": "^1.4.1",
"react-bootstrap": "^2.9.1",
"react-bootstrap-sweetalert": "^5.2.0",
"react-chartjs-2": "^5.2.0",
"react-confirm-alert": "^3.0.6",
"react-data-table-component": "^7.5.4",
"react-dom": "^18.2.0",
"react-feather": "^2.0.10",
"react-i18next": "^13.3.1",
"react-icons": "^4.11.0",
"react-input-range": "^1.3.0",
"react-number-format": "^5.3.4",
"react-query": "^3.39.3",
"react-redux": "^8.1.3",
"react-router-dom": "^6.18.0",
"react-scripts": "5.0.1",
"react-select": "^5.7.7",
"react-simple-star-rating": "^5.1.7",
"react-switch": "^7.0.0",
"react-tabs": "^6.0.2",
"react-toastify": "^9.1.3",
"react-toggle": "^4.1.3",
"reactstrap": "^9.2.0",
"redux": "^4.2.1",
"sass": "^1.69.5",
"socket.io-client": "^4.7.2",
"styled-components": "5.3.3",
"ts-xlsx": "^0.0.11",
"typescript": "^4.9.5",
"web-vitals": "^2.1.4",
"xlsx": "^0.18.5",
"yup": "^1.3.2",
"zustand": "^4.4.5"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"g:api": "node src/Extensions/FileGenerator/generateApi.js",
"g:column": "node src/Extensions/FileGenerator/generateColumn.js",
"g:formutil": "node src/Extensions/FileGenerator/generateformUtils.js",
"g:page": "node src/Extensions/FileGenerator/generatePage.js",
"g:dashboard": "node src/Extensions/FileGenerator/generateDashboard.js ",
"g:modal:add": "node src/Extensions/FileGenerator/generateEditModal.js ",
"g:model:edit": "node src/Extensions/FileGenerator/generateEditModal.js "
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"@types/react-toggle": "^4.0.5"
}
}

BIN
public/Layout/LoginBg.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
public/Logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

11
public/Logo.svg Normal file
View File

@ -0,0 +1,11 @@
<svg width="72" height="34" viewBox="0 0 72 34" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_2001_4350)">
<path d="M34.9514 12.9924C34.4047 16.0388 33.9491 18.929 33.116 21.6629C31.3456 27.5058 27.9089 31.2239 22.7931 32.6143C21.1138 33.0674 19.4215 33.2236 17.7032 33.2236C12.0406 33.2236 6.37794 33.2236 0.71531 33.2392C0.181591 33.2392 -0.0136719 33.1455 -0.0136719 32.4112C0.0123632 26.2091 0.0123632 20.0226 -0.0136719 13.8204C-0.0136719 13.2268 0.103486 13.0393 0.624188 13.0393C2.99338 13.0706 5.34955 13.0706 7.71875 13.0393C8.23945 13.0393 8.40868 13.1643 8.40868 13.8361C8.36962 17.273 8.40868 20.71 8.38264 24.1469C8.38264 24.7562 8.4998 24.9437 9.03352 24.928C12.0276 24.8968 15.0216 24.9437 18.0156 24.8968C20.3848 24.8656 22.5978 24.2407 24.3812 22.1785C25.3835 21.038 25.7871 19.5539 26.1646 18.0229C27.2451 13.5705 28.3255 9.10244 29.432 4.65003C30.3042 1.18183 32.9598 -0.521025 35.7715 0.556928C37.0863 1.05685 37.9715 2.18167 38.6094 3.57207C41.4862 9.75858 44.5454 15.8201 47.1879 22.1629C47.227 22.2566 47.266 22.3347 47.3571 22.5066C47.6045 21.8973 47.8128 21.3505 48.0471 20.8037C50.6246 14.9453 53.3973 9.2118 56.131 3.46271C57.667 0.244478 60.6871 -0.661628 63.1865 1.19745C64.2539 1.9942 64.8788 3.18151 65.2172 4.58753C66.9616 11.8051 68.6799 19.0071 70.4112 26.2247C70.9189 28.3337 71.4136 30.4428 71.9343 32.5362C72.0514 33.0205 72.0775 33.2392 71.5307 33.2392C69.1225 33.1923 66.7142 33.208 64.306 33.2392C63.8894 33.2392 63.7462 33.0517 63.6551 32.6299C62.3794 26.5997 60.8694 20.6475 59.6848 14.6016C59.5936 14.1329 59.5155 13.6642 59.3984 13.0237C59.1771 13.5236 59.0209 13.8673 58.8777 14.2266C56.6907 19.7101 54.2434 25.0218 51.8742 30.3803C50.4293 33.6454 48.3204 34.2703 45.1962 33.3954C44.0897 33.083 43.3347 32.0675 42.814 30.9115C41.33 27.6776 39.8721 24.4125 38.4401 21.1318C37.3206 18.5384 36.11 16.0076 35.1337 13.3205C35.0816 13.258 35.0556 13.1955 34.9514 12.9924Z" fill="red"/>
<path d="M24.1476 11.8056C22.0778 9.71216 19.6825 9.16537 17.1051 9.181C11.4685 9.22786 5.83188 9.19662 0.078125 9.19662C0.559774 8.43112 0.989353 7.74373 1.41893 7.05634C2.62956 5.13477 3.85321 3.2132 5.05082 1.27601C5.24609 0.963559 5.44135 0.791711 5.79282 0.807334C10.5182 0.869824 15.2436 0.682354 19.9689 0.932314C22.0387 1.04167 24.0434 1.63533 25.983 2.57268C26.3605 2.76015 26.3345 2.94762 26.2434 3.32256C25.5404 6.11899 24.8635 8.89979 24.1476 11.8056Z" fill="#AFB0B6"/>
</g>
<defs>
<clipPath id="clip0_2001_4350">
<rect width="72" height="33.5103" fill="white" transform="translate(0 0.244873)"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

BIN
public/Logo_2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

17
public/index.html Normal file
View File

@ -0,0 +1,17 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<title>Hijab - App</title>
</head>
<body>
<div id="root"></div>
</body>
</html>

1
public/language/ar.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 10 KiB

View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<svg width="800px" height="800px" viewBox="0 0 36 36" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--twemoji" preserveAspectRatio="xMidYMid meet"><path fill="#DE2910" d="M36 27a4 4 0 0 1-4 4H4a4 4 0 0 1-4-4V9a4 4 0 0 1 4-4h28a4 4 0 0 1 4 4v18z"></path><path fill="#FFDE02" d="M11.136 8.977l.736.356l.589-.566l-.111.81l.72.386l-.804.144l-.144.804l-.386-.72l-.81.111l.566-.589zm4.665 2.941l-.356.735l.566.59l-.809-.112l-.386.721l-.144-.805l-.805-.144l.721-.386l-.112-.809l.59.566zm-.957 3.779l.268.772l.817.017l-.651.493l.237.783l-.671-.467l-.671.467l.236-.783l-.651-.493l.817-.017zm-3.708 3.28l.736.356l.589-.566l-.111.81l.72.386l-.804.144l-.144.804l-.386-.72l-.81.111l.566-.589zM7 10.951l.929 2.671l2.826.058l-2.253 1.708l.819 2.706L7 16.479l-2.321 1.615l.819-2.706l-2.253-1.708l2.826-.058z"></path></svg>

After

Width:  |  Height:  |  Size: 1009 B

1
public/language/de.svg Normal file
View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 55.2 38.4"><g fill-rule="evenodd" clip-rule="evenodd"><path d="M3.03 0h49.13c1.67 0 3.03 1.36 3.03 3.03v32.33c0 1.66-1.36 3.02-3.02 3.03H3.02C1.36 38.4 0 37.03 0 35.37V3.03C0 1.36 1.36 0 3.03 0z"/><path d="M0 12.8h55.2v22.57c0 1.67-1.36 3.03-3.03 3.03H3.03C1.36 38.4 0 37.04 0 35.37V12.8z" fill="#d00"/><path d="M0 25.6h55.2v9.77c0 1.66-1.36 3.02-3.02 3.03H3.03A3.04 3.04 0 010 35.37V25.6z" fill="#ffce00"/></g></svg>

After

Width:  |  Height:  |  Size: 470 B

1
public/language/en.svg Normal file
View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="42.67" height="32" viewBox="0 0 640 480"><defs><clipPath id="flagUm4x30"><path fill-opacity=".7" d="M0 0h682.7v512H0z"/></clipPath></defs><g fill-rule="evenodd" clip-path="url(#flagUm4x30)" transform="scale(.9375)"><g stroke-width="1pt"><path fill="#bd3d44" d="M0 0h972.8v39.4H0zm0 78.8h972.8v39.4H0zm0 78.7h972.8V197H0zm0 78.8h972.8v39.4H0zm0 78.8h972.8v39.4H0zm0 78.7h972.8v39.4H0zm0 78.8h972.8V512H0z"/><path fill="#fff" d="M0 39.4h972.8v39.4H0zm0 78.8h972.8v39.3H0zm0 78.7h972.8v39.4H0zm0 78.8h972.8v39.4H0zm0 78.8h972.8v39.4H0zm0 78.7h972.8v39.4H0z"/></g><path fill="#192f5d" d="M0 0h389.1v275.7H0z"/><path fill="#fff" d="M32.4 11.8L36 22.7h11.4l-9.2 6.7l3.5 11l-9.3-6.8l-9.2 6.7l3.5-10.9l-9.3-6.7H29zm64.9 0l3.5 10.9h11.5l-9.3 6.7l3.5 11l-9.2-6.8l-9.3 6.7l3.5-10.9l-9.2-6.7h11.4zm64.8 0l3.6 10.9H177l-9.2 6.7l3.5 11l-9.3-6.8l-9.2 6.7l3.5-10.9l-9.3-6.7h11.5zm64.9 0l3.5 10.9H242l-9.3 6.7l3.6 11l-9.3-6.8l-9.3 6.7l3.6-10.9l-9.3-6.7h11.4zm64.8 0l3.6 10.9h11.4l-9.2 6.7l3.5 11l-9.3-6.8l-9.2 6.7l3.5-10.9l-9.2-6.7h11.4zm64.9 0l3.5 10.9h11.5l-9.3 6.7l3.6 11l-9.3-6.8l-9.3 6.7l3.6-10.9l-9.3-6.7h11.5zM64.9 39.4l3.5 10.9h11.5L70.6 57L74 67.9l-9-6.7l-9.3 6.7L59 57l-9-6.7h11.4zm64.8 0l3.6 10.9h11.4l-9.3 6.7l3.6 10.9l-9.3-6.7l-9.3 6.7L124 57l-9.3-6.7h11.5zm64.9 0l3.5 10.9h11.5l-9.3 6.7l3.5 10.9l-9.2-6.7l-9.3 6.7l3.5-10.9l-9.2-6.7H191zm64.8 0l3.6 10.9h11.4l-9.3 6.7l3.6 10.9l-9.3-6.7l-9.2 6.7l3.5-10.9l-9.3-6.7H256zm64.9 0l3.5 10.9h11.5L330 57l3.5 10.9l-9.2-6.7l-9.3 6.7l3.5-10.9l-9.2-6.7h11.4zM32.4 66.9L36 78h11.4l-9.2 6.7l3.5 10.9l-9.3-6.8l-9.2 6.8l3.5-11l-9.3-6.7H29zm64.9 0l3.5 11h11.5l-9.3 6.7l3.5 10.9l-9.2-6.8l-9.3 6.8l3.5-11l-9.2-6.7h11.4zm64.8 0l3.6 11H177l-9.2 6.7l3.5 10.9l-9.3-6.8l-9.2 6.8l3.5-11l-9.3-6.7h11.5zm64.9 0l3.5 11H242l-9.3 6.7l3.6 10.9l-9.3-6.8l-9.3 6.8l3.6-11l-9.3-6.7h11.4zm64.8 0l3.6 11h11.4l-9.2 6.7l3.5 10.9l-9.3-6.8l-9.2 6.8l3.5-11l-9.2-6.7h11.4zm64.9 0l3.5 11h11.5l-9.3 6.7l3.6 10.9l-9.3-6.8l-9.3 6.8l3.6-11l-9.3-6.7h11.5zM64.9 94.5l3.5 10.9h11.5l-9.3 6.7l3.5 11l-9.2-6.8l-9.3 6.7l3.5-10.9l-9.2-6.7h11.4zm64.8 0l3.6 10.9h11.4l-9.3 6.7l3.6 11l-9.3-6.8l-9.3 6.7l3.6-10.9l-9.3-6.7h11.5zm64.9 0l3.5 10.9h11.5l-9.3 6.7l3.5 11l-9.2-6.8l-9.3 6.7l3.5-10.9l-9.2-6.7H191zm64.8 0l3.6 10.9h11.4l-9.2 6.7l3.5 11l-9.3-6.8l-9.2 6.7l3.5-10.9l-9.3-6.7H256zm64.9 0l3.5 10.9h11.5l-9.3 6.7l3.5 11l-9.2-6.8l-9.3 6.7l3.5-10.9l-9.2-6.7h11.4zM32.4 122.1L36 133h11.4l-9.2 6.7l3.5 11l-9.3-6.8l-9.2 6.7l3.5-10.9l-9.3-6.7H29zm64.9 0l3.5 10.9h11.5l-9.3 6.7l3.5 10.9l-9.2-6.7l-9.3 6.7l3.5-10.9l-9.2-6.7h11.4zm64.8 0l3.6 10.9H177l-9.2 6.7l3.5 11l-9.3-6.8l-9.2 6.7l3.5-10.9l-9.3-6.7h11.5zm64.9 0l3.5 10.9H242l-9.3 6.7l3.6 11l-9.3-6.8l-9.3 6.7l3.6-10.9l-9.3-6.7h11.4zm64.8 0l3.6 10.9h11.4l-9.2 6.7l3.5 11l-9.3-6.8l-9.2 6.7l3.5-10.9l-9.2-6.7h11.4zm64.9 0l3.5 10.9h11.5l-9.3 6.7l3.6 11l-9.3-6.8l-9.3 6.7l3.6-10.9l-9.3-6.7h11.5zM64.9 149.7l3.5 10.9h11.5l-9.3 6.7l3.5 10.9l-9.2-6.8l-9.3 6.8l3.5-11l-9.2-6.7h11.4zm64.8 0l3.6 10.9h11.4l-9.3 6.7l3.6 10.9l-9.3-6.8l-9.3 6.8l3.6-11l-9.3-6.7h11.5zm64.9 0l3.5 10.9h11.5l-9.3 6.7l3.5 10.9l-9.2-6.8l-9.3 6.8l3.5-11l-9.2-6.7H191zm64.8 0l3.6 10.9h11.4l-9.2 6.7l3.5 10.9l-9.3-6.8l-9.2 6.8l3.5-11l-9.3-6.7H256zm64.9 0l3.5 10.9h11.5l-9.3 6.7l3.5 10.9l-9.2-6.8l-9.3 6.8l3.5-11l-9.2-6.7h11.4zM32.4 177.2l3.6 11h11.4l-9.2 6.7l3.5 10.8l-9.3-6.7l-9.2 6.7l3.5-10.9l-9.3-6.7H29zm64.9 0l3.5 11h11.5l-9.3 6.7l3.6 10.8l-9.3-6.7l-9.3 6.7l3.6-10.9l-9.3-6.7h11.4zm64.8 0l3.6 11H177l-9.2 6.7l3.5 10.8l-9.3-6.7l-9.2 6.7l3.5-10.9l-9.3-6.7h11.5zm64.9 0l3.5 11H242l-9.3 6.7l3.6 10.8l-9.3-6.7l-9.3 6.7l3.6-10.9l-9.3-6.7h11.4zm64.8 0l3.6 11h11.4l-9.2 6.7l3.5 10.8l-9.3-6.7l-9.2 6.7l3.5-10.9l-9.2-6.7h11.4zm64.9 0l3.5 11h11.5l-9.3 6.7l3.6 10.8l-9.3-6.7l-9.3 6.7l3.6-10.9l-9.3-6.7h11.5zM64.9 204.8l3.5 10.9h11.5l-9.3 6.7l3.5 11l-9.2-6.8l-9.3 6.7l3.5-10.9l-9.2-6.7h11.4zm64.8 0l3.6 10.9h11.4l-9.3 6.7l3.6 11l-9.3-6.8l-9.3 6.7l3.6-10.9l-9.3-6.7h11.5zm64.9 0l3.5 10.9h11.5l-9.3 6.7l3.5 11l-9.2-6.8l-9.3 6.7l3.5-10.9l-9.2-6.7H191zm64.8 0l3.6 10.9h11.4l-9.2 6.7l3.5 11l-9.3-6.8l-9.2 6.7l3.5-10.9l-9.3-6.7H256zm64.9 0l3.5 10.9h11.5l-9.3 6.7l3.5 11l-9.2-6.8l-9.3 6.7l3.5-10.9l-9.2-6.7h11.4zM32.4 232.4l3.6 10.9h11.4l-9.2 6.7l3.5 10.9l-9.3-6.7l-9.2 6.7l3.5-11l-9.3-6.7H29zm64.9 0l3.5 10.9h11.5L103 250l3.6 10.9l-9.3-6.7l-9.3 6.7l3.6-11l-9.3-6.7h11.4zm64.8 0l3.6 10.9H177l-9 6.7l3.5 10.9l-9.3-6.7l-9.2 6.7l3.5-11l-9.3-6.7h11.5zm64.9 0l3.5 10.9H242l-9.3 6.7l3.6 10.9l-9.3-6.7l-9.3 6.7l3.6-11l-9.3-6.7h11.4zm64.8 0l3.6 10.9h11.4l-9.2 6.7l3.5 10.9l-9.3-6.7l-9.2 6.7l3.5-11l-9.2-6.7h11.4zm64.9 0l3.5 10.9h11.5l-9.3 6.7l3.6 10.9l-9.3-6.7l-9.3 6.7l3.6-11l-9.3-6.7h11.5z"/></g></svg>

After

Width:  |  Height:  |  Size: 4.5 KiB

25
public/manifest.json Normal file
View File

@ -0,0 +1,25 @@
{
"short_name": "React App",
"name": "Create React App Sample",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
},
{
"src": "logo192.png",
"type": "image/png",
"sizes": "192x192"
},
{
"src": "logo512.png",
"type": "image/png",
"sizes": "512x512"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}

3
public/robots.txt Normal file
View File

@ -0,0 +1,3 @@
# https://www.robotstxt.org/robotstxt.html
User-agent: *
Disallow:

69
src/App.tsx Normal file
View File

@ -0,0 +1,69 @@
import { Fragment, lazy, Suspense } from 'react';
import { Route, Routes } from 'react-router-dom'
import Loading from './Components/Utils/Loading/Loading';
import { RoutesLinks } from './Routes';
import Layout from './Layout/app/Layout';
import Auth from './Pages/Auth/Page';
const Page404 = lazy(() => import("./Layout/app/NotFoundPage"))
const App = () => {
return (
<Routes >
{/* 404 Page */}
<Route path="*" element={<Suspense fallback={<Loading />}> <Page404 /></Suspense>} />
{/* Login Page */}
<Route path="/auth" element={<Suspense fallback={<Loading />}> <Auth /></Suspense>} />
{/* route not in navigation */}
{/* All Routes */}
{RoutesLinks?.map((item: any, index: number) => (
<Fragment key={index}>
if(item?.element){
<Route
key={index}
path={item.href}
element={
<Suspense fallback={<Loading />} >
<Layout>
{item?.element ?? "Please Add Element Props in Routes"}
</Layout>
</Suspense>
}
/>
}else{
item?.children?.map((item:any)=>{
return(
<Route
path={item.href}
element={
<Suspense fallback={<Loading />} >
<Layout>
{item?.element ?? "Please Add Element Props in Routes"}
</Layout>
</Suspense>
}
/>
)
})
}
</Fragment>
))
}
</Routes>
)
}
export default App

View File

@ -0,0 +1,86 @@
import {
DownloadOutlined,
RotateLeftOutlined,
RotateRightOutlined,
SwapOutlined,
ZoomInOutlined,
ZoomOutOutlined,
} from '@ant-design/icons';
import React from 'react';
import { Image, Space } from 'antd';
import { ImageBaseURL } from '../../api/config';
import useImageError from '../../Hooks/useImageError';
const ColumnsImage= ({src}:any) => {
const ErrorImage = "https://upload.wikimedia.org/wikipedia/commons/thumb/6/65/No-Image-Placeholder.svg/832px-No-Image-Placeholder.svg.png"
const imageUrl = ImageBaseURL + src || ErrorImage;
console.log(imageUrl);
const handleError = useImageError;
// or you can download flipped and rotated image
// https://codesandbox.i`o/s/zi-ding-yi-gong-ju-lan-antd-5-7-0-forked-c9jvmp
const onDownload = () => {
fetch(src)
.then((response) => response.blob())
.then((blob) => {
const url = URL.createObjectURL(new Blob([blob]));
const link = document.createElement('a');
link.href = url;
link.download = 'image.png';
document.body.appendChild(link);
link.click();
URL.revokeObjectURL(url);
link.remove();
});
};
return (
<Image
width={45}
height={45}
src={imageUrl }
className='p-1 mb-1 columnImage '
preview={{
toolbarRender: (
_,
{
transform: { scale },
actions: { onFlipY, onFlipX, onRotateLeft, onRotateRight, onZoomOut, onZoomIn },
},
) => (
<Space size={12} className="toolbar-wrapper">
<DownloadOutlined onClick={onDownload} />
<SwapOutlined rotate={90} onClick={onFlipY} />
<SwapOutlined onClick={onFlipX} />
<RotateLeftOutlined onClick={onRotateLeft} />
<RotateRightOutlined onClick={onRotateRight} />
<ZoomOutOutlined disabled={scale === 1} onClick={onZoomOut} />
<ZoomInOutlined disabled={scale === 50} onClick={onZoomIn} />
</Space>
),
}}
onError={handleError}
/>
);
};
export default ColumnsImage;
// {
// name: t("image"),
// center: "true",
// cell: (row: any) => {
// return (
// <ColumnsImage src={row?.image} />
// )
// }
// },

View File

@ -0,0 +1,42 @@
import { Switch } from 'antd'
import React from 'react'
import { CheckOutlined, CloseOutlined } from '@ant-design/icons';
import { useFormikContext } from 'formik';
export interface ColumnsSwitchProps {
name: string;
Front?: string;
Back?: string;
onChange?: (checked:any,event:any) => any;
icon?: boolean
Checked?:boolean
}
const ColumnsSwitch = (props: ColumnsSwitchProps) => {
const { name, Front, Back, icon, onChange } = props;
const formik = useFormikContext<any>();
const onSwitchChange = (checked: boolean, event: Event) => {
// formik.setFieldValue("status", checked)
};
return (
<Switch
checkedChildren={icon ? <CheckOutlined /> : Front}
unCheckedChildren={icon ? <CloseOutlined /> : Back}
onChange={ (checked:any,event:any)=> onChange ? onChange(checked,event) : onSwitchChange(checked,event)}
/>
)
}
export default ColumnsSwitch
ColumnsSwitch.defaultProps = {
Front: "Front",
Back: "Back",
onChange: undefined,
icon: false,
Checked:false
};

View File

@ -0,0 +1,50 @@
import React from "react";
import { confirmAlert } from "react-confirm-alert";
import SweetAlert from "react-bootstrap-sweetalert";
import { useTranslation } from "react-i18next";
export default function CustomConfirmAlert(options : any) {
confirmAlert({
customUI: ({ onClose }) => <CustomUI onClose={onClose} options={options} />,
});
}
type CustomUIProps ={
onClose :()=> void
options:{
title?:string
confirmBtnText:string
cancelBtnText:string
body:string
onConfirm:()=>void
}
}
function CustomUI({ onClose, options }:CustomUIProps) {
const [t] = useTranslation()
return (
<div className="">
<SweetAlert
title={options.title || t(`delete_are_you_sure`)}
customClass="SweetAlert"
warning
show={true}
showCancel
reverseButtons
cancelBtnBsStyle="danger"
confirmBtnText={options.confirmBtnText || t("yes_delete_it")}
cancelBtnText={options.cancelBtnText || t("cancel")}
onConfirm={() => {
options.onConfirm();
onClose();
}}
onCancel={onClose}
/>
</div>
);
}

View File

@ -0,0 +1,49 @@
import React from 'react';
interface CheckBoxesVuexyProps {
className?: string;
color: string;
defaultChecked?: boolean;
checked?: boolean;
value?: string;
disabled?: boolean;
onClick?: () => void;
onChange?: () => void;
size?: string;
icon: React.ReactNode;
label: string;
}
const CheckBoxesVuexy: React.FC<CheckBoxesVuexyProps> = ({
className = '',
color,
defaultChecked,
checked,
value,
disabled,
onClick,
onChange,
size = 'md',
icon,
label,
}) => {
return (
<div className={`vx-checkbox-con ${className} vx-checkbox-${color}`}>
<input
type="checkbox"
defaultChecked={defaultChecked}
checked={checked}
value={value}
disabled={disabled}
onClick={onClick}
onChange={onChange}
/>
<span className={`vx-checkbox vx-checkbox-${size}`}>
<span className="vx-checkbox--check">{icon}</span>
</span>
<span>{label}</span>
</div>
);
};
export default CheckBoxesVuexy;

View File

@ -0,0 +1,27 @@
import React from 'react'
import 'bootstrap/dist/css/bootstrap.min.css';
import { Input } from 'reactstrap';
import { useFormikContext } from 'formik';
type FileInputProps = {
name:string,
label:string,
accept:string,
onChange:any
}
function FileInput({name , accept="image/*" ,label , onChange} :FileInputProps) {
return (
<div className="custom-file-input">
<label className="custom-file-label" htmlFor="inputGroupFile01">
{label}
</label>
<Input accept={accept} id="inputGroupFile01" name={name} onChange={onChange}
type="file" className="custom-file-input" />
</div>
)
}
export default FileInput

View File

@ -0,0 +1,37 @@
import React from "react";
import { Tooltip } from "reactstrap";
const tooltipStyle = {
backgroundColor: "white",
border: "2px solid lightgrey",
maxWidth: "400px",
};
const HovarableImage = ({ id, src, imgPreviewProps = {}, ...props }:any) => {
const [isOpen, setIsOpen] = React.useState(false);
const ID = `image_hover_tooltip_${id}`;
const toggleTooltip = React.useCallback(() => setIsOpen((prev) => !prev), []);
return (
<div style={{marginInline:"20px"}}>
<img id={ID} src={src} alt={props.alt} {...props} style={{ maxWidth:"300px", maxHeight:'50px'}}/>
<Tooltip
placement="left"
isOpen={isOpen}
target={ID}
toggle={toggleTooltip}
style={tooltipStyle}
>
<img
style={{ maxWidth:"300px", maxHeight:'150px'}}
src={src}
alt={props.alt}
{...imgPreviewProps}
/>
</Tooltip>
</div>
);
};
export default HovarableImage;

View File

@ -0,0 +1,34 @@
import React from "react";
import { useTranslation } from "react-i18next";
const ImagePreview = ({ preview, height = 200 }:any) => {
const [t] = useTranslation();
return (
<div
style={{
border: "1px solid lightgray",
height: `${height}px`,
display: "flex",
justifyContent: "center",
alignItems: "center",
}}
>
{preview ? (
<img
className="p-1"
style={{
maxWidth: "100%",
}}
height={height}
src={preview}
alt=""
/>
) : (
<div>{t("image_preview")}</div>
)}
</div>
);
};
export default ImagePreview;

View File

@ -0,0 +1,13 @@
import React from "react";
import { Button, Spinner } from "reactstrap";
const LoadingButton = ({ isLoading = false, ...props }) => {
return (
<Button className="btn-primary" disabled={isLoading} {...props}>
{isLoading ? <Spinner style={{ marginRight: "10px" }} size="sm" /> : null}
<span >{props.children}</span>
</Button>
);
};
export { LoadingButton };

View File

@ -0,0 +1,10 @@
import { Spin } from 'antd'
import React from 'react'
function LoadingSpinner() {
return (
<Spin className='primary' />
)
}
export default LoadingSpinner

View File

@ -0,0 +1,57 @@
import React, { FC, useState } from "react";
import { ErrorMessage, useField, Field } from "formik";
import { FormGroup } from "reactstrap";
// import PropTypes from "prop-types";
import { Eye, EyeOff } from "react-feather";
import "./index.css";
interface PasswordFieldProps {
name: string;
label?: string;
}
const PasswordField: FC<PasswordFieldProps> = ({ name, label, ...props }) => {
const [field, meta] = useField({ name, ...props });
const [showPassword, setShowPassword] = useState<boolean>(false);
const EyeIcon = showPassword ? Eye : EyeOff;
const toggleShow = () => {
setShowPassword((prev) => !prev);
};
return (
<>
{label && <label className="change_password_body" htmlFor={name}>{label}</label>}
<FormGroup className={"position-relative has-icon-left"}>
<Field
className={
"form-control " + (meta.touched && meta.error ? "is-invalid" : "")
}
name={name}
type={showPassword ? "text" : "password"}
autoComplete="new-password"
{...props}
/>
<div className="form-control-position">
<EyeIcon
fontSize={12}
onClick={toggleShow}
className="cursor-pointer change_password_body"
/>
</div>
<ErrorMessage
className="field-error text-danger"
component="div"
name={field.name}
/>
</FormGroup>
</>
);
};
// PasswordField.propTypes = {
// name: PropTypes.string.isRequired,
// };
export { PasswordField };

View File

@ -0,0 +1,10 @@
.back-icon {
font-size: 18px;
margin: 0;
margin-right: 5px;
}
.back-btn {
padding-left: 0.8rem;
padding-right: 1rem;
}

View File

@ -0,0 +1,24 @@
import React from "react";
import { Progress } from "reactstrap";
const ProgressBar = ({ value,isLoading, isSuccess, isError }:any) => {
let color = "";
if (!isLoading && isSuccess) {
color = "success";
}
if (!isLoading && isError) {
color = "danger";
}
return (
<div className="my-1">
<Progress color={color} style={{ height: "1rem" }} className=" mt-4" value={value}>
{value}%
</Progress>
</div>
);
};
export default ProgressBar;

View File

@ -0,0 +1,29 @@
import React from "react";
import Select from "react-select";
import { ValidatedField } from "./ValidatedField";
import { useFormikContext } from "formik";
const SelectField = ({ label, name, options, ...props }:any) => {
const formik = useFormikContext<any>();
return (
<ValidatedField
CustomField={Select}
label={label}
name={name}
className="React"
classNamePrefix="select"
options={options || []}
value={options?.find((opt:any) => opt.value === formik?.values[name]) || ""}
onChange={(opt:any) => formik.setFieldValue(name, opt.value)}
onBlur={() => formik.setFieldTouched(name)}
key={name}
{...props}
/>
);
};
export default SelectField;

View File

@ -0,0 +1,58 @@
import React from "react";
import { Card, CardBody } from "reactstrap";
import { ChartTypeEnum } from "../../../enums/ChartTypeEnum";
import { history } from "../../../ProviderContainer";
import { useNavigate } from "react-router-dom";
interface StatisticsCardProps {
className?: string;
iconLeft?: boolean;
icon: React.ReactNode;
count?: string;
CardTitle?: string;
CardContent?: string;
height?: number;
pathWhenClick :string ;
}
const StatisticsCard = (props :StatisticsCardProps) => {
const navigate = useNavigate()
const {
className,
iconLeft = false ,
icon,
count,
CardTitle,
CardContent,
pathWhenClick,
height,
...rest
} = props;
return (
<Card className="p-4 gomecards" {...rest} onClick={()=>navigate(pathWhenClick )}>
<CardBody
className={`${
className ? className : "stats-card-body"
} d-flex justify-content-center flex-column text-center pb-2 pt-2 primary `}
>
<div className="icon-section">
<div
className={`avatar avatar-stats p-50 m-0 ${ "bg-rgba-primary"}`}
>
{/* <p className="mb-0 text-bold-700">{CardTitle}</p> */}
<div className="avatar-content ">{icon}</div>
</div>
</div>
<div className={"title-section " + (iconLeft ? "ml-2" : "")}>
{/* <h2 className="text-bold-600 mb-25 ">{count}</h2> */}
<p className="mb-2 Content">{CardContent}</p>
</div>
</CardBody>
</Card>
);
};
export default StatisticsCard;

View File

@ -0,0 +1,17 @@
import React from "react";
import { useTranslation } from "react-i18next";
import { Badge } from "reactstrap";
const StatusBadge = ({ status }:any) => {
const [t] = useTranslation();
return (
<Badge color={status ? "success" : "danger"}>
{status ? t("active") : t("inacticve")}
</Badge>
);
};
export default StatusBadge;

View File

@ -0,0 +1,38 @@
import React , {ReactNode} from "react";
import confirmAlert from "./Alert";
import { FaEdit, FaTrash } from "react-icons/fa";
type TableActionsProps = {
onDelete: () => any;
onEdit: () => void;
showEdit?: boolean;
showDelete?: boolean;
children?: ReactNode;
};
const TableActions = ({ onDelete , onEdit,showEdit=true,showDelete=true, children }:TableActionsProps) => {
return (
<div className="data-list-action TableActions">
{showEdit && <FaEdit onClick={onEdit} className="cursor-pointer m-1" size={20} />}
{showDelete && (
<FaTrash
onClick={() =>
confirmAlert({
onConfirm: () => {
onDelete();
},
})
}
className="cursor-pointer"
size={20}
/>
)}
{children}
</div>
);
};
export default TableActions;

View File

@ -0,0 +1,31 @@
import React from 'react';
import type { RadioChangeEvent } from 'antd';
import { Radio } from 'antd';
const onChange = (e: RadioChangeEvent) => {
console.log(`radio checked:${e.target.value}`);
};
const App: React.FC = () => (
<>
<Radio.Group onChange={onChange} defaultValue="a" style={{ marginTop: 16 }}>
<Radio.Button value="a">Hangzhou</Radio.Button>
<Radio.Button value="b" disabled>
Shanghai
</Radio.Button>
<Radio.Button value="c">Beijing</Radio.Button>
<Radio.Button value="d">Chengdu</Radio.Button>
</Radio.Group>
<Radio.Group disabled onChange={onChange} defaultValue="a" style={{ marginTop: 16 }}>
<Radio.Button value="a">Hangzhou</Radio.Button>
<Radio.Button value="b">Shanghai</Radio.Button>
<Radio.Button value="c">Beijing</Radio.Button>
<Radio.Button value="d">Chengdu</Radio.Button>
</Radio.Group>
</>
);
export default App;

View File

@ -0,0 +1,39 @@
import React from "react";
import Toggle from "react-toggle";
import "react-toggle/style.css";
import StatusBadge from "./StatusBadge";
import { useTranslation } from "react-i18next";
interface ToggleStatusProps {
}
export const ToggleStatus = ({ object, handleSwitch, toggleMutation, ...props }:any) => {
const [t] = useTranslation();
// const handleSwitch = () => {
// toggleMutation.mutate({
// id: object.id,
// new_status: !object.is_active,
// });
// };
return (
<>
<div className="p-0">
<p
className="mb-0 p-0"
style={{ whiteSpace: "nowrap", textAlign: "center" }}
>
{object.is_active ? t("active") : t("inactive")}
</p>
<Toggle
{...props}
className="custom-switch"
disabled={toggleMutation.isLoading}
onChange={handleSwitch}
checked={object.is_active}
/>
</div>
</>
);
};

View File

@ -0,0 +1,64 @@
import React from "react";
import { ErrorMessage, useField, Field } from "formik";
import { FormGroup } from "reactstrap";
import { useTranslation } from "react-i18next";
const ValidatedField = ({
name,
label,
CustomField,
icon: Icon,
optional,
labelIcon = null,
formProps,
isRequired,
...props
}:any) => {
const [field, meta] = useField({ name, ...props });
const [t] = useTranslation();
let Wrapper = Field;
if (CustomField) {
Wrapper = CustomField;
}
const fieldProps = props.type === "file" ? {} : { ...field };
return (
<>
{label && (
<label htmlFor={name}>
{label} {props.required || isRequired ? "*" : ""} {labelIcon}
</label>
)}
<FormGroup
className={Icon ? "position-relative has-icon-left" : ""}
{...formProps}
>
<Wrapper
className={
"form-control " + (meta.touched && meta.error ? "is-invalid" : "")
}
{...fieldProps}
required={props.isRequired}
{...props}
/>
{Icon && (
<div className="form-control-position">
<Icon size={15} />
</div>
)}
<ErrorMessage name={field.name}>
{(msg) => <span className="field-error text-danger">{t(msg)}</span>}
</ErrorMessage>
</FormGroup>
</>
);
};
export { ValidatedField };

View File

@ -0,0 +1,17 @@
import Checkbox from './CheckboxesVuexy'
import ImagePreview from './ImagePreview'
import SelectField from './SelectField'
import { useImagePreview } from './useImagePreview'
import {ValidatedField} from './ValidatedField'
import StatusBadge from './StatusBadge'
import HovarableImage from './HovarableImage'
export {
Checkbox,
ImagePreview,
SelectField,
useImagePreview,
ValidatedField,
StatusBadge,
HovarableImage
}

View File

@ -0,0 +1,58 @@
import React , {ReactNode} from "react";
import { FaEdit, FaEye, FaTrash } from "react-icons/fa";
import CustomConfirmAlert from "../Alert";
import { usePageState } from "../../../lib/state mangment/LayoutPagestate";
type TableActionsProps = {
onDelete?: () => any;
onEdit?: () => any;
onView?:() => any;
showView?: boolean;
showEdit?: boolean;
showDelete?: boolean;
children?: ReactNode;
objectToEdit:any
className?:string
};
const TableActions = ({ onDelete=()=>{} , objectToEdit,onEdit=()=>{},onView,showEdit=true,showDelete=true,showView=true,children,className }:TableActionsProps) => {
// const TableActions = ({ onDelete=()=>{} , objectToEdit,onEdit=()=>{},onView,showEdit=true,showDelete=true,showView=true,children }:TableActionsProps) => {
// console.log(objectToEdit);
const {setObjectToEdit , setIsOpenEditModel} = usePageState()
return (
<div className={`data-list-action TableActions ${className}`}>
{showEdit && <FaEdit onClick={()=>{
setObjectToEdit(objectToEdit)
setIsOpenEditModel()
onEdit()
}} className="cursor-pointer m-2" size={20} />}
{showView && <FaEye onClick={onView} className="cursor-pointer m-2" size={25} />}
{showDelete && (
<FaTrash
onClick={() =>
CustomConfirmAlert({
onConfirm: () => {
onDelete();
},
})
}
className="cursor-pointer"
size={20}
/>
)}
{children}
</div>
);
};
export default TableActions;

View File

@ -0,0 +1,40 @@
import React from "react";
import { confirmAlert } from "react-confirm-alert";
import SweetAlert from "react-bootstrap-sweetalert";
interface CustomUIProps {
onClose: () => void;
options: {
title?: string;
confirmBtnText?: string;
cancelBtnText?: string;
onConfirm: () => void;
body?: string;
};
}
export default function CustomConfirmAlert(options: any) {
confirmAlert({
customUI: ({ onClose }) => <CustomUI onClose={onClose} options={options} />,
});
}
function CustomUI({ onClose, options }: CustomUIProps) {
const sweetAlertProps: any = {
title: options.title || `DELETE, Are you sure?`,
warning: true,
show: true,
showCancel: true,
reverseButtons: true,
cancelBtnBsStyle: "danger",
confirmBtnText: options.confirmBtnText || "Yes, delete it!",
cancelBtnText: options.cancelBtnText || "Cancel",
onConfirm: () => {
options.onConfirm();
onClose();
},
onCancel: onClose,
};
return <SweetAlert {...sweetAlertProps}>{options.body || "You won't be able to revert this!"}</SweetAlert>;
}

View File

@ -0,0 +1,24 @@
import { useState, useEffect } from "react";
export const useImagePreview = (defaultValue:any = null) => {
const [preview, setPreview] = useState(defaultValue || null);
useEffect(() => {
return () => {
URL.revokeObjectURL(preview);
};
}, [preview]);
const handleImageChange = (event:any) => {
setPreview(URL.createObjectURL(event.target.files[0]));
};
return {
preview,
handleImageChange,
setPreview,
};
};

View File

@ -0,0 +1,62 @@
import React, { useEffect } from 'react';
import { useTranslation } from 'react-i18next';
import { BsExclamationCircle } from 'react-icons/bs';
import { Button, Card, CardBody, Input, Label, Modal, ModalHeader } from 'reactstrap';
import { useCommonModelState } from '../../lib/state mangment/driver&customer/ModelState';
import { LoadingButton } from '../Ui/LoadingButton';
interface BlockModelProps {
Mutation:any,
type :'customer' |'driver'
}
const BlockModel: React.FC<BlockModelProps> = ({Mutation ,type}) => {
const {t} = useTranslation();
const key_to_api = type == t('customer') ? t('customer_id') : t("driver_id")
const {isOpenBlock:isOpen , objectID , setIsopenBlock:setIsOpen} = useCommonModelState()
const handleSubmit = () => {
const blockInput = document.getElementById('block_input') as HTMLInputElement;
if (blockInput) {
Mutation.mutate({ [key_to_api]: objectID, block_timer: blockInput.value });
}
};
useEffect(() => {
if (Mutation.isSuccess) {
setIsOpen();
}
}, [Mutation.isSuccess, setIsOpen]);
return (
<Modal isOpen={isOpen} centered size='md'>
<ModalHeader toggle={() => setIsOpen()}>
{t("al")}{type}{t('_block_page')}
</ModalHeader>
<Card>
<CardBody>
<div style={{ width: '100%', display: 'flex', alignItems: 'center', flexDirection: 'column' }}>
<h1 className='modal_info' style={{ fontWeight: 'bold' }}> {t('blocking_')}{type}</h1>
<BsExclamationCircle className='modal_info' style={{ fontSize: '100px', color: '#f8be86', margin: '20px 0' }} />
<div className=''>
<Label for='block_input'>{t('date_blocking')}</Label>
<Input id='block_input' placeholder={t('date_blocking')} type='date' />
<div style={{ marginTop: 20 }}>
<Button color='danger' style={{ marginInline: 10 }} onClick={() => setIsOpen()}>
{t('cancel')}
</Button>
<LoadingButton color='primary' onClick={handleSubmit} isLoading={Mutation.isLoading} type='submit'>
{t('add_block_for_')}{type}
</LoadingButton>
</div>
</div>
</div>
</CardBody>
</Card>
</Modal>
);
};
export default BlockModel;

View File

@ -0,0 +1,63 @@
import React, { useEffect } from 'react';
import { useTranslation } from 'react-i18next';
import { BsExclamationCircle } from 'react-icons/bs';
import { Button, Card, CardBody, Col, Input, Label, Modal, ModalHeader, Row } from 'reactstrap';
import { useCommonModelState } from '../../lib/state mangment/driver&customer/ModelState';
import { LoadingButton } from '../Ui/LoadingButton';
interface GiftModalProps {
Mutation:any,
type :'customer' |'driver'
}
const GiftModal: React.FC<GiftModalProps> = ({Mutation ,type }) => {
const {t} = useTranslation();
const {isOpenGift:isOpen , objectID , setIsopenGift:setIsOpen} = useCommonModelState()
useEffect(() => {
if (Mutation.isSuccess) {
setIsOpen();
}
}, [Mutation.isSuccess, setIsOpen]);
const handleGift = () => {
const enterCodesInput = document.getElementById('enter_codes') as HTMLInputElement;
if (enterCodesInput && enterCodesInput.value) {
Mutation.mutate({ type, id: objectID, value: enterCodesInput.value });
}
};
return (
<Modal isOpen={isOpen} centered size='md'>
<ModalHeader toggle={() => setIsOpen()}>
{t("al")}{type} {t('_gift_page')}
</ModalHeader>
<Card>
<CardBody>
<Row>
<Col className='' style={{ width: 300 }}>
<Label for='enter_codes' className='modal_info'>{t('value')}</Label>
<Input id='enter_codes' placeholder={t('value')} type='number' />
<Col style={{ marginTop: 20, display: 'flex', justifyContent: 'space-between' }}>
<Button color='danger' onClick={() => setIsOpen()}>
{t('cancel')}
</Button>
<LoadingButton
color='primary'
onClick={handleGift}
type='submit'
isLoading={Mutation.isLoading}>
{t('give')}
</LoadingButton>
</Col>
</Col>
</Row>
</CardBody>
</Card>
</Modal>
);
};
export default GiftModal;

View File

@ -0,0 +1,93 @@
.Loading{
.wrapper {
width: 200px;
height: 60px;
position: relative;
left: 40%;
z-index: 1;
}
.circle {
width: 20px;
height: 20px;
position: absolute;
border-radius: 50%;
background-color: var(--primary);
left: 15%;
transform-origin: 50%;
animation: circle7124 .5s alternate infinite ease;
}
@keyframes circle7124 {
0% {
top: 60px;
height: 5px;
border-radius: 50px 50px 25px 25px;
transform: scaleX(1.7);
}
40% {
height: 20px;
border-radius: 50%;
transform: scaleX(1);
}
100% {
top: 0%;
}
}
.circle:nth-child(2) {
left: 45%;
animation-delay: .2s;
}
.circle:nth-child(3) {
left: auto;
right: 15%;
animation-delay: .3s;
}
.shadow {
width: 20px;
height: 4px;
border-radius: 50%;
background-color: rgba(0,0,0,0.9);
position: absolute;
top: 62px;
transform-origin: 50%;
z-index: -1;
left: 15%;
filter: blur(1px);
animation: shadow046 .5s alternate infinite ease;
}
@keyframes shadow046 {
0% {
transform: scaleX(1.5);
}
40% {
transform: scaleX(1);
opacity: .7;
}
100% {
transform: scaleX(.2);
opacity: .4;
}
}
.shadow:nth-child(4) {
left: 45%;
animation-delay: .2s
}
.shadow:nth-child(5) {
left: auto;
right: 15%;
animation-delay: .3s;
}
}

View File

@ -0,0 +1,19 @@
import React from 'react'
import './Loading.scss'
const Loading = () => {
return (
<div className="Loading">
<div className="wrapper">
<div className="circle"></div>
<div className="circle"></div>
<div className="circle"></div>
<div className="shadow"></div>
<div className="shadow"></div>
<div className="shadow"></div>
</div>
</div>
)
}
export default Loading

View File

@ -0,0 +1,43 @@
.SearchBar{
.group {
display: flex;
align-items: center;
position: relative;
max-width: 190px;
}
.input {
width: 100%;
height: 40px;
padding: 0 1rem;
padding-left: 2.5rem;
border-radius: 8px;
outline: none;
font-weight: 500;
background: var(--primary);
color: var(--bg);
border: none;
box-shadow: 2px 2px 7px 0 var(--primary);
}
.input::placeholder {
color: var(--bg);
}
.icon {
position: absolute;
left: 1rem;
fill: var(--bg);
width: 1rem;
height: 1rem;
}
}

View File

@ -0,0 +1,14 @@
import React from 'react'
import './SearchBar.scss'
const SearchBar = () => {
return (
<div className='SearchBar'>
<div className="group">
<svg className="icon" viewBox="0 0 24 24"><g><path d="M21.53 20.47l-3.66-3.66C19.195 15.24 20 13.214 20 11c0-4.97-4.03-9-9-9s-9 4.03-9 9 4.03 9 9 9c2.215 0 4.24-.804 5.808-2.13l3.66 3.66c.147.146.34.22.53.22s.385-.073.53-.22c.295-.293.295-.767.002-1.06zM3.5 11c0-4.135 3.365-7.5 7.5-7.5s7.5 3.365 7.5 7.5-3.365 7.5-7.5 7.5-7.5-3.365-7.5-7.5z"></path></g></svg>
<input placeholder="Search" type="search" className="input"/>
</div>
</div>
)
}
export default SearchBar

View File

@ -0,0 +1,84 @@
import { Menu, MenuItem, MenuButton } from '@szhsin/react-menu';
import { useTranslation } from 'react-i18next';
import { usePageState } from '../../lib/state mangment/LayoutPagestate';
import { BsFillMoonStarsFill, BsFillSunFill, BsSunglasses } from 'react-icons/bs';
let What_the_Theme = localStorage.getItem('theme') ?? "light";
if (What_the_Theme === "dark") {
document.body.classList.add('dark')}
else if (What_the_Theme === "glass") {
document.body.classList.add('glass')
}
export default function Theme() {
const {t} = useTranslation();
const {setThemChange} = usePageState()
const changeTheme = (newTheme : any) => {
if(newTheme === "dark"){
document.body.classList.remove('glass');
document.body.classList.add('dark');localStorage.setItem("theme", "dark");
What_the_Theme = "dark"
}
else if(newTheme === "light"){
document.body.classList.remove('glass');
document.body.classList.remove('dark');localStorage.setItem("theme", "light");
What_the_Theme = "light"
}
else if(newTheme === "glass"){
document.body.classList.remove('dark'); document.body.classList.add('glass'); localStorage.setItem("theme", "glass");
What_the_Theme = "glass"
}
setThemChange()
};
/// BsSunglasses BsFillSunFill BsFillMoonStarsFill
return (
<div className='Theme'>
<Menu menuButton={<MenuButton>
{(What_the_Theme === "light") ?
<>
<BsFillSunFill/>
{t("light")}
</>
: (What_the_Theme === "dark") ?
<>
<BsFillMoonStarsFill/>
{t("dark")}
</>
:
<>
<BsSunglasses/>
{t("glass")}
</>
}
</MenuButton>} transition>
<MenuItem onClick={() => changeTheme('light')}>
<BsFillSunFill/>
{t("light")}
</MenuItem>
<MenuItem onClick={() => changeTheme('dark')}>
<BsFillMoonStarsFill/>
{t("dark")} </MenuItem>
<MenuItem onClick={() => changeTheme('glass')}>
<BsSunglasses/>
{t("glass")} </MenuItem>
</Menu>
</div>
);
}

View File

@ -0,0 +1,42 @@
import React from 'react';
import { Menu, Dropdown } from 'antd';
import { useLanguage, useLanguageMenu } from '../../Hooks/useChangeLanguage';
import i18next from 'i18next';
import type { MenuProps } from 'antd';
export default function Translate() {
const { changeLanguage } = useLanguage();
const { languageOptions } = useLanguageMenu();
const handleLanguageChange = (newLanguage:string) => {
changeLanguage(newLanguage);
};
const items : MenuProps['items'] = languageOptions.map((option:any,index:number) => ({
key: index,
label: (
<div className='MenuPropsItem' onClick={() => handleLanguageChange(option.code)}>
<img alt='' src={option.icon} width={20} height={20} />
{option.label}
</div>
)
}));
return (
<div className='Translate'>
<Dropdown menu={{items}} placement="bottomLeft">
<button className="ant-dropdown-link" onClick={e => e.preventDefault()}>
{languageOptions.map((option:any,index:number) => (
option.code === i18next.language ?
<React.Fragment key={index}>
<img alt='' src={option.icon} width={20} height={20} /> {option.label}
</React.Fragment>
: null
))}
</button>
</Dropdown>
</div>
);
}

View File

@ -0,0 +1,60 @@
import React, { useEffect } from 'react';
import { BsExclamationCircle } from 'react-icons/bs';
import { Button, Card, CardBody, Input, Label, Modal, ModalHeader } from 'reactstrap';
import { useTranslation } from 'react-i18next';
import { LoadingButton } from '../Ui/LoadingButton';
import { useCommonModelState } from '../../lib/state mangment/driver&customer/ModelState';
import { CiLock } from "react-icons/ci";
interface UnBlockModalProps {
Mutation:any,
type :'customer' |'driver'
}
const UnBlockModal: React.FC<UnBlockModalProps> = ({Mutation ,type }) => {
const {t} = useTranslation();
const key_to_api = type == t('customer') ? t('customer_id') : t("driver_id")
const {isOpenUnBlock:isOpen , objectID , setIsopenUnBlock:setIsopen} = useCommonModelState()
const handleSubmit = () => {
Mutation.mutate({ [key_to_api]: objectID });
};
useEffect(() => {
if (Mutation.isSuccess) {
setIsopen();
}
}, [Mutation.isSuccess, setIsopen]);
return (
<Modal isOpen={isOpen} centered size='md'>
<ModalHeader toggle={() => setIsopen()}>
{t("al")}{type} {t('un_block_page')}
</ModalHeader>
<Card>
<CardBody>
<div style={{ width: '100%', display: 'flex', alignItems: 'center', flexDirection: 'column' }}>
<h1 className='modal_info' style={{ fontWeight: 'bold' }}> {t('un_blocking_')}{type}</h1>
<CiLock className='modal_info' style={{ fontSize: '100px', color: 'black', margin: '20px 0' }} />
<div className=''>
<div style={{ marginTop: 20 }}>
<Button color='danger' style={{ marginInline: 10 }} onClick={() => setIsopen()}>
{t('cancel')}
</Button>
<LoadingButton color='primary' onClick={handleSubmit} type='submit' isLoading={Mutation.isLoading}>
{t('un_block_for_')}{type}
</LoadingButton>
</div>
</div>
</div>
</CardBody>
</Card>
</Modal>
);
};
export default UnBlockModal;

View File

@ -0,0 +1,18 @@
import React from 'react';
import { Spin } from 'antd';
interface Props {
loading: boolean;
children: React.ReactNode;
className?: string;
}
const KarimSpinner: React.FC<Props> = ({ loading, className, children }) => {
return (
<div className={className ?? ""}>
{loading ? <div className='text-center'><Spin /></div> : children}
</div>
);
};
export default KarimSpinner;

View File

@ -0,0 +1,48 @@
.SearchBar{
// margin-top: 20px;
.group {
display: flex;
align-items: center;
position: relative;
max-width: 350px;
width: 350px;
}
.input {
width: 100%;
height: 40px;
padding: 0 1rem;
padding-left: 2.5rem;
border-radius: 8px;
outline: none;
font-weight: 500;
background: var(--bg);
color: var(--text);
border: none;
box-shadow: 2px 2px 7px 0 var(--bg);
}
.input::placeholder {
color: var(--subtext);
opacity: .4;
}
.icon {
position: absolute;
left: 1rem;
fill: var(--subtext);
width: 1rem;
height: 1rem;
}
}

View File

@ -0,0 +1,35 @@
import React, { useState } from 'react'
import './SearchBar.scss'
import { useNavigate, useSearchParams } from 'react-router-dom';
const SearchBar = () => {
const [searchQuery, setSearchQuery] = useState('');
const [searchParams] = useSearchParams()
const navigate = useNavigate();
const handleChange = (event:any) => {
const { value } = event.target;
setSearchQuery(value);
updateUrlParams(value);
};
const updateUrlParams = (value:any) => {
navigate(`?search=${value}`);
};
return (
<div className='SearchBar'>
<div className="group">
<svg xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink" className="MuiSvgIcon-root MuiSvgIcon-fontSizeMedium css-1b5stb0 icon" focusable="false" aria-hidden="true" viewBox="0 0 24 24" data-testid="SearchIcon"><path d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"></path></svg>
<input placeholder="Search Product...." type="search"
className="input"
value={searchQuery}
onChange={handleChange}
/>
</div>
</div>
)
}
export default SearchBar

View File

@ -0,0 +1,78 @@
.ValidationField{
>*{
width: 100%;
}
.text,.ant-form-item{
margin-bottom:7px !important;
}
>span{
margin-bottom: 0px !important;
&:focus-within{
border-color: var(--primary) ;
box-shadow: 0 0 0 1px var(--primary);
cursor: pointer;
}
&:has(.is-invalid){
border-color: red !important;
}
input{
color: var(--text);
background: var(--bg);
}
input:-webkit-autofill,
input:-webkit-autofill:hover,
input:-webkit-autofill:focus,
input:-webkit-autofill:active{
-webkit-box-shadow: 0 0 0 30px white inset !important;
}
}
}
.ant-upload-select{
width: 100%;
}
.Checkboxs{
padding: 4%;
}
.SearchField{
button{
background: var(--primary);
}
}
.text{
color: var(--text);
}
input:disabled{
color: var(--text) !important;
}
.isError{
outline: red 1px solid;
color: red;
}
.Error_color{
color: red;
}
input:-webkit-autofill {
-webkit-box-shadow: 0 0 0 1000px white inset !important; /* Change the color to your desired background color */
}
input:-webkit-autofill:focus {
-webkit-box-shadow: 0 0 0 1000px white inset !important; /* Change the color to your desired background color */
}
/* Remove autofill background color on hover */
input:-webkit-autofill:hover {
-webkit-box-shadow: 0 0 0 1000px white inset !important; /* Change the color to your desired background color */
}
.ant-upload-list .ant-upload-list-item{
height:78px !important;
}

View File

@ -0,0 +1,34 @@
import React from "react";
import "./ValidationField.scss";
import { Date, Time, File, DataRange, SelectField, Default, CheckboxField ,TextAreaField} from './View';
import { ValidationFieldProps } from "./types";
import MaltyFile from "./View/MaltyFile";
import SearchField from "./View/SearchField";
const ValidationField: React.FC<ValidationFieldProps> = ({type , ...otherProps}) => {
switch (type) {
case 'Select':
return <SelectField {...otherProps} />;
case 'Search':
return <SearchField {...otherProps} />;
case "DataRange":
return <DataRange {...otherProps} />;
case "Date":
return <Date {...otherProps} />;
case "Time":
return <Time {...otherProps} />;
case "File":
return <File {...otherProps} />;
case "MaltyFile":
return <MaltyFile {...otherProps} />;
case "Checkbox":
return <CheckboxField {...otherProps} />;
case "TextArea":
return <TextAreaField {...otherProps} />;
default:
return <Default {...otherProps} type={type}/>;
}
};
export default React.memo(ValidationField);

View File

@ -0,0 +1,36 @@
import React from 'react'
import useFormField from '../../../Hooks/useFormField';
import { Checkbox, Form } from 'antd';
const CheckboxField = ({ name, label, isDisabled, onChange,Group,className, props }: any) => {
const { t, formik,isError,errorMsg} = useFormField(name, props)
const CheckboxhandleChange = (value: any) => {
formik.setFieldValue(name, value?.target?.checked)
};
return (
<div className={Group ? "d-inline mt-3 Checkboxs" :``}>
<Form.Item
hasFeedback
validateStatus={isError ? 'error' : ''}
help={isError ? errorMsg : ''}
>
<Checkbox
onChange={onChange || CheckboxhandleChange}
disabled={isDisabled}
checked={formik.values[name] ?? false}
className={className}
>
{t(`${label ? label : name}`)}
</Checkbox>
</Form.Item>
</div>
)
}
export default CheckboxField

View File

@ -0,0 +1,44 @@
import { Form, DatePicker } from 'antd'
import React from 'react'
import useFormField from '../../../Hooks/useFormField';
const { RangePicker } = DatePicker;
const DataRange = ({ name, label, Format, props, onChange, isDisabled, placeholder, className }: any) => {
const { errorMsg, isError, t, formik } = useFormField(name, props)
const onCalendarChange = (value: any) => {
formik.setFieldValue(name, value)
};
return (
<div className='ValidationField'>
<label htmlFor={name} className="text">
{t(`${label ? label : name}`)}
</label>
<Form.Item
hasFeedback
validateStatus={isError ? "error" : ""}
help={isError ? errorMsg : ""}
>
<RangePicker
placeholder={placeholder}
size="large"
allowClear
className={`${className} w-100`}
format={Format}
onChange={onChange || onCalendarChange}
disabled={isDisabled}
defaultValue={formik.values[name]}
/>
</Form.Item>
</div>
)
}
export default DataRange

View File

@ -0,0 +1,51 @@
import { Form, DatePicker } from 'antd';
import React from 'react';
import useFormField from '../../../Hooks/useFormField';
import dayjs from 'dayjs';
const DateField = ({ name, label, picker = "date", isDisabled, props, onChange, placeholder, className, Format }: any) => {
const { errorMsg, isError, t, formik } = useFormField(name, props);
const onCalendarChange = (value: any) => {
formik.setFieldValue(name, value);
};
// Function to check if a date is valid
const isValidDate = (date: any) => {
return date && !isNaN(date.valueOf()) && dayjs(date).isValid();
};
// Set a default invalid date if the provided defaultValue is invalid
const getDefaultDate = () => {
const defaultValue = formik.values[name];
return isValidDate(defaultValue) ? defaultValue : null; // Set to null or any other default invalid date
};
return (
<div className='ValidationField'>
<label htmlFor={name} className="text">
{t(`${label ? label : name}`)}
</label>
<Form.Item
hasFeedback
validateStatus={isError ? "error" : ""}
help={isError ? errorMsg : ""}
>
<DatePicker
picker={picker}
placeholder={placeholder ? t(placeholder) : t(name)}
allowClear
className={`${className} w-100`}
defaultValue={getDefaultDate()}
size="large"
onChange={onChange || onCalendarChange}
disabled={isDisabled}
format={Format}
/>
</Form.Item>
</div>
);
}
export default DateField;

View File

@ -0,0 +1,37 @@
import { Form, Input } from 'antd'
import React from 'react'
import useFormField from '../../../Hooks/useFormField';
const Default = ({ name, label, placeholder, isDisabled, onChange, props,type }: any) => {
const { Field, formik, isError, errorMsg, t } = useFormField(name, props);
// console.log(isError);
return (
<div className="ValidationField w-100" >
<label htmlFor={name} className="text">
{t(`${label ? label : name}`)}
</label>
<Form.Item
hasFeedback
validateStatus={isError ? 'error' : ''}
help={isError ? errorMsg : ''}
>
<Field
as={Input}
type={type ?? "text"}
placeholder={t(`${placeholder ?placeholder : name}`)}
name={name}
disabled={isDisabled}
size="large"
// onChange={onChange ? onChange : handleChange}
/>
</Form.Item>
</div>
);
};
export default React.memo(Default);
;

View File

@ -0,0 +1,64 @@
import { Button, Upload, UploadFile } from 'antd'
import useFormField from '../../../Hooks/useFormField';
import { UploadOutlined } from '@ant-design/icons';
import { ImageBaseURL } from '../../../api/config';
const File = ({ name, label, onChange, isDisabled,placholder,className, props }: any) => {
const { formik, t ,isError,errorMsg} = useFormField(name, props)
let FormikName = formik.values[name];
const imageUrl = formik.values[name] ? ImageBaseURL + FormikName : '';
const fileList: UploadFile[] = [
{
uid: '-1',
name: '',
status: 'done',
url: FormikName == ""? imageUrl : imageUrl?.replace("public", "/storage"),
thumbUrl: FormikName == ""? imageUrl : imageUrl?.replace("public", "/storage")
}
];
const FilehandleChange = (value:any) => {
formik.setFieldValue(name, value.file.originFileObj)
};
const customRequest = async ({ onSuccess}: any) => {
onSuccess();
};
return (
<div className="ValidationField">
<label htmlFor={name} className="text">
{t(`${label || name}`)} {isError ? errorMsg : ''}
</label>
<Upload
disabled={isDisabled}
listType="picture"
maxCount={1}
defaultFileList={[...fileList]}
onChange={onChange || FilehandleChange}
customRequest={customRequest}
className={`${className} w-100`}
>
<Button className={isError ? "isError w-100" : " w-100"} icon={<UploadOutlined />}>
{placholder ?? t("upload_image") }
</Button>
<div className='Error_color'> {isError ? "required" : ""}</div>
</Upload>
</div>
)
}
export default File

View File

@ -0,0 +1,92 @@
import { Button, Upload } from "antd";
import { UploadOutlined } from "@ant-design/icons";
import useFormField from "../../../Hooks/useFormField";
import { ImageBaseURL } from "../../../api/config";
const MaltyFile = ({
name,
label,
onChange,
isDisabled,
placeholder,
className,
props,
}: any) => {
const { formik, t, isError } = useFormField(name, props);
let imageUrl = formik?.values?.[name] ?? null;
// console.log(imageUrl);
// Mapping formik values to fileList format
const fileList = imageUrl
? imageUrl.map((file: any, index: number) => {
let fileUrl = "";
if (typeof file === "string") {
fileUrl = file.replace("public", "/storage");
}
console.log(file instanceof File);
return file instanceof File
? {
uid: index,
name: file?.name,
status: "done",
originFileObj: file,
}
: {
uid: index,
id: file?.id,
name: file?.name,
status: "done",
url: ImageBaseURL + fileUrl || "",
thumbUrl: ImageBaseURL + fileUrl || "",
};
})
: [];
const FilehandleChange = ({ fileList }: any) => {
if (fileList.length === 0) {
formik.setFieldValue(name, null);
} else {
formik.setFieldValue(
name,
fileList.map((file: any) => file?.originFileObj ?? file),
);
}
};
// Custom request function
const customRequest = async ({ onSuccess }: any) => {
// Perform any necessary actions before onSuccess is called
onSuccess();
};
return (
<div className="ValidationField upload_image_button">
<label htmlFor={name} className="text">
{t(`input.${label || name}`)}
</label>
<Upload
disabled={isDisabled}
listType="picture"
fileList={fileList} // Using fileList instead of defaultFileList
onChange={onChange || FilehandleChange}
customRequest={customRequest}
className={`${className} w-100`}
multiple // Allow multiple files to be selected
>
<Button
className={isError ? "isError w-100" : " w-100"}
icon={<UploadOutlined />}
>
{t(`input.` + placeholder) ?? t("input.upload_image")}
</Button>
<div className="Error_color"> {isError ? "required" : ""}</div>
</Upload>
</div>
);
};
export default MaltyFile;

View File

@ -0,0 +1,69 @@
import { Form, Select } from 'antd';
import React, { useEffect, useState } from 'react';
import useFormField from '../../../Hooks/useFormField';
import { useLocation, useNavigate } from 'react-router-dom';
const SearchField = ({ name, label, placeholder, isDisabled, searchBy, option, isMulti, onChange, className, loading,props }: any) => {
const { errorMsg, isError, t, formik } = useFormField(name, props);
const [searchQuery, setSearchQuery] = useState<string>('');
const location = useLocation()
const navigate = useNavigate()
useEffect(() => {
const searchParams = new URLSearchParams(location?.search);
setSearchQuery(searchParams?.get('search') || '');
console.log(searchParams);
}, [location]);
const SelecthandleChange = (value: { value: string; label: React.ReactNode }) => {
formik?.setFieldValue(name, value);
console.log(value);
};
const SearchHandleChange = (value:any) => {
if (value || value !== "") {
navigate(`${window?.location?.pathname}?${searchBy}=${value}`);
} else {
const params = new URLSearchParams(location.search);
params.delete(searchBy ?? "search");
navigate(`${window?.location.pathname}?${params.toString()}`);
}
};
return (
<div className='ValidationField'>
<label htmlFor={name} className="text">
{t(`${label ? label : name}`)}
</label>
<Form.Item
hasFeedback
validateStatus={isError ? "error" : ""}
help={isError ? errorMsg : ""}
>
<Select
placeholder={t(`${placeholder ? placeholder : name}`)}
disabled={isDisabled}
options={option}
size="large"
className={`${className} w-100`}
value={formik.values[name]}
// defaultValue={formik.values[name]}
allowClear
{...(isMulti && { mode: "multiple" })}
onChange={onChange || SelecthandleChange}
showSearch
optionFilterProp="label"
onSearch={SearchHandleChange}
loading={loading}
/>
</Form.Item>
</div>
);
};
export default React.memo(SearchField);

View File

@ -0,0 +1,41 @@
import { Form, Select } from 'antd'
import React from 'react'
import useFormField from '../../../Hooks/useFormField';
const SelectField = ({ name, label, placeholder, isDisabled,option,isMulti,onChange,className, props}: any) => {
const { errorMsg, isError, t ,formik} = useFormField(name, props)
const SelecthandleChange = (value: { value: string; label: React.ReactNode }) => {
formik.setFieldValue(name, value)
};
return (
<div className='ValidationField'>
<label htmlFor={name} className="text">
{t(`${label ? label : name}`)}
</label>
<Form.Item
hasFeedback
validateStatus={isError ? "error" : ""}
help={isError ? errorMsg : ""}
>
<Select
placeholder={t(`${placeholder ?placeholder : name}`)}
disabled={isDisabled}
options={option}
size="large"
className={`${className} w-100`}
value={formik.values[name]}
allowClear
{...(isMulti && { mode: "multiple" })}
onChange={onChange || SelecthandleChange}
/>
</Form.Item>
</div>
)
}
export default React.memo(SelectField);

View File

@ -0,0 +1,45 @@
import { Form, Input } from 'antd'
import React from 'react'
import useFormField from '../../../Hooks/useFormField';
const { TextArea } = Input;
const TextAreaField = ({ name, label, placeholder, isDisabled, onChange, props,type }: any) => {
const { Field, formik, isError, errorMsg, t } = useFormField(name, props);
const handleChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
console.log('Change:', e.target.value);
formik.setFieldValue(name, e.target.value)
};
return (
<div className="ValidationField w-100" >
<label htmlFor={name} className="text">
{t(`${label ? label : name}`)}
</label>
<Form.Item
hasFeedback
validateStatus={isError ? 'error' : ''}
help={isError ? errorMsg : ''}
>
<Field
as={TextArea}
placeholder={t(`${placeholder ?placeholder : name}`)}
name={name}
disabled={isDisabled}
size="large"
onChange={onChange || handleChange}
// onChange={onChange ? onChange : handleChange}
/>
</Form.Item>
</div>
);
};
export default React.memo(TextAreaField);
;

View File

@ -0,0 +1,41 @@
import { Form, TimePicker } from 'antd'
import React from 'react'
import useFormField from '../../../Hooks/useFormField';
const Time = ({ name, label,className,isDisabled,onChange,props }: any) => {
const { errorMsg, isError, t, formik } = useFormField(name, props)
const onCalendarChange = (value: any) => {
formik.setFieldValue(name, value)
};
return (
<div className='ValidationField'>
<label htmlFor={name} className="text">
{t(`${label}`)}
</label>
<Form.Item
hasFeedback
validateStatus={isError ? "error" : ""}
help={isError ? errorMsg : ""}
>
<TimePicker
allowClear
className={`${className} w-100`}
size="large"
defaultValue={formik.values[name]}
onChange={onChange || onCalendarChange}
disabled={isDisabled}
/>
</Form.Item>
</div>
)
}
export default Time

View File

@ -0,0 +1,22 @@
import Time from "./Time";
import SelectField from "./SelectField";
import Date from "./Date";
import DataRange from "./DataRange";
import CheckboxField from "./CheckboxField";
import Default from "./Default";
import File from "./File";
import TextAreaField from './TextArea'
export {
Time,
SelectField,
Date,
DataRange,
CheckboxField,
Default,
File,
TextAreaField
}

View File

@ -0,0 +1,21 @@
import { useState } from 'react';
import { ErrorMessage, useField, Field, useFormikContext } from 'formik';
import { useTranslation } from 'react-i18next';
import { FaExclamationCircle } from 'react-icons/fa';
import Select from 'react-select';
import { convert_data_to_select } from '../../Layout/app/Const';
export {
useState,
ErrorMessage, useField, Field, useFormikContext,
useTranslation,
FaExclamationCircle,
Select,
convert_data_to_select,
}

View File

@ -0,0 +1,132 @@
// export interface ValidationFieldProps {
// name: string;
// type?: "text" | "Select" | "DataRange" | "Date" | "Time" | "File" | "number" | "Checkbox" | "password";
// placeholder?: string;
// label?: string;
// className?: string;
// option?: any[];
// isMulti?: boolean;
// isDisabled?: boolean;
// picker?: "data" | "week" | "month" | "quarter" | "year";
// Format?: "YYYY/MM/DD" | "MM/DD" | "YYYY/MM";
// onChange?: (value: any) => void;
// Group?: boolean
// dir?:'ltr' | "rtl"
// }
export interface ValidationFieldPropsText {
name: string;
type: "text";
placeholder?: string;
label?: string;
className?: string;
isDisabled?: boolean;
onChange?: (value: any) => void;
dir?:'ltr' | "rtl"
}
export interface ValidationFieldPropsSelect {
name: string;
type: "Select";
placeholder?: string;
label?: string;
className?: string;
isDisabled?: boolean;
onChange?:any;
dir?:'ltr' | "rtl";
option: any[];
isMulti?: boolean;
}
export interface ValidationFieldPropsSearch{
name: string;
type: "Search";
placeholder?: string;
label?: string;
className?: string;
isDisabled?: boolean;
onChange?: (value: any) => void;
dir?:'ltr' | "rtl";
option: any[];
isMulti?: boolean;
searchBy:string;
loading?:boolean;
}
export interface ValidationFieldPropsDataRange {
name: string;
type: "DataRange";
placeholder?: string;
label?: string;
className?: string;
isDisabled?: boolean;
onChange?: (value: any) => void;
dir?:'ltr' | "rtl"
Format?: "YYYY/MM/DD" | "MM/DD" | "YYYY/MM" | "YYYY-MM-DD HH:mm:ss.SSS";
}
export interface ValidationFieldPropsDate {
name: string;
type: "Date";
placeholder?: string;
label?: string;
className?: string;
isDisabled?: boolean;
onChange?: (value: any) => void;
dir?:'ltr' | "rtl"
picker?: "data" | "week" | "month" | "quarter" | "year";
Format?: "YYYY/MM/DD" | "MM/DD" | "YYYY/MM" | "YYYY-MM-DD HH:mm:ss.SSS" | "YYYY-MM-DD HH:MM:SS";
}
export interface ValidationFieldPropsTime {
name: string;
type: "Time";
label?: string;
placeholder?: string;
className?: string;
isDisabled?: boolean;
onChange?: (value: any) => void;
dir?:'ltr' | "rtl"
}
export interface ValidationFieldPropsFile {
name: string;
type: "File" | "MaltyFile";
placeholder?: string;
label?: string;
className?: string;
isDisabled?: boolean;
onChange?: (value: any) => void;
dir?:'ltr' | "rtl"
}
export interface ValidationFieldPropsCheckbox {
name: string;
type: "Checkbox";
label?: string;
className?: string;
isDisabled?: boolean;
onChange?: (value: any) => void;
dir?:'ltr' | "rtl"
Group?: boolean
}
export interface ValidationFieldPropstext {
name: string;
type?: "text" | "number" | "password" | "TextArea";
label?: string;
className?: string;
placeholder?: string;
isDisabled?: boolean;
onChange?: (value: any) => void;
dir?:'ltr' | "rtl"
Group?: boolean
}
export type ValidationFieldProps = ValidationFieldPropsText| ValidationFieldPropsSelect| ValidationFieldPropsDataRange| ValidationFieldPropsDate| ValidationFieldPropsTime| ValidationFieldPropsFile| ValidationFieldPropsCheckbox| ValidationFieldPropstext | ValidationFieldPropsSearch;

View File

@ -0,0 +1,10 @@
import React from 'react'
// for write later
function OrderStatus() {
return (
<div>OrderStatus</div>
)
}
export default OrderStatus

View File

@ -0,0 +1,42 @@
import React, { FC } from "react";
import { Editor } from '@tinymce/tinymce-react';
import { useFormikContext } from "formik";
interface HtmlEditorProps {
langCode: number;
name: string;
editorState: string;
}
const HtmlEditor: FC<HtmlEditorProps> = ({ langCode, name, editorState, ...props }) => {
const formik = useFormikContext();
const ar: boolean = langCode === 2;
return (
<Editor
apiKey='6xf0byrgd7m2j28p9dfjittsq884x9j0d3e6dsterqrvtvez'
value={editorState}
init={{
height: 500,
menubar: false,
directionality: ar ? "rtl" : "ltr",
plugins: [
'advlist autolink lists link image charmap print preview anchor',
'searchreplace visualblocks code fullscreen',
'insertdatetime media table paste code help wordcount'
],
toolbar: 'undo redo | formatselect | ' +
'bold italic backcolor | alignleft aligncenter ' +
'alignright alignjustify | bullist numlist outdent indent | ' +
'removeformat | help',
content_style: 'body { font-family:Helvetica,Arial,sans-serif; font-size:14px }'
}}
onEditorChange={(newValue, editor) => {
formik.setFieldValue(name, newValue)
}}
/>
);
}
export { HtmlEditor };

View File

@ -0,0 +1,43 @@
import React, { FC } from "react";
// import PropTypes from "";
import { HtmlEditor } from "./HtmlEditor";
import { useFormikContext } from "formik";
import { useTranslation } from "react-i18next";
interface SingleLangEditorProps {
langCode: number;
property: string;
}
const PROPERTY_TYPES: string[] = [
"privacy_description",
"conditions_description",
"about_us_description",
"product_description",
"auction_description"
];
const SingleLangEditor: FC<SingleLangEditorProps> = ({ langCode, property }) => {
const formik:any = useFormikContext();
const {t} = useTranslation();
const label = `${t(property)} (${t(`lang_${langCode}`)})`;
const fieldName = `translated_fields[${langCode}][${property}]`;
return (
<>
<h5 className="Information_title">{label}</h5>
<HtmlEditor
langCode={langCode}
name={fieldName}
editorState={formik.values.translated_fields[langCode][property]}
/>
</>
);
};
// SingleLangEditor.propTypes = {
// langCode: PropTypes.oneOf([1, 2]).isRequired,
// property: PropTypes.oneOf(PROPERTY_TYPES).isRequired,
// };
export default SingleLangEditor;

View File

@ -0,0 +1,23 @@
import React, { FC } from "react";
import { Card, CardBody, Spinner } from "reactstrap";
interface StatusCardProps {
isLoading: boolean;
isError: boolean;
}
const StatusCard= ({ isLoading, isError }:StatusCardProps) => {
return (
<Card>
<CardBody
className="d-flex align-items-center justify-content-center"
style={{ height: "15rem" }}
>
{isLoading && <Spinner size="lg" color="primary" />}
{isError && <h4>Failed !</h4>}
</CardBody>
</Card>
);
};
export default StatusCard;

View File

@ -0,0 +1,65 @@
const fs = require('fs');
// Get the file name from the command line arguments
const fileName = process.argv[2];
// Check if a file name is provided
if (!fileName) {
console.error('Please provide a file name.');
process.exit(1);
}
let FileContiner = `
import React from 'react'
import LayoutModal from '../../Layout/Dashboard/LayoutModal'
import Form${capitalizeFirstLetter(fileName)} from './Form${capitalizeFirstLetter(fileName)}'
import { useAdd${capitalizeFirstLetter(fileName)} } from '../../api/${(fileName)}'
import { getDataToSend, getInitialValues, getValidationSchema } from './formUtil'
import { QueryStatusEnum } from '../../config/QueryStatus'
import { useTranslation } from 'react-i18next'
function Add${capitalizeFirstLetter(fileName)}Modal() {
const [t] = useTranslation()
const {mutate , status} = useAdd${capitalizeFirstLetter(fileName)}()
const handelSubmit = (values:any )=>{
const dataToSend = getDataToSend(values)
mutate(dataToSend)
// Submit Value
}
return (
<LayoutModal
isAddModal={true}
getInitialValues={getInitialValues()}
handleSubmit={handelSubmit}
status={status as QueryStatusEnum}
headerText={t('Add') +t('${(fileName)}')}
getValidationSchema={getValidationSchema()}>
<Form${capitalizeFirstLetter(fileName)} />
</LayoutModal>
)
}
export default Add${capitalizeFirstLetter(fileName)}Modal
`
fs.writeFileSync('src/Pages/'+fileName+"/"+"Add"+ capitalizeFirstLetter(fileName)+"Modal.tsx",
FileContiner
);
console.log(`File "${fileName}" generated successfully.`);
function capitalizeFirstLetter(word) {
return (word).charAt(0).toUpperCase() + (word).slice(1);
}

View File

@ -0,0 +1,40 @@
const fs = require('fs');
const fileName = process.argv[2]
if (!fileName) {
console.error('Please provide a file name.');
process.exit(1);
}
let FileContiner = `
import useAddMutation from "./helper/useAddMutation"
import useDeleteMutation from "./helper/useDeleteMutation"
import useGetQuery from "./helper/useGetQuery"
import useUpdateMutation from "./helper/useUpdateMutation"
const API = {
GET: "/api/admin/${fileName}",
ADD: "/api/admin/${fileName}/create",
UPDATE: "/api/admin/${fileName}/update",
DELETE: "/api/admin/${fileName}/delete",
};
const KEY = "${fileName.toUpperCase()}";
export const useGet${capitalizeFirstLetter(fileName)} = (params?:any) => useGetQuery(KEY, API.GET, params);
export const useAdd${capitalizeFirstLetter(fileName)} = () => useAddMutation(KEY, API.ADD);
export const useUpdate${capitalizeFirstLetter(fileName)} = () => useUpdateMutation(KEY, API.UPDATE);
export const useDelete${capitalizeFirstLetter(fileName)} = () =>useDeleteMutation(KEY, API.DELETE);
`
fs.writeFileSync('src/api/'+fileName+".ts",
FileContiner
);
console.log(`File "${fileName}" generated successfully.`);
function capitalizeFirstLetter(word) {
return (word).charAt(0).toUpperCase() + (word).slice(1);
}

View File

@ -0,0 +1,63 @@
const fs = require('fs');
// Get the file name from the command line arguments
const fileName = process.argv[2];
// Check if a file name is provided
if (!fileName) {
console.error('Please provide a file name.');
process.exit(1);
}
let FileContiner = `
import React, { useMemo } from "react";
import { useTranslation } from "react-i18next";
import Actions from "../../Components/Ui/tables/Actions";
function fnDelete(props :any ){}
const useTableColumns :any = () => {
const [t] = useTranslation();
return useMemo(
() => [
{
name: t("email"),
sortable: false,
center: "true",
cell: (row:any) => row?.email
},
{
name: "#",
sortable: false,
center: "true",
cell: (row) => (
<Actions
// importnat to return the row in on Edit Function to store in objectToEdit That Upper in Edit Modal
onEdit={() => row}
onView={()=>{}}
objectToEdit={row}
showEdit={true}
// showDelete={false}
onDelete={() => fnDelete({ id: row.id })}
/>
),
},
],
[t]
);
};
export default useTableColumns;
`
fs.writeFileSync('src/Pages/'+fileName+"/useTableColumns"+".tsx",
FileContiner
);
console.log(`File "${fileName}" generated successfully.`);

View File

@ -0,0 +1,30 @@
const { exec } = require('child_process');
const fileName = process.argv[2]
const CreateApi = `node src/Extensions/FileGenerator/generateApi.js ${fileName}`
const CreatePage = `node src/Extensions/FileGenerator/generatePage.js ${fileName}`
const CreateColumn = `node src/Extensions/FileGenerator/generateColumn.js ${fileName}`
const CreateformUtil= `node src/Extensions/FileGenerator/generateformUtils.js ${fileName}`
const CreateAddModal= `node src/Extensions/FileGenerator/generateAddModal.js ${fileName}`
const CreateEditModal= `node src/Extensions/FileGenerator/generateEditModal.js ${fileName}`
const CreateForm= `node src/Extensions/FileGenerator/generateForm.js ${fileName}`
const RunCommand = async()=>{
exec(CreatePage)
exec(CreateApi)
setTimeout(()=>{},100)
exec(CreateColumn)
exec(CreateformUtil)
exec(CreateAddModal)
exec(CreateEditModal)
exec(CreateForm)
}
RunCommand()

View File

@ -0,0 +1,47 @@
const fs = require('fs');
// Get the file name from the command line arguments
const fileName = process.argv[2];
// Check if a file name is provided
if (!fileName) {
console.error('Please provide a file name.');
process.exit(1);
}
let FileContiner = `
import React from 'react'
import LayoutModal from '../../Layout/Dashboard/LayoutModal'
import Form${capitalizeFirstLetter(fileName)} from './Form${capitalizeFirstLetter(fileName)}'
import { getInitialValues, getValidationSchema } from './formUtil'
import { usePageState } from '../../lib/state mangment/LayoutPagestate'
function Edit${capitalizeFirstLetter(fileName)}Modal() {
const {objectToEdit} = usePageState()
return (
<LayoutModal
isAddModal={false}
getInitialValues={getInitialValues(objectToEdit)}
handleSubmit={() => { }}
headerText='Edit Modal'
getValidationSchema={getValidationSchema(objectToEdit)}>
<Form${capitalizeFirstLetter(fileName)} />
</LayoutModal>
)
}
export default Edit${capitalizeFirstLetter(fileName)}Modal
`
fs.writeFileSync('src/Pages/'+fileName+"/"+"Edit"+ capitalizeFirstLetter(fileName)+"Modal.tsx",
FileContiner
);
console.log(`File "${fileName}" generated successfully.`);
function capitalizeFirstLetter(word) {
return (word).charAt(0).toUpperCase() + (word).slice(1);
}

View File

@ -0,0 +1,66 @@
const fs = require('fs');
// Get the file name from the command line arguments
const fileName = process.argv[2];
// Check if a file name is provided
if (!fileName) {
console.error('Please provide a file name.');
process.exit(1);
}
let FileContiner = `
import React from 'react'
import { Col, Row } from 'reactstrap';
import ValidationField from '../../Components/ValidationField/ValidationField';
import { FakeSelectData } from '../../Layout/app/Const';
import { useFormikContext } from 'formik';
import { DatePicker } from 'antd';
function Form${capitalizeFirstLetter(fileName)}() {
const formik = useFormikContext<any>();
return (
<Row xs={1} sm={1} md={1} lg={2} xl={2}>
<Col>
// name from form utils
<ValidationField name="name" type="text"label='name' placeholder='placeholder' />
<ValidationField name="number" type="number" label='number' placeholder='placeholder' />
<ValidationField name="select" type="select"label='select' option={FakeSelectData} isMulti={true} placeholder='placeholder' />
<ValidationField name="Multiselect" type="select"label='Multiselect' option={FakeSelectData} Disabled={true} placeholder='placeholder'/>
</Col>
<Col>
<ValidationField name="date" type="date" label='date' placeholder='placeholder' />
<ValidationField name="time" type="text"label='time' placeholder='placeholder' />
<ValidationField name="CheckBox" name2='CheckBox2' type="checkbox" label='CheckBox' placeholder='placeholder' group={true} />
<ValidationField name="DateFrom" name2="DateTo" type="DataRange" />
</Col>
</Row>
)
}
export default Form${capitalizeFirstLetter(fileName)}
`
fs.writeFileSync('src/Pages/'+fileName+'/Form'+ capitalizeFirstLetter(fileName)+".tsx",
FileContiner
);
console.log(`File "${fileName}" generated successfully.`);
function capitalizeFirstLetter(word) {
return (word).charAt(0).toUpperCase() + (word).slice(1);
}

View File

@ -0,0 +1,64 @@
const fs = require('fs');
// Get the file name from the command line arguments
const fileName = process.argv[2];
// Check if a file name is provided
if (!fileName) {
console.error('Please provide a file name.');
process.exit(1);
}
let FileContiner = `
import React from 'react'
import LayoutModal from '../../Layout/Dashboard/LayoutModal'
import Form${capitalizeFirstLetter(fileName)} from './Form${capitalizeFirstLetter(fileName)}'
import { useAdd${capitalizeFirstLetter(fileName)} } from '../../api/${(fileName)}'
import { getDataToSend, getInitialValues, getValidationSchema } from './formUtil'
import { QueryStatusEnum } from '../../config/QueryStatus'
import { useTranslation } from 'react-i18next'
function Add${capitalizeFirstLetter(fileName)}Modal() {
const [t] = useTranslation()
const {mutate , status} = useAdd${capitalizeFirstLetter(fileName)}()
const handelSubmit = (values:any )=>{
const dataToSend = getDataToSend(values)
mutate(dataToSend)
// Submit Value
}
return (
<LayoutModal
isAddModal={true}
getInitialValues={getInitialValues()}
handleSubmit={handelSubmit}
status={status as QueryStatusEnum}
headerText={t('Add') +t('${(fileName)}')}
getValidationSchema={getValidationSchema()}>
<Form${capitalizeFirstLetter(fileName)} />
</LayoutModal>
)
}
export default Add${capitalizeFirstLetter(fileName)}Modal
`
fs.writeFileSync('src/Pages/'+fileName+"/"+"Add"+ capitalizeFirstLetter(fileName)+"Modal.tsx",
FileContiner
);
console.log(`File "${fileName}" generated successfully.`);
function capitalizeFirstLetter(word) {
return (word).charAt(0).toUpperCase() + (word).slice(1);
}

View File

@ -0,0 +1,67 @@
const fs = require('fs');
// Get the file name from the command line arguments
const fileName = process.argv[2];
// Check if a file name is provided
if (!fileName) {
console.error('Please provide a file name.');
process.exit(1);
}
const folderPath = 'src/Pages/'+fileName;
if (!fs.existsSync(folderPath)) {
fs.mkdirSync(folderPath, { recursive: true });
}
let FileContiner = `
import React from 'react'
import DashBody from '../../Layout/Dashboard/DashBody'
import DashHeader from '../../Layout/Dashboard/DashHeader'
import LyTable from '../../Layout/Dashboard/LyTable'
import useTableColumns from './useTableColumns'
import { useGet${capitalizeFirstLetter(fileName)}} from '../../api/${fileName}'
import { QueryStatusEnum } from '../../config/QueryStatus'
import Edit${capitalizeFirstLetter(fileName)}Modal from './Edit${capitalizeFirstLetter(fileName)}Modal'
import Add${capitalizeFirstLetter(fileName)}Modal from './Add${capitalizeFirstLetter(fileName)}Modal'
function ${capitalizeFirstLetter(fileName)}Page() {
const column =useTableColumns()
const {data ,status } = useGet${capitalizeFirstLetter(fileName)}()
return (
// Pass Status to Layout
<DashBody status={status as QueryStatusEnum} >
<DashHeader title={'${capitalizeFirstLetter(fileName)}'}></DashHeader>
<LyTable
data={data}
isLoading={false}
columns={column}
/>
<Edit${capitalizeFirstLetter(fileName)}Modal />
<Add${capitalizeFirstLetter(fileName)}Modal />
</DashBody>
)
}
export default ${capitalizeFirstLetter(fileName)}Page
`
fs.writeFileSync('src/Pages/'+fileName+"/"+capitalizeFirstLetter(fileName)+"Page.tsx",
FileContiner
);
console.log(`File "${fileName}" generated successfully.`);
function capitalizeFirstLetter(word) {
return (word).charAt(0).toUpperCase() + (word).slice(1);
}

View File

@ -0,0 +1,73 @@
const fs = require('fs');
// Get the file name from the command line arguments
const fileName = process.argv[2];
// Check if a file name is provided
if (!fileName) {
console.error('Please provide a file name.');
process.exit(1);
}
let FileContiner = `
import * as Yup from "yup";
import { buildFormData } from "../../api/helper/buildFormData";
interface formUtilCommon {
name:string,
email:string
}
interface ObjectToEdit extends formUtilCommon {
id?:number,
}
interface InitialValues extends ObjectToEdit {
}
interface ValidateSchema extends formUtilCommon{
}
export const getInitialValues = (objectToEdit: ObjectToEdit | null = null): InitialValues => {
return {
id:objectToEdit?.id?? 0 ,
name:objectToEdit?.name ?? "",
email:objectToEdit?.email?? ""
}
};
export const getValidationSchema = (editMode: boolean = false): Yup.Schema<ValidateSchema> => {
// validate input
return Yup.object().shape({
name:Yup.string().required('required'),
email:Yup.string().required("required")
});
};
export const getDataToSend = (values: any): FormData => {
const data = { ...values };
const formData = new FormData();
buildFormData(formData, data);
return formData;
};
`
fs.writeFileSync('src/Pages/'+fileName+"/"+"formUtil.ts",
FileContiner
);
console.log(`File "${fileName}" generated successfully.`);
function capitalizeFirstLetter(word) {
return (word).charAt(0).toUpperCase() + (word).slice(1);
}

45
src/Hooks/WithDrawer.tsx Normal file
View File

@ -0,0 +1,45 @@
import React, { useState, ReactNode } from 'react';
import type { DrawerProps } from 'antd';
import { Drawer, Space } from 'antd';
interface WithDrawerProps {
button: React.ReactNode;
children: ReactNode;
title:string;
className?:string,
iopen?:boolean,
setOpen:any
}
const WithDrawer: React.FC<WithDrawerProps> = ({ children,title ="Basic Drawer",className ,setOpen, iopen }) => {
const [placement, setPlacement] = useState<DrawerProps['placement']>('right');
return (
<>
<Drawer
// title={title}
placement={placement}
closable={false}
onClose={() => setOpen(false)}
open={iopen}
key={placement}
>
<div className={className}>
{children}
</div>
</Drawer>
</>
);
};
export default WithDrawer;
// <WithDrawer
// button={<Button type="primary">Open</Button>}
// >
// {/* Your content goes here */}
// </WithDrawer>

View File

@ -0,0 +1,13 @@
export async function fetchImage(imageUrl:any) {
try {
const response = await fetch(imageUrl);
if (!response.ok) {
throw new Error(`Failed to fetch image: ${response.status} ${response.statusText}`);
}
const blob = await response.blob();
return new File([blob], 'image.png', { type: 'image/png' });
} catch (error) {
console.error('Error fetching image:', error);
return null;
}
}

3
src/Hooks/isEmpty.tsx Normal file
View File

@ -0,0 +1,3 @@
export const isEmpty = (Type:any) => {
return !Type || (Array.isArray(Type) && Type.length === 0);
};

View File

@ -0,0 +1,75 @@
import { useEffect } from 'react';
import { initReactI18next, useTranslation } from 'react-i18next';
import i18n from 'i18next';
import translationEN from '../translate/en.json';
import translationAR from '../translate/ar.json';
import translationCN from '../translate/cn.json';
const language = localStorage.getItem('language') ?? 'en';
i18n.use(initReactI18next).init({
resources: {
en: {
translation: translationEN
},
ar: {
translation: translationAR
},
cn: {
translation: translationCN
}
},
lng: language,
interpolation: {
escapeValue: false
}
});
export function useLanguage() {
useEffect(() => {
changeLanguage(language);
}, [language]);
const changeLanguage = (newLanguage:any) => {
i18n.changeLanguage(newLanguage);
localStorage.setItem('language', newLanguage);
applyLanguageStyles(newLanguage);
};
return { changeLanguage };
}
function applyLanguageStyles(language:any) {
if (language === 'ar') {
document.body.setAttribute('dir', 'rtl');
document.body.classList.remove('cn');
document.body.classList.add('ar');
} else if (language === 'en') {
document.body.setAttribute('dir', 'ltr');
document.body.classList.remove('ar', 'cn');
document.body.classList.add('en');
} else if (language === 'cn') {
document.body.setAttribute('dir', 'ltr');
document.body.classList.remove('ar');
document.body.classList.add('cn');
}
}
export function useLanguageMenu() {
const { t } = useTranslation();
const { changeLanguage } = useLanguage();
const languageOptions = [
{ code: 'ar', icon: '/language/ar.svg', label: t('Arabic') },
{ code: 'en', icon: '/language/en.svg', label: t('English') },
{ code: 'cn', icon: '/language/china.svg', label: t('Chinese') }
];
const handleLanguageChange = (code:any) => {
changeLanguage(code);
};
return { languageOptions, handleLanguageChange };
}

View File

@ -0,0 +1,16 @@
import { useEffect, useRef } from "react";
export const useEventListener = (eventType:any, callback:any, element = window) => {
const callbackRef = useRef(callback);
useEffect(() => {
callbackRef.current = callback;
}, [callback]);
useEffect(() => {
const handler = (e:any) => callbackRef.current(e);
element.addEventListener(eventType, handler);
return () => element.removeEventListener(eventType, handler);
}, [eventType, element]);
};

View File

@ -0,0 +1,16 @@
import { useField, useFormikContext } from 'formik';
import { useTranslation } from 'react-i18next';
import { Field } from 'formik';
const useFormField = (name: string, props?: any) => {
const [field, meta] = useField({ name, ...props });
const { t } = useTranslation();
const formik = useFormikContext<any>();
const isError = meta.touched && meta.error;
const errorMsg = meta.error ? t(meta.error.toString()) : '';
return { Field, field, meta, formik, isError, errorMsg, t };
};
export default useFormField;

View File

@ -0,0 +1,16 @@
const useFormatToSelect = (Data : any) => {
const format = (data :any) => {
if (!data) return [];
const language = localStorage.getItem("language") ?? "en";
return data.map((item :any) => ({
value: item?.id,
label: item?.name[language],
}));
};
return format(Data);
};
export default useFormatToSelect;

View File

@ -0,0 +1,9 @@
import React from 'react'
const useImageError = ({currentTarget}:any) => {
const ErrorImage = "https://upload.wikimedia.org/wikipedia/commons/thumb/6/65/No-Image-Placeholder.svg/832px-No-Image-Placeholder.svg.png"
currentTarget.onerror = null;
currentTarget.src=`${ErrorImage}`;
}
export default useImageError

View File

@ -0,0 +1,21 @@
import { useState, useEffect } from 'react';
function useLoadingState(initialValue: boolean, duration: number): [boolean, () => void] {
const [loading, setLoading] = useState<boolean>(initialValue);
useEffect(() => {
const timeoutId = setTimeout(() => {
setLoading(false);
}, duration);
return () => clearTimeout(timeoutId);
}, [duration]);
const resetLoading = () => {
setLoading(true);
};
return [loading, resetLoading];
}
export default useLoadingState;

View File

@ -0,0 +1,20 @@
import React, { useEffect } from 'react'
import { useNavigate } from 'react-router-dom'
function useNavigateOnSuccess(isSuccess :boolean , to_path:string , callbackAfterSuccess?:any) {
const navigate = useNavigate()
useEffect(()=>{
if(isSuccess){
if (typeof callbackAfterSuccess === 'function') {
callbackAfterSuccess()
}
navigate(to_path )
}
},[isSuccess])
}
export default useNavigateOnSuccess

View File

@ -0,0 +1,38 @@
import { Pagination } from "antd";
import { useTranslation } from "react-i18next";
import { useLocation, useNavigate, useSearchParams } from "react-router-dom";
export const PaginationBody = ({ data }: any) => {
const navigate = useNavigate();
const location = useLocation();
const pagination = location?.search || '';
const currentPage = parseInt(new URLSearchParams(location.search).get("page") || "1", 10);
const pageSize = parseInt(new URLSearchParams(location.search).get("per_page") || "15", 10);
const [searchParams] = useSearchParams()
const onChange = (page: number, pageSize?: number) => {
navigate(`?page=${page}&per_page=${pageSize || data?.per_page}`);
};
const onShowSizeChange = (current: number, pageSize: number) => {
navigate(`?page=${current}&per_page=${pageSize}`);
};
const [t] = useTranslation()
return (
<Pagination
className='text-center mt-3 paginateStyle'
total={data}
showTotal={(total: any) => `${t(`Total`)} ${total} ${t(`items`)}`}
pageSize={pageSize}
pageSizeOptions={[6, 15, 22, 30]}
defaultCurrent={currentPage}
current={currentPage}
onChange={onChange}
onShowSizeChange={onShowSizeChange}
// showQuickJumper
showSizeChanger
/>
);
};

View File

@ -0,0 +1,18 @@
import { useState } from "react";
import { useEventListener } from "./useEventListener";
export const useWindowSize = () => {
const [windowSize, setWindowSize] = useState({
width: window.innerWidth,
height: window.innerHeight,
});
useEventListener("resize", () => {
setWindowSize({
width: window.innerWidth,
height: window.innerHeight,
});
});
return windowSize;
};

View File

@ -0,0 +1,33 @@
import React from 'react'
import './Add_Button.scss'
import { useTranslation } from 'react-i18next'
import { usePageState } from '../../../lib/state mangment/LayoutPagestate'
const AddButton = (props :any) => {
const [t] = useTranslation();
return (
<div className='Add_Button' {...props} >
<button >
<span >
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
width={24}
height={24}
>
<path fill="none" d="M0 0h24v24H0z" />
<path fill="currentColor" d="M11 11V5h2v6h6v2h-6v6h-2v-6H5v-2z" />
</svg>{" "}
{t("Add")}
</span>
</button>
</div>
)
}
export default AddButton

View File

@ -0,0 +1,41 @@
import React from 'react'
import './Add_Button.scss'
import { useTranslation } from 'react-i18next'
import { usePageState } from '../../../lib/state mangment/LayoutPagestate'
const AddButtonLayout = ({haveAddModal}:any) => {
const { setIsOpenAddModel , setObjectToEdit } = usePageState()
const [t] = useTranslation();
return (
<div className='Add_Button' onClick={()=>{
if(haveAddModal){
setIsOpenAddModel()
}
setObjectToEdit(null)
}}>
<button>
<span >
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
width={24}
height={24}
>
<path fill="none" d="M0 0h24v24H0z" />
<path fill="currentColor" d="M11 11V5h2v6h6v2h-6v6h-2v-6H5v-2z" />
</svg>{" "}
{t("Add")}
</span>
</button>
</div>
)
}
export default AddButtonLayout

View File

@ -0,0 +1,77 @@
.Add_Button{
button {
border: 2px solid var(--primary);
background-color: var(--primary);
border-radius: 0.5vw;
height: 40px;
width: 70px;
font-size: 1vw ;
display: flex; justify-content: center; align-items: center;
box-shadow: 2px 2px 7px 0 var(--primary);
}
button span {
display: flex;
align-items: center;
color: var(--bg);
font-weight: normal;
font-size: 14px;
}
button:hover {
background-color:var(--primary);
}
}
@media screen and (max-width: 700px) {
.Add_Button{
button{
font-size: 2vw !important;
}
}
}
@media screen and (max-width: 470px) {
.Add_Button{
button{
font-size: 3vw !important;
}
}
}
.Add_Button_notification{
button {
border: 2px solid var(--primary);
background-color: var(--primary);
border-radius: 0.5vw;
height: 40px;
width: 180px;
font-size: 1vw ;
display: flex; justify-content: center; align-items: center;
box-shadow: 2px 2px 7px 0 var(--primary);
}
button span {
display: flex;
align-items: center;
color: var(--bg);
font-weight: normal;
font-size: 14px;
}
button:hover {
background-color:var(--primary);
}
}
@media screen and (max-width: 700px) {
.Add_Button_notification{
button{
font-size: 2vw !important;
}
}
}
@media screen and (max-width: 470px) {
.Add_Button_notification{
button{
font-size: 3vw !important;
}
}
}

View File

@ -0,0 +1,32 @@
import { Spinner } from "reactstrap"
import { QueryStatusEnum } from "../../config/QueryStatus"
import LoadingPage from "../app/LoadingPage"
import { useTranslation } from "react-i18next"
import { BsEmojiFrown } from "react-icons/bs";
import ErrorPage from "../app/ErrorPage";
const DashBody = ({ children , status }: { children: React.ReactNode ,status?:QueryStatusEnum }) => {
const {t} = useTranslation();
// Add You Custom Loadaing Page
if(status === QueryStatusEnum.LOADING){
return <LoadingPage />
}
// Add Your Custom Error Page
if(status === QueryStatusEnum.ERROR){
return (
<ErrorPage/>
)
}
return (
<div className='Page' >
{ children }
</div>
)
}
export default DashBody

View File

@ -0,0 +1,27 @@
import React from "react";
import AddButtonLayout from "./AddButton/AddButtonLayout";
import { useTranslation } from "react-i18next";
interface DashHeaderProp {
title: string;
children?: React.ReactNode;
showAddButton?: boolean;
haveAddModal?:boolean
}
const DashHeader = ({
children,
title,
haveAddModal= true ,
showAddButton = true,
}: DashHeaderProp) => {
const [t] = useTranslation();
return (
<div className="Page_Header">
<h3>{t(`${title}`)}</h3>
{children}
{showAddButton && <AddButtonLayout haveAddModal={haveAddModal}/>}
</div>
);
};
export default DashHeader;

View File

@ -0,0 +1,42 @@
import { Formik, Form } from 'formik';
import React, { ReactNode } from 'react';
import { Button } from "reactstrap";
import * as Yup from 'yup';
interface FormValues {
[key: string]: any;
}
interface FormPageProps {
handleSubmit: (values: any) => void
initialValues: FormValues;
validationSchema: any;
title?: string;
children: ReactNode;
}
const FormPage: React.FC<FormPageProps> = ({ children, handleSubmit, initialValues, validationSchema, title = "Edit Item" }) => {
return (
<>
<h4 className='text-bold'>{title}</h4>
<div className="Card">
<Formik
initialValues={initialValues}
validationSchema={validationSchema}
onSubmit={handleSubmit}
>
{formik => (
<Form>
{children}
<div className='w-100 d-flex justify-content-center'>
<Button type='submit' color="primary" className='mt-4 w-25 text-center'>Submit</Button>
</div>
</Form>
)}
</Formik>
</div>
</>
);
};
export default FormPage;

View File

@ -0,0 +1,67 @@
import { Formik, Form } from 'formik';
import React, { ReactNode } from 'react';
import { useTranslation } from 'react-i18next';
import { Button } from "reactstrap";
import * as Yup from 'yup';
interface FormValues {
[key: string]: any;
}
interface FormikFormProps {
handleSubmit: (values: any) => void
initialValues: FormValues;
validationSchema: any;
title?: string;
children: ReactNode;
ButtonName?:string
}
const FormikForm: React.FC<FormikFormProps> = ({ children, handleSubmit, initialValues, validationSchema, title = "Add New Item" ,ButtonName="إضافة"}) => {
const [t]= useTranslation()
return (
<>
<Formik
initialValues={initialValues}
validationSchema={validationSchema}
onSubmit={handleSubmit}
>
{formik => (
<Form >
<div className="Card">
{children}
</div>
</Form>
)}
</Formik>
</>
);
};
export default FormikForm;
{/* <FormikForm
handleSubmit={() => {
}}
initialValues={() => {
return {
id: null,
name: "",
}
}}
validationSchema={() => {
return Yup.object().shape({
name: Yup.string().required('required'),
});
}}
>
</FormikForm> */}

View File

@ -0,0 +1,77 @@
import { Form, Formik } from 'formik'
import React, { useEffect } from 'react'
import { Button, Modal, ModalBody, ModalFooter, ModalHeader } from 'reactstrap'
import { usePageState } from '../../lib/state mangment/LayoutPagestate'
import { useTranslation } from 'react-i18next';
import { LoadingButton } from '../../Components/Ui/LoadingButton';
import { QueryStatusEnum } from '../../config/QueryStatus';
interface LayoutModalProps {
isAddModal: boolean;
headerText: string;
handleSubmit: (values: any) => void;
getInitialValues: any;
getValidationSchema: any;
children: React.ReactNode;
status?:QueryStatusEnum
}
function LayoutModal({isAddModal , headerText , handleSubmit =()=>{} , getInitialValues , getValidationSchema,status ,children}:LayoutModalProps) {
const {isOpenAddModel ,setIsOpenAddModel , setIsOpenEditModel ,isOpenEditModel , objectToEdit , CloseAllModal} = usePageState(state => state)
useEffect(()=>{
if(status === QueryStatusEnum.SUCCESS){
CloseAllModal()
}
},[status , CloseAllModal])
const [t] = useTranslation()
return (
<Modal centered isOpen={isAddModal ? isOpenAddModel :isOpenEditModel} size="lg" >
<ModalHeader className='ModalHeader' toggle={() => isAddModal ?setIsOpenAddModel() : setIsOpenEditModel()} >
{t(headerText)}
</ModalHeader>
{
(( objectToEdit != null && isOpenEditModel) || isOpenAddModel) &&
<Formik
onSubmit={handleSubmit}
initialValues={getInitialValues}
validationSchema={getValidationSchema}
>
{(formik) => (
<Form>
<ModalBody>
{children}
</ModalBody>
<ModalFooter>
<Button
disabled={status === QueryStatusEnum.LOADING}
onClick={() => isAddModal ?setIsOpenAddModel() : setIsOpenEditModel()}
color="danger"
>
{t("cancel")}
</Button>
<LoadingButton
type="submit"
color="primary"
isLoading={status === QueryStatusEnum.LOADING}
>
{t(isAddModal ? "Add" :"edit")}
</LoadingButton>
</ModalFooter>
</Form>
)}
</Formik>
}
</Modal>
)
}
export default LayoutModal

View File

@ -0,0 +1,39 @@
import DataTable from 'react-data-table-component';
import { Card, CardBody, Spinner } from 'reactstrap';
import { PaginationBody } from '../../Hooks/usePagination';
import { useTranslation } from 'react-i18next';
const LyTable = (props?: any) => {
const {t} = useTranslation();
return (
<div className='LayoutBody'>
<Card>
<CardBody>
<DataTable
columns={props?.column}
data={props?.data}
progressPending={props?.isLoading}
noDataComponent={<h6 className="my-4">{t("no_records")}</h6>}
noHeader
pagination
progressComponent={<Spinner />}
{...(props.is_pagination && {
paginationServer: true,
paginationComponent: () => <PaginationBody data={props?.total} />
})}
{...props}
/>
</CardBody>
</Card>
</div>
)
}
export default LyTable

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