first push
23
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
# 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
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
13
.vscode/settings.json
vendored
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"cSpell.words": [
|
||||
"aldeen",
|
||||
"currentlanguage",
|
||||
"Datepicker",
|
||||
"formik",
|
||||
"Karim",
|
||||
"queryqlent",
|
||||
"setstyle",
|
||||
"szhsin",
|
||||
"Viewelement"
|
||||
]
|
||||
}
|
||||
48
db.json
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
{
|
||||
"example":[
|
||||
{
|
||||
"type": "Bernadette O'Reilly",
|
||||
"href": "/Dennis Von",
|
||||
"data": [
|
||||
|
||||
],
|
||||
"count": 48,
|
||||
"id": "10"
|
||||
},
|
||||
{
|
||||
"type": "Jeanette",
|
||||
"href": "/Patsy",
|
||||
"data": [
|
||||
|
||||
],
|
||||
"count": 32613,
|
||||
"id": "12"
|
||||
},
|
||||
{
|
||||
"type": "Marion",
|
||||
"href": "/MissLuis",
|
||||
"data": [
|
||||
|
||||
],
|
||||
"count": 71846,
|
||||
"id": "13"
|
||||
},
|
||||
{
|
||||
"type": "Jean",
|
||||
"href": "/Georgia",
|
||||
"data": [
|
||||
|
||||
],
|
||||
"count": 8268,
|
||||
"id": "14"
|
||||
}
|
||||
],
|
||||
"users": [
|
||||
{
|
||||
"id": 1,
|
||||
"email": "admin@adamin.com",
|
||||
"password": "password",
|
||||
"token": "token"
|
||||
}
|
||||
]
|
||||
}
|
||||
20
index.html
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
<!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"
|
||||
/>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
|
||||
|
||||
<title>React-ts</title>
|
||||
</head>
|
||||
<script type="module" src="/src/index.tsx"></script>
|
||||
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
34650
package-lock.json
generated
Normal file
104
package.json
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
{
|
||||
"name": "my-app",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@ant-design/icons": "^5.2.6",
|
||||
"@emailjs/browser": "^4.3.3",
|
||||
"@reduxjs/toolkit": "^1.9.7",
|
||||
"@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",
|
||||
"@types/jest": "^27.5.2",
|
||||
"@types/node": "^16.18.60",
|
||||
"@types/react": "^18.2.33",
|
||||
"@types/react-dom": "^18.2.14",
|
||||
"@types/react-slick": "^0.23.12",
|
||||
"@wojtekmaj/react-daterange-picker": "^5.4.4",
|
||||
"antd": "^5.11.1",
|
||||
"apexcharts": "^3.44.0",
|
||||
"axios": "^1.6.0",
|
||||
"bootstrap": "^5.3.2",
|
||||
"chart.js": "^4.4.0",
|
||||
"dayjs": "^1.11.10",
|
||||
"formik": "^2.4.5",
|
||||
"i18next": "^23.6.0",
|
||||
"i18next-browser-languagedetector": "^7.1.0",
|
||||
"json-server": "^0.17.4",
|
||||
"mdb-react-ui-kit": "^7.2.0",
|
||||
"react": "^18.2.0",
|
||||
"react-alice-carousel": "^2.8.0",
|
||||
"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-id-swiper": "^4.0.0",
|
||||
"react-multi-carousel": "^2.8.4",
|
||||
"react-player": "^2.16.0",
|
||||
"react-query": "^3.39.3",
|
||||
"react-redux": "^8.1.3",
|
||||
"react-responsive-carousel": "^3.2.23",
|
||||
"react-router-dom": "^6.18.0",
|
||||
"react-scripts": "5.0.1",
|
||||
"react-select-country-list": "^2.2.3",
|
||||
"react-slick": "^0.29.0",
|
||||
"react-tabs": "^6.0.2",
|
||||
"react-toastify": "^9.1.3",
|
||||
"react-toggle": "^4.1.3",
|
||||
"react-transition-group": "^4.4.5",
|
||||
"react-verification-code-input": "^1.2.9",
|
||||
"reactstrap": "^9.2.0",
|
||||
"sass": "^1.69.5",
|
||||
"slick-carousel": "^1.8.1",
|
||||
"source-map-explorer": "^2.5.3",
|
||||
"styled-components": "5.3.3",
|
||||
"swiper": "^11.0.5",
|
||||
"typescript": "^4.9.5",
|
||||
"web-vitals": "^2.1.4",
|
||||
"yup": "^1.3.2",
|
||||
"zustand": "^4.4.5"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "vite",
|
||||
"build": "vite 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 ",
|
||||
"analyze": "source-map-explorer 'build/static/js/*.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": {
|
||||
"@vitejs/plugin-react": "^4.3.0",
|
||||
"unplugin-auto-import": "^0.17.6",
|
||||
"vite": "^5.2.12"
|
||||
}
|
||||
}
|
||||
12898
pnpm-lock.yaml
Normal file
BIN
public/App/DarkBlueBg.png
Normal file
|
After Width: | Height: | Size: 283 KiB |
BIN
public/App/DarkBlueBgRes.png
Normal file
|
After Width: | Height: | Size: 110 KiB |
BIN
public/App/ServiceIconBg.png
Normal file
|
After Width: | Height: | Size: 3.2 KiB |
BIN
public/App/WhiteBg.png
Normal file
|
After Width: | Height: | Size: 861 KiB |
BIN
public/App/WhiteBgRes.png
Normal file
|
After Width: | Height: | Size: 354 KiB |
BIN
public/Home/HeroBg.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
BIN
public/Home/HeroBgRes.png
Normal file
|
After Width: | Height: | Size: 160 KiB |
7
public/Home/HeroBorder.svg
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
<svg width="158" height="367" viewBox="0 0 158 367" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<line x1="-0.00195312" y1="2.62891" x2="157.011" y2="2.62891" stroke="#50A3EF" stroke-width="4"/>
|
||||
<path d="M2 364.129L155 364.129" stroke="#50A3EF" stroke-width="4" stroke-linecap="round"/>
|
||||
<line x1="1.99609" y1="1.99998" x2="2.00002" y2="364.129" stroke="#50A3EF" stroke-width="4"/>
|
||||
<line x1="155" y1="3.12891" x2="155" y2="54.1289" stroke="#50A3EF" stroke-width="4"/>
|
||||
<path d="M153.373 364.129C153.373 365.234 154.268 366.129 155.373 366.129C156.478 366.129 157.373 365.234 157.373 364.129H153.373ZM153.373 263.125V364.129H157.373V263.125H153.373Z" fill="#50A3EF"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 675 B |
BIN
public/Home/about_left_image.png
Normal file
|
After Width: | Height: | Size: 384 KiB |
BIN
public/Home/scrollDown.png
Normal file
|
After Width: | Height: | Size: 6.0 KiB |
1
public/Layout/Ar.svg
Normal file
|
After Width: | Height: | Size: 10 KiB |
1
public/Layout/En.svg
Normal 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 |
BIN
public/Layout/FooterImage.png
Normal file
|
After Width: | Height: | Size: 624 KiB |
1
public/Layout/dark.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 64 64"><path fill="currentColor" d="M43.139 2a29.885 29.885 0 0 1 5.121 16.756c0 16.701-13.686 30.24-30.57 30.24a30.656 30.656 0 0 1-15.689-4.285C7.209 54.963 17.93 62 30.318 62C47.816 62 62 47.969 62 30.66C62 17.867 54.246 6.871 43.139 2z"/></svg>
|
||||
|
After Width: | Height: | Size: 324 B |
1
public/Layout/light.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 512 512"><path fill="currentColor" d="M256 160c-52.9 0-96 43.1-96 96s43.1 96 96 96s96-43.1 96-96s-43.1-96-96-96zm246.4 80.5l-94.7-47.3l33.5-100.4c4.5-13.6-8.4-26.5-21.9-21.9l-100.4 33.5l-47.4-94.8c-6.4-12.8-24.6-12.8-31 0l-47.3 94.7L92.7 70.8c-13.6-4.5-26.5 8.4-21.9 21.9l33.5 100.4l-94.7 47.4c-12.8 6.4-12.8 24.6 0 31l94.7 47.3l-33.5 100.5c-4.5 13.6 8.4 26.5 21.9 21.9l100.4-33.5l47.3 94.7c6.4 12.8 24.6 12.8 31 0l47.3-94.7l100.4 33.5c13.6 4.5 26.5-8.4 21.9-21.9l-33.5-100.4l94.7-47.3c13-6.5 13-24.7.2-31.1zm-155.9 106c-49.9 49.9-131.1 49.9-181 0c-49.9-49.9-49.9-131.1 0-181c49.9-49.9 131.1-49.9 181 0c49.9 49.9 49.9 131.1 0 181z"/></svg>
|
||||
|
After Width: | Height: | Size: 715 B |
BIN
public/Logo/LogoText.png
Normal file
|
After Width: | Height: | Size: 4.8 KiB |
108
public/MainPartnerr.svg
Normal file
|
After Width: | Height: | Size: 87 KiB |
BIN
public/Works/Works.png
Normal file
|
After Width: | Height: | Size: 313 KiB |
BIN
public/Works/WorksBgRes.png
Normal file
|
After Width: | Height: | Size: 115 KiB |
25
public/manifest.json
Normal 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
|
|
@ -0,0 +1,3 @@
|
|||
# https://www.robotstxt.org/robotstxt.html
|
||||
User-agent: *
|
||||
Disallow:
|
||||
34
src/App.tsx
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
import { lazy, Suspense } from 'react';
|
||||
import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';
|
||||
import LoadingAntd from './Components/Utils/Loading/LoadingAntd';
|
||||
import Layout from './Layout/app/Layout';
|
||||
import { routesArray } from './config/RoutesArray';
|
||||
|
||||
const App = () => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<Suspense fallback={<LoadingAntd />}>
|
||||
<Routes>
|
||||
{routesArray.map(({ path, LayoutClassName, ComponentElement, isLayoutExist }) => (
|
||||
<Route
|
||||
key={path}
|
||||
path={path}
|
||||
element={
|
||||
isLayoutExist ? (
|
||||
<Layout className={LayoutClassName}>
|
||||
<ComponentElement />
|
||||
</Layout>
|
||||
) : (
|
||||
<ComponentElement />
|
||||
)
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</Routes>
|
||||
</Suspense>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default App;
|
||||
47
src/Components/Home/HeroSection.tsx
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
import AnimationButton from "../Ui/AnimationButton";
|
||||
import MediaButton from "../Ui/MediaButton";
|
||||
import { IoIosArrowDroprightCircle } from "react-icons/io";
|
||||
import Spinner from "../Utils/Loading/Spinner";
|
||||
import { THeaderPage } from "../../type/app";
|
||||
|
||||
const HeroSection = ({data, isLoading}:THeaderPage) => {
|
||||
|
||||
const {t} = useTranslation();
|
||||
const mediaArray = data?.Social_media
|
||||
|
||||
return (
|
||||
<div className='HeroSection'>
|
||||
<a href="#about">
|
||||
<img className="scroll_down_img" src="/Home/scrollDown.png" alt="scrollDown" />
|
||||
</a>
|
||||
<div className="media_section">
|
||||
<p>{t("Follow Us")}</p>
|
||||
<hr />
|
||||
<div className='media_container'>
|
||||
{
|
||||
isLoading ? <Spinner/> :
|
||||
mediaArray?.map((media: { id: number; image: string; link:string}) => (
|
||||
<MediaButton key={media?.id} img={media?.image} link={media?.link} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="main_text_section">
|
||||
<div>
|
||||
<img src="/Home/HeroBorder.svg" alt="hero_image" />
|
||||
<h1>{t("WE")}</h1>
|
||||
<h1>{t("DEVELOP")}</h1>
|
||||
<h1>{t("EDUCATION APPLICATIONS")}</h1>
|
||||
</div>
|
||||
<div className="bottom_text_container">
|
||||
<p className="bottom_text">{t("We develop a variety of parent follow-up apps for students that help parents keep track of their children's progress and homework schedules")}.</p>
|
||||
<div className="button_container">
|
||||
<AnimationButton link="/projects" icon={<IoIosArrowDroprightCircle/>} text="View Projects" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default HeroSection
|
||||
24
src/Components/Info/Info.tsx
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
import HeaderLink from '../Ui/HeaderLink'
|
||||
import { InfoProps } from '../../type/InfoProps';
|
||||
|
||||
const Info = ({headerText,title,response}:InfoProps) => {
|
||||
const {t} = useTranslation();
|
||||
|
||||
return (
|
||||
<div className='info'>
|
||||
|
||||
<picture>
|
||||
<source className="info_image" srcSet="/App/WhiteBgRes.png" media="(max-width: 600px)" />
|
||||
<img className="info_image" src="/App/WhiteBg.png" alt="MDN" />
|
||||
</picture>
|
||||
|
||||
<div className="info_content">
|
||||
<HeaderLink text={headerText}/>
|
||||
<h1>{t(title)}</h1>
|
||||
<p>{response}</p>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Info
|
||||
27
src/Components/Projects/ProjectCard.tsx
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
import { BaseURL_IMAGE } from "../../api/config";
|
||||
import AnimationButton from "../Ui/AnimationButton"
|
||||
import PreviewButton from "../Ui/PreviewButton"
|
||||
|
||||
const ProjectCard = ({data}:any) => {
|
||||
|
||||
const projectLink = `/single_project/${data?.id}`;
|
||||
|
||||
return (
|
||||
<div className="project_card">
|
||||
<div className="project_card_container">
|
||||
<div className="images">
|
||||
<img className="main_img" src={BaseURL_IMAGE + data?.image} alt="" />
|
||||
<img className="hover_img" src={BaseURL_IMAGE + data?.hover_image} alt="" />
|
||||
<div className="buttons">
|
||||
<PreviewButton link={projectLink} />
|
||||
<AnimationButton text="Contact Us Now" link="/contact" withAnimation={false} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h1>{data?.title}</h1>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default ProjectCard
|
||||
82
src/Components/Recent/Recent.tsx
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
import React, { useState } from 'react';
|
||||
import { IoIosArrowDroprightCircle } from "react-icons/io";
|
||||
import AnimationButton from "../Ui/AnimationButton";
|
||||
import CustomTitle from "../Ui/CustomTitle";
|
||||
import { MdKeyboardArrowRight, MdOutlineKeyboardArrowLeft } from "react-icons/md";
|
||||
import { CSSTransition, TransitionGroup } from 'react-transition-group';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { BaseURL_IMAGE } from '../../api/config';
|
||||
import Spinner from '../Utils/Loading/Spinner';
|
||||
|
||||
const Recent = ({ data, isLoading }:{data:any,isLoading:boolean}) => {
|
||||
const { t } = useTranslation();
|
||||
const recentData = data?.Recent_works;
|
||||
|
||||
const [currentIndex, setCurrentIndex] = useState(0);
|
||||
|
||||
const handleNext = () => {
|
||||
setCurrentIndex((prevIndex) => (prevIndex + 1) % recentData.length);
|
||||
};
|
||||
|
||||
const handlePrevious = () => {
|
||||
setCurrentIndex((prevIndex) => (prevIndex - 1 + recentData.length) % recentData.length);
|
||||
};
|
||||
|
||||
if (isLoading) {
|
||||
return <Spinner/>;
|
||||
}
|
||||
|
||||
// if (!recentData || recentData.length === 0) {
|
||||
// return <div>No recent works available.</div>;
|
||||
// }
|
||||
|
||||
return (
|
||||
<div className='Recent'>
|
||||
<picture>
|
||||
<source className="recent_image" srcSet="/App/DarkBlueBgRes.png" media="(max-width: 600px)" />
|
||||
<img className="recent_image" src="/App/DarkBlueBg.png" alt="MDN" />
|
||||
</picture>
|
||||
|
||||
<div className="recent_container">
|
||||
<div className="recent_top">
|
||||
<CustomTitle title="portfolio" />
|
||||
<h1>{t("OUR")} <span>{t("RECENT WORK")}</span></h1>
|
||||
</div>
|
||||
|
||||
<div className="recent_bottom">
|
||||
<MdOutlineKeyboardArrowLeft className="arrow_svg fake_arrow_none" onClick={handlePrevious} />
|
||||
|
||||
<div className="data_section">
|
||||
<TransitionGroup>
|
||||
<CSSTransition
|
||||
key={currentIndex}
|
||||
timeout={500}
|
||||
classNames="fade"
|
||||
>
|
||||
<div className="data_section_content">
|
||||
<div className="data_section_left">
|
||||
<h1>{recentData[currentIndex]?.title}</h1>
|
||||
<p className="data_text">{recentData[currentIndex]?.description}</p>
|
||||
<div className='button_container'>
|
||||
<AnimationButton link='/projects' icon={<IoIosArrowDroprightCircle />} text="View Application" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="data_section_right">
|
||||
<img src={BaseURL_IMAGE + recentData[currentIndex]?.image} alt="recent_works" />
|
||||
</div>
|
||||
</div>
|
||||
</CSSTransition>
|
||||
</TransitionGroup>
|
||||
</div>
|
||||
<div className='arrow_responsive_container'>
|
||||
<MdOutlineKeyboardArrowLeft className="arrow_svg fake_arrow" onClick={handlePrevious} />
|
||||
<MdKeyboardArrowRight className="arrow_svg" onClick={handleNext} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Recent;
|
||||
49
src/Components/Service/Service.tsx
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
import CustomTitle from "../Ui/CustomTitle"
|
||||
import SingleService from "./SingleService";
|
||||
import HeaderLink from "../Ui/HeaderLink";
|
||||
import Spinner from "../Utils/Loading/Spinner";
|
||||
import { THeaderPage } from "../../type/app";
|
||||
|
||||
const Service = ({isHaveHeader = false, data,isLoading}:THeaderPage) => {
|
||||
|
||||
const {t} = useTranslation();
|
||||
const serviceData = data?.Services
|
||||
|
||||
return (
|
||||
<div className='Service'>
|
||||
<picture>
|
||||
<source className="service_image" srcSet="/App/WhiteBgRes.png" media="(max-width: 600px)" />
|
||||
<img className='service_image' src="/App/WhiteBg.png" alt="bg_image" />
|
||||
</picture>
|
||||
<div className="Title_link_container">
|
||||
{
|
||||
isHaveHeader ? <HeaderLink text='Services' /> : ""
|
||||
}
|
||||
|
||||
</div>
|
||||
<div className="service_top_container">
|
||||
<CustomTitle title="services" />
|
||||
<div className="title_container">
|
||||
<img src="/Logo/LogoText.png" alt="Logo" />
|
||||
<h1>{t("SERVICES")}</h1>
|
||||
</div>
|
||||
<p>{t("Services that we provide to you.")}</p>
|
||||
</div>
|
||||
|
||||
<div className="service_bottom_container">
|
||||
{
|
||||
isLoading ? <Spinner/> :
|
||||
serviceData?.map((item: { id: number; image: string; title:string,description:string})=>(
|
||||
<SingleService
|
||||
key={item?.id}
|
||||
image={item?.image}
|
||||
title={item?.title}
|
||||
description={item?.description}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Service
|
||||
18
src/Components/Service/SingleService.tsx
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
import { BaseURL_IMAGE } from "../../api/config"
|
||||
import { SingleServiceProps } from "../../type/app"
|
||||
|
||||
const SingleService = ({image,title,description}:SingleServiceProps) => {
|
||||
return (
|
||||
<div className='Single_Service'>
|
||||
<div className='icon_container'>
|
||||
<img src="/App/ServiceIconBg.png" alt="ServiceBg" />
|
||||
<span><img src={BaseURL_IMAGE + image} alt="" width={40} /></span>
|
||||
</div>
|
||||
|
||||
<h2>{title}</h2>
|
||||
<p>{description}</p>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default SingleService
|
||||
13
src/Components/Ui/AnimationButton.tsx
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
const AnimationButton = ({text,icon,link,withAnimation= true}:AnimationButtonProps) => {
|
||||
|
||||
return (
|
||||
<div className='button'>
|
||||
<Link to={link}><p>{text}</p></Link>
|
||||
{
|
||||
withAnimation ? <span>{icon}</span> : <span style={{display:"none"}}>{icon}</span>
|
||||
}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default AnimationButton
|
||||
50
src/Components/Ui/CardItem.tsx
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
import { CloseOutlined, MinusCircleOutlined, PlusCircleFilled } from '@ant-design/icons';
|
||||
import React, { useState } from 'react';
|
||||
import { Card, Skeleton, Button, Tooltip, Popconfirm } from 'antd';
|
||||
import useLoadingState from '../../Hooks/useLoadingState';
|
||||
import { TProduct } from '../../Layout/app/Types';
|
||||
|
||||
interface CartItemProps {
|
||||
data: TProduct;
|
||||
}
|
||||
|
||||
const CardItem: React.FC<CartItemProps> = ({ data }) => {
|
||||
const [loading, resetLoading] = useLoadingState(true, 2000);
|
||||
const [Counter, setCounter] = useState<number>(data?.count);
|
||||
const [Price, setPrice] = useState<number>(data?.price);
|
||||
|
||||
return (
|
||||
<Skeleton loading={loading} active avatar style={{ width: "100%", marginTop: 22 }}>
|
||||
<Card className='CardItem' style={{ width: "100%", marginTop: 16 }} loading={loading}>
|
||||
<span className='Card_Counter'>
|
||||
<Button shape="circle" icon={<PlusCircleFilled />} onClick={() => { setCounter(v => ++v); setPrice(v => 2 * v) }} />
|
||||
<div className='Counter'>{Counter}</div>
|
||||
<Button shape="circle" icon={<MinusCircleOutlined />} onClick={() => { setCounter(v => v > 1 ? --v : v); setPrice(v => Counter > 1 ? v / 2 : v) }} />
|
||||
</span>
|
||||
<span className='Card_Img'>
|
||||
<img alt='' src={data?.img} />
|
||||
</span>
|
||||
<span className='Card_Info'>
|
||||
<h5>{data.name}</h5>
|
||||
<h6>{data.type }</h6>
|
||||
<strong>${Price}.00</strong>
|
||||
</span>
|
||||
<span className='Card_Delete'>
|
||||
<Popconfirm
|
||||
title="Delete the Item"
|
||||
description="Are you sure to delete this Item?"
|
||||
okText="Yes"
|
||||
cancelText="No"
|
||||
>
|
||||
<Tooltip title="Delete" placement="bottom">
|
||||
<Button shape="circle" icon={<CloseOutlined />} danger />
|
||||
</Tooltip>
|
||||
</Popconfirm>
|
||||
</span>
|
||||
</Card>
|
||||
</Skeleton>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
export default CardItem;
|
||||
28
src/Components/Ui/Carousel.tsx
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
import React from 'react';
|
||||
import { Carousel } from 'antd';
|
||||
import { TbannerData } from '../../Layout/app/Types';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { BsArrowUpRight } from 'react-icons/bs';
|
||||
|
||||
type TCarouselApp = {
|
||||
data:TbannerData[]
|
||||
}
|
||||
|
||||
const CarouselApp: React.FC <TCarouselApp>= ({data}) => (
|
||||
<Carousel >
|
||||
{data.map((item:TbannerData, index:number) => (
|
||||
<div className='banner_Container' key={index}>
|
||||
<img alt='' className='banner1' src={item.imageUrl} />
|
||||
<div className='banner_Info'>
|
||||
<h1 className='underLineText'>{item.title}</h1>
|
||||
<h2>
|
||||
{item.subtitle} <br /> <strong>{item.discount}</strong>
|
||||
</h2>
|
||||
<Link to={item.link}>{item?.btn} <BsArrowUpRight /> </Link>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</Carousel>
|
||||
);
|
||||
|
||||
export default CarouselApp;
|
||||
15
src/Components/Ui/ContactInfo.tsx
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
import MediaButton from './MediaButton';
|
||||
|
||||
const ContactInfo = ({ title,info}:ContactInfoProps) => {
|
||||
const {t} = useTranslation();
|
||||
return (
|
||||
<div className='single_contact_info'>
|
||||
<div>
|
||||
<h2>{t(title)}</h2>
|
||||
<p>{info}</p>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default ContactInfo
|
||||
15
src/Components/Ui/CustomTitle.tsx
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
import { CustomTitleProps } from '../../type/app';
|
||||
|
||||
|
||||
const CustomTitle = ({title}:CustomTitleProps) => {
|
||||
|
||||
const {t} = useTranslation();
|
||||
|
||||
return (
|
||||
<div className='Custom_Title'>
|
||||
<p>{t(title)}</p>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default CustomTitle
|
||||
20
src/Components/Ui/DrawerLink.tsx
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
import { useTranslation } from 'react-i18next'
|
||||
import { NavLink } from 'react-router-dom';
|
||||
|
||||
const DrawerLink = ({href,name,icon,closeDrawer}:HedaerLinksProps) => {
|
||||
|
||||
const {t} = useTranslation();
|
||||
const pathname = window.location.pathname;
|
||||
const is_active = pathname === href;
|
||||
const handleClick = () => {
|
||||
closeDrawer();
|
||||
};
|
||||
|
||||
return (
|
||||
<NavLink to={href} className="nav_link_drawer" onClick={handleClick}>
|
||||
<p className={`drawer_link ${is_active && "active_link" }`}>{icon}{t(name)} </p>
|
||||
</NavLink>
|
||||
)
|
||||
}
|
||||
|
||||
export default DrawerLink
|
||||
39
src/Components/Ui/DropDown.tsx
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
import React from 'react';
|
||||
import { DownOutlined } from '@ant-design/icons';
|
||||
import { Dropdown, Menu, Space } from 'antd';
|
||||
|
||||
interface MenuItem {
|
||||
key: string;
|
||||
name: string;
|
||||
href: string;
|
||||
}
|
||||
|
||||
interface DropDownProps {
|
||||
menuItems: MenuItem[];
|
||||
title: string;
|
||||
}
|
||||
|
||||
const DropDown: React.FC<DropDownProps> = ({ menuItems, title }) => {
|
||||
const renderMenuItems = () => {
|
||||
return menuItems.map((item) => (
|
||||
<Menu.Item key={item.key}>
|
||||
<a target="_blank" rel="noopener noreferrer" href={item.href}>
|
||||
{item.name}
|
||||
</a>
|
||||
</Menu.Item>
|
||||
));
|
||||
};
|
||||
|
||||
const menu = <Menu>{renderMenuItems()}</Menu>;
|
||||
|
||||
return (
|
||||
<Dropdown overlay={menu} placement="bottomLeft">
|
||||
<Space>
|
||||
<span>{title} </span>
|
||||
<DownOutlined />
|
||||
</Space>
|
||||
</Dropdown>
|
||||
);
|
||||
};
|
||||
|
||||
export default DropDown;
|
||||
87
src/Components/Ui/DropdownMenu.tsx
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
import React from 'react';
|
||||
import {Dropdown, Button } from 'antd';
|
||||
import { AppstoreOutlined, DownOutlined } from '@ant-design/icons';
|
||||
import MenuItems from './MenuItems';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const DropdownMenu = () => {
|
||||
const {t} = useTranslation();
|
||||
return (
|
||||
<Dropdown overlay={MenuItems} placement="bottomLeft" className='DropdownMenu'trigger={['click']} >
|
||||
<Button>
|
||||
<AppstoreOutlined />
|
||||
{t("Categories")}
|
||||
<DownOutlined />
|
||||
</Button>
|
||||
</Dropdown>
|
||||
);
|
||||
};
|
||||
|
||||
export default DropdownMenu;
|
||||
|
||||
|
||||
//////////// you can use this file when you connect with backend just change the response and api endpoint //////////////////
|
||||
|
||||
// import React from 'react';
|
||||
// import { Dropdown, Button, Menu } from 'antd';
|
||||
// import { AppstoreOutlined, DownOutlined, MailOutlined } from '@ant-design/icons';
|
||||
// import { useGetAllCategories } from '../../api/categories';
|
||||
// import { Link, useNavigate } from 'react-router-dom';
|
||||
// import { useTranslation } from 'react-i18next';
|
||||
// import type { MenuProps } from 'antd';
|
||||
|
||||
// const DropdownMenu = () => {
|
||||
// const { data, isError, isLoading } = useGetAllCategories();
|
||||
// const navigate = useNavigate();
|
||||
// const [t] = useTranslation();
|
||||
|
||||
// if (isLoading) {
|
||||
// return <div>Loading...</div>;
|
||||
// }
|
||||
|
||||
// if (isError || !data?.data?.data) {
|
||||
// return <div>Error loading categories</div>;
|
||||
// }
|
||||
|
||||
|
||||
// const CategoriesArry = data.data.data.map((item: any) => ({
|
||||
// value: item?.category_translations[0]?.name,
|
||||
// label: item?.id,
|
||||
// }));
|
||||
|
||||
|
||||
// const items: any = CategoriesArry?.map((item: any) => ({
|
||||
// key: item.key,
|
||||
// label: (
|
||||
// <Link rel="noopener noreferrer" to={`/Products?category_id=`+item.label}>
|
||||
// {item.value}
|
||||
// </Link>
|
||||
// ),
|
||||
// icon: item.icon, // You can include the icon if available
|
||||
// disabled: item.disabled,
|
||||
// danger: item.danger,
|
||||
// }));
|
||||
|
||||
// const menu: React.ReactNode = (
|
||||
// <Menu>
|
||||
// {items.map((menuItem: any) => (
|
||||
// <Menu.Item key={menuItem.key} disabled={menuItem.disabled} danger={menuItem.danger}>
|
||||
// {menuItem.label}
|
||||
// </Menu.Item>
|
||||
// ))}
|
||||
// </Menu>
|
||||
// );
|
||||
|
||||
|
||||
// return (
|
||||
// <Dropdown menu={{items}} placement="bottomLeft" className="DropdownMenu" trigger={['click']}>
|
||||
// <Button>
|
||||
// <AppstoreOutlined />
|
||||
// {t("Categories")}
|
||||
// <DownOutlined />
|
||||
// </Button>
|
||||
// </Dropdown>
|
||||
// );
|
||||
// };
|
||||
|
||||
// export default DropdownMenu;
|
||||
11
src/Components/Ui/FooterTItleWithSeperator.tsx
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
const FooterTItleWithSeparator = ({ title }: { title: string }) => {
|
||||
const {t} = useTranslation()
|
||||
return (
|
||||
<div className='FooterTItleWithSeparator'>
|
||||
<h1>{t(title)}</h1>
|
||||
<hr />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default FooterTItleWithSeparator;
|
||||
27
src/Components/Ui/HeaderLink.tsx
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
import { useTranslation } from 'react-i18next';
|
||||
import { SlArrowRight } from "react-icons/sl";
|
||||
import { Link } from 'react-router-dom';
|
||||
import { THeaderLink } from '../../type/app';
|
||||
import { BaseURL } from '../../api/config';
|
||||
|
||||
const HeaderLink = ({text,isMulti,extraText,extraLink}:THeaderLink) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<div className='header_link'>
|
||||
<Link to={"/"} className='first_link'>{t("Home")}</Link>
|
||||
<SlArrowRight className='header_link_svg'/>
|
||||
{
|
||||
isMulti ?
|
||||
<>
|
||||
<Link to={`${extraLink}`} className='first_link'>{ t(extraText || "")}</Link>
|
||||
<SlArrowRight className='header_link_svg'/>
|
||||
</>
|
||||
: ""
|
||||
}
|
||||
<span className='page_title_link'>{t(text)}</span>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default HeaderLink
|
||||
14
src/Components/Ui/MediaButton.tsx
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
import { BaseURL_IMAGE } from "../../api/config";
|
||||
|
||||
const MediaButton = ({ img:Image,link,isStatic }:any) => {
|
||||
|
||||
return (
|
||||
<Link to={link}>
|
||||
<div className='MediaButton'>
|
||||
<span>{isStatic ? <span>{<Image/>}</span>:<img src={BaseURL_IMAGE + Image} alt="ak" width={14} />}</span>
|
||||
</div>
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
|
||||
export default MediaButton;
|
||||
37
src/Components/Ui/MenuItems.tsx
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
import React from 'react';
|
||||
import { Menu } from 'antd';
|
||||
import { MenuItem } from '../../Layout/app/Types';
|
||||
import { menuData } from './MenuItemsData';
|
||||
|
||||
const { SubMenu } = Menu;
|
||||
|
||||
|
||||
|
||||
const generateMenuItems = (items: MenuItem[]): React.ReactNode => {
|
||||
return items.map((item) => {
|
||||
if (item.children) {
|
||||
return (
|
||||
<SubMenu key={item.key} icon={item.icon} title={item.label}>
|
||||
{generateMenuItems(item.children)}
|
||||
</SubMenu>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<Menu.Item key={item.key}>
|
||||
<a href={`/${item.key}`}>{item.label}</a>
|
||||
</Menu.Item>
|
||||
);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const MenuItems: React.FC<{ items: MenuItem[] }> = ({ items }) => {
|
||||
return <Menu mode="vertical">{generateMenuItems(items)}</Menu>;
|
||||
};
|
||||
|
||||
|
||||
const App = () => {
|
||||
return <MenuItems items={menuData} />;
|
||||
};
|
||||
|
||||
export default App;
|
||||
170
src/Components/Ui/MenuItemsData.tsx
Normal file
|
|
@ -0,0 +1,170 @@
|
|||
//// fake data ////
|
||||
|
||||
import { MenuItem } from "../../Layout/app/Types";
|
||||
import { AppstoreOutlined, MailOutlined, SettingOutlined } from '@ant-design/icons';
|
||||
export const menuData: MenuItem[] = [
|
||||
{
|
||||
key: 'sub1',
|
||||
label: 'Moaz',
|
||||
icon: <MailOutlined />,
|
||||
children: [
|
||||
{ key: '1', label: 'Option 1' },
|
||||
{ key: '2', label: 'Option 2' },
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'sub2',
|
||||
label: 'Navigation Two',
|
||||
icon: <AppstoreOutlined />,
|
||||
children: [
|
||||
{ key: '5', label: 'Option 5' },
|
||||
{ key: '6', label: 'Option 6' },
|
||||
{
|
||||
key: 'sub3',
|
||||
label: 'Submenu',
|
||||
children: [
|
||||
{ key: '7', label: 'Option 7' },
|
||||
{
|
||||
key: 'subsub1',
|
||||
label: 'Sub-Submenu 1',
|
||||
children: [
|
||||
{ key: '8', label: 'Option 8' },
|
||||
{ key: '9', label: 'Option 9' },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'sub4',
|
||||
label: 'Navigation Three',
|
||||
icon: <SettingOutlined />,
|
||||
children: [
|
||||
{ key: '9', label: 'Option 9' },
|
||||
{ key: '10', label: 'Option 10' },
|
||||
{ key: '11', label: 'Option 11' },
|
||||
{
|
||||
key: 'subsub2',
|
||||
label: 'Sub-Submenu 2',
|
||||
children: [
|
||||
{ key: '12', label: 'Option 12' },
|
||||
{ key: '13', label: 'Option 13' },
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'subsub3',
|
||||
label: 'Sub-Submenu 3',
|
||||
children: [
|
||||
{ key: '14', label: 'Option 14' },
|
||||
{ key: '15', label: 'Option 15' },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'sub5',
|
||||
label: 'Navigation Four',
|
||||
icon: <SettingOutlined />,
|
||||
children: [
|
||||
{ key: '16', label: 'Option 16' },
|
||||
{ key: '17', label: 'Option 17' },
|
||||
{
|
||||
key: 'subsub4',
|
||||
label: 'Sub-Submenu 4',
|
||||
children: [
|
||||
{ key: '18', label: 'Option 18' },
|
||||
{ key: '19', label: 'Option 19' },
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'subsub5',
|
||||
label: 'Sub-Submenu 5',
|
||||
children: [
|
||||
{ key: '20', label: 'Option 20' },
|
||||
{ key: '21', label: 'Option 21' },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'sub6',
|
||||
label: 'Navigation Five',
|
||||
icon: <SettingOutlined />,
|
||||
children: [
|
||||
{ key: '22', label: 'Option 22' },
|
||||
{ key: '23', label: 'Option 23' },
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'sub7',
|
||||
label: 'Navigation Six',
|
||||
icon: <SettingOutlined />,
|
||||
children: [
|
||||
{ key: '24', label: 'Option 24' },
|
||||
{ key: '25', label: 'Option 25' },
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'sub8',
|
||||
label: 'Navigation Seven',
|
||||
icon: <SettingOutlined />,
|
||||
children: [
|
||||
{ key: '26', label: 'Option 26' },
|
||||
{ key: '27', label: 'Option 27' },
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'sub9',
|
||||
label: 'Navigation Eight',
|
||||
icon: <SettingOutlined />,
|
||||
children: [
|
||||
{ key: '28', label: 'Option 28' },
|
||||
{ key: '29', label: 'Option 29' },
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'sub10',
|
||||
label: 'Navigation Nine',
|
||||
icon: <SettingOutlined />,
|
||||
children: [
|
||||
{ key: '30', label: 'Option 30' },
|
||||
{ key: '31', label: 'Option 31' },
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
export const menuItems = [
|
||||
{
|
||||
key: '1',
|
||||
name: '1st menu item',
|
||||
href: 'https://www.antgroup.com',
|
||||
},
|
||||
{
|
||||
key: '2',
|
||||
name: '2nd menu item',
|
||||
href: 'https://www.example.com',
|
||||
},
|
||||
{
|
||||
key: '3',
|
||||
name: '1st menu item',
|
||||
href: 'https://www.antgroup.com',
|
||||
},
|
||||
{
|
||||
key: '4',
|
||||
name: '2nd menu item',
|
||||
href: 'https://www.example.com',
|
||||
},
|
||||
{
|
||||
key: '5',
|
||||
name: '1st menu item',
|
||||
href: 'https://www.antgroup.com',
|
||||
},
|
||||
{
|
||||
key: '6.NavMenus',
|
||||
name: '2nd menu item',
|
||||
href: 'https://www.example.com',
|
||||
},
|
||||
];
|
||||
|
||||
13
src/Components/Ui/PreviewButton.tsx
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
|
||||
const PreviewButton = ({ link }: { link: string }) => {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<div className='preview_button'>
|
||||
<Link to={link}>
|
||||
<p>{t("Preview")}</p>
|
||||
</Link>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default PreviewButton;
|
||||
13
src/Components/Ui/SingleLink.tsx
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
|
||||
const SingleLink = ({name, href}:FooterLinksProps) => {
|
||||
return (
|
||||
<div className='SingleLink'>
|
||||
<Link to={href} className="link">
|
||||
<div><RiArrowRightDoubleLine/></div>
|
||||
<h5>{name}</h5>
|
||||
</Link>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default SingleLink
|
||||
170
src/Components/Utils/BombBtn/BombBtn.scss
Normal file
|
|
@ -0,0 +1,170 @@
|
|||
.BombBtn{
|
||||
.container-button {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
grid-template-rows: 1fr 1fr;
|
||||
grid-template-areas: "bt-1 bt-2 bt-3"
|
||||
"bt-4 bt-5 bt-6";
|
||||
position: relative;
|
||||
perspective: 800;
|
||||
padding: 0;
|
||||
width: 60px;
|
||||
height: 25px;
|
||||
transition: all 0.3s ease-in-out;
|
||||
}
|
||||
|
||||
.container-button:active {
|
||||
transform: scale(0.95);
|
||||
}
|
||||
|
||||
.hover {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 200;
|
||||
}
|
||||
|
||||
.bt-1 {
|
||||
grid-area: bt-1;
|
||||
}
|
||||
|
||||
.bt-2 {
|
||||
grid-area: bt-2;
|
||||
}
|
||||
|
||||
.bt-3 {
|
||||
grid-area: bt-3;
|
||||
}
|
||||
|
||||
.bt-4 {
|
||||
grid-area: bt-4;
|
||||
}
|
||||
|
||||
.bt-5 {
|
||||
grid-area: bt-5;
|
||||
}
|
||||
|
||||
.bt-6 {
|
||||
grid-area: bt-6;
|
||||
}
|
||||
|
||||
.bt-1:hover ~ button {
|
||||
transform: rotateX(15deg) rotateY(-15deg) rotateZ(0deg);
|
||||
box-shadow: -2px -2px #18181888;
|
||||
}
|
||||
|
||||
.bt-1:hover ~ button::after {
|
||||
animation: shake 0.5s ease-in-out 0.3s;
|
||||
text-shadow: -2px -2px #18181888;
|
||||
}
|
||||
|
||||
.bt-3:hover ~ button {
|
||||
transform: rotateX(15deg) rotateY(15deg) rotateZ(0deg);
|
||||
box-shadow: 2px -2px #18181888;
|
||||
}
|
||||
|
||||
.bt-3:hover ~ button::after {
|
||||
animation: shake 0.5s ease-in-out 0.3s;
|
||||
text-shadow: 2px -2px #18181888;
|
||||
}
|
||||
|
||||
.bt-4:hover ~ button {
|
||||
transform: rotateX(-15deg) rotateY(-15deg) rotateZ(0deg);
|
||||
box-shadow: -2px 2px #18181888;
|
||||
}
|
||||
|
||||
.bt-4:hover ~ button::after {
|
||||
animation: shake 0.5s ease-in-out 0.3s;
|
||||
text-shadow: -2px 2px #18181888;
|
||||
}
|
||||
|
||||
.bt-6:hover ~ button {
|
||||
transform: rotateX(-15deg) rotateY(15deg) rotateZ(0deg);
|
||||
box-shadow: 2px 2px #18181888;
|
||||
}
|
||||
|
||||
.bt-6:hover ~ button::after {
|
||||
animation: shake 0.5s ease-in-out 0.3s;
|
||||
text-shadow: 2px 2px #18181888;
|
||||
}
|
||||
|
||||
.hover:hover ~ button::before {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.hover:hover ~ button::after {
|
||||
content: attr(data-text);
|
||||
top: -200%;
|
||||
transform: translate(-50%, 0);
|
||||
font-size: 20px;
|
||||
color: var(--secondary);
|
||||
}
|
||||
|
||||
button {
|
||||
position: absolute;
|
||||
padding: 0;
|
||||
width: 60px;
|
||||
height: 25px;
|
||||
background: var(--secondary);
|
||||
font-size: 10px;
|
||||
font-weight: 900;
|
||||
border: 3px solid var(--secondary);
|
||||
border-radius: 12px;
|
||||
transition: all 0.3s ease-in-out;
|
||||
}
|
||||
|
||||
button::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 60px;
|
||||
height: 25px;
|
||||
background-color: var(--secondary);
|
||||
border-radius: 12px;
|
||||
transition: all 0.3s ease-in-out;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
button::after {
|
||||
content: attr(data-text);
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 60px;
|
||||
height: 25px;
|
||||
background-color: transparent;
|
||||
font-size: 10px;
|
||||
font-weight: 900;
|
||||
line-height: 25px;
|
||||
color: var(--primary);
|
||||
border: none;
|
||||
border-radius: 12px;
|
||||
transition: all 0.3s ease-in-out;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
@keyframes shake {
|
||||
0% {
|
||||
left: 45%;
|
||||
}
|
||||
|
||||
25% {
|
||||
left: 54%;
|
||||
}
|
||||
|
||||
50% {
|
||||
left: 48%;
|
||||
}
|
||||
|
||||
75% {
|
||||
left: 52%;
|
||||
}
|
||||
|
||||
100% {
|
||||
left: 50%;
|
||||
}
|
||||
}
|
||||
}
|
||||
21
src/Components/Utils/BombBtn/BombBtn.tsx
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
import React from 'react'
|
||||
import './BombBtn.scss'
|
||||
|
||||
const BombBtn = () => {
|
||||
|
||||
return (
|
||||
<div className='BombBtn'>
|
||||
<div className="container-button" >
|
||||
<div className="hover bt-1" />
|
||||
<div className="hover bt-2" />
|
||||
<div className="hover bt-3" />
|
||||
<div className="hover bt-4" />
|
||||
<div className="hover bt-5" />
|
||||
<div className="hover bt-6" />
|
||||
<button data-text={"15% off"} />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default BombBtn
|
||||
47
src/Components/Utils/FileInput/File.tsx
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
import { Button, Upload, UploadFile } from 'antd'
|
||||
import { UploadOutlined } from '@ant-design/icons';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const File = ({ label,set }: any) => {
|
||||
const {t} = useTranslation();
|
||||
const imageUrl = '';
|
||||
|
||||
const fileList: UploadFile[] = [
|
||||
{
|
||||
uid: '-1',
|
||||
name: '',
|
||||
status: 'done',
|
||||
url: imageUrl,
|
||||
thumbUrl: imageUrl,
|
||||
}
|
||||
];
|
||||
|
||||
const FilehandleChange = (value:any) => {
|
||||
set(value?.file?.originFileObj)
|
||||
};
|
||||
const customRequest = async ({ onSuccess}: any) => {
|
||||
onSuccess();
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="TalabeeField">
|
||||
<label htmlFor={label} className="text" >
|
||||
{(`${label}`)}
|
||||
</label>
|
||||
|
||||
<Upload
|
||||
listType="picture"
|
||||
maxCount={1}
|
||||
className='w-100 upload_file'
|
||||
defaultFileList={[...fileList]}
|
||||
onChange={ FilehandleChange}
|
||||
customRequest={customRequest}
|
||||
>
|
||||
<Button className='w-100 partner_image' icon={<UploadOutlined />}>{t("upload_image")}</Button>
|
||||
</Upload>
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default File
|
||||
117
src/Components/Utils/Loading/Loading.scss
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
.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(--fifthly);
|
||||
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: var(--fifthly);
|
||||
position: absolute;
|
||||
opacity: .5;
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
.loading_page{
|
||||
width: 100vw !important;height: 50vh !important;
|
||||
display: flex !important;justify-content: space-between !important;align-items: center !important; flex-direction: column;
|
||||
}
|
||||
|
||||
|
||||
:where(.css-dev-only-do-not-override-1ae8k9u).ant-spin .ant-spin-dot-item ,:where(.css-1adbn6x).ant-spin .ant-spin-dot-item{
|
||||
background-color: var(--primary);
|
||||
}
|
||||
:where(.css-dev-only-do-not-override-1ae8k9u).ant-spin, :where(.css-1adbn6x).ant-spin .ant-spin-dot-item{
|
||||
color: var(--primary);
|
||||
}
|
||||
|
||||
|
||||
.spinner{
|
||||
color: var(--primary);
|
||||
padding-block: 30px;
|
||||
}
|
||||
19
src/Components/Utils/Loading/Loading.tsx
Normal 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
|
||||
17
src/Components/Utils/Loading/LoadingAntd.tsx
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
import { Spin } from 'antd';
|
||||
import './Loading.scss'
|
||||
import { useGetHome } from '../../../api/home';
|
||||
import { BaseURL_IMAGE } from '../../../api/config';
|
||||
|
||||
const LoadingAntd = () => {
|
||||
const {data} = useGetHome();
|
||||
const Logo = data?.Static_info[5]
|
||||
return (
|
||||
<div className='loading_page'>
|
||||
<img src={BaseURL_IMAGE + Logo?.value} width={100} alt='logo'/>
|
||||
<Spin className='LoadingAntd' size='large' />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default LoadingAntd
|
||||
15
src/Components/Utils/Loading/LoadingButton.tsx
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
import React from "react";
|
||||
import { Button, Spinner } from "reactstrap";
|
||||
|
||||
const LoadingButton = ({ className = 'LoadinButton',isLoading = false, ...props }) => {
|
||||
return (
|
||||
<Button className={className} disabled={isLoading} {...props}>
|
||||
{isLoading ? <Spinner style={{ marginRight: "10px" }} size="sm" /> : null}
|
||||
<span >{props.children}</span>
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
|
||||
export { LoadingButton };
|
||||
8
src/Components/Utils/Loading/Spinner.tsx
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
import React from 'react'
|
||||
import { Spin } from 'antd';
|
||||
|
||||
const Spinner: React.FC = () =>
|
||||
<>
|
||||
<Spin className='LoadingAntd spinner' size='large'/>
|
||||
</>
|
||||
export default Spinner
|
||||
57
src/Components/Utils/TalabeeField/TalabeeField.scss
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
.TalabeeField{
|
||||
>*{
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
.error{
|
||||
color: red;
|
||||
}
|
||||
56
src/Components/Utils/TalabeeField/TalabeeField.tsx
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
import React from "react";
|
||||
import "./TalabeeField.scss";
|
||||
import { Date, Time, File, DataRange, SelectField, Default, CheckboxField } from './View';
|
||||
|
||||
export interface TalabeeFieldProps {
|
||||
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"
|
||||
inputType?:String
|
||||
}
|
||||
|
||||
const TalabeeField = (props: TalabeeFieldProps) => {
|
||||
switch (props?.type) {
|
||||
case 'Select':
|
||||
return <SelectField {...props} />;
|
||||
case "DataRange":
|
||||
return <DataRange {...props} />;
|
||||
case "Date":
|
||||
return <Date {...props} />;
|
||||
case "Time":
|
||||
return <Time {...props} />;
|
||||
case "File":
|
||||
return <File {...props} />;
|
||||
case "Checkbox":
|
||||
return <CheckboxField {...props} />;
|
||||
default:
|
||||
return <Default {...props} />;
|
||||
}
|
||||
};
|
||||
|
||||
TalabeeField.defaultProps = {
|
||||
type: "text",
|
||||
className: 'default-class',
|
||||
option: [],
|
||||
isMulti: false,
|
||||
isDisabled: false,
|
||||
picker: "date",
|
||||
Format: "YYYY/MM/DD",
|
||||
onChange: undefined,
|
||||
Group:false,
|
||||
dir : "ltr",
|
||||
inputType: "text"
|
||||
|
||||
};
|
||||
|
||||
export default TalabeeField;
|
||||
29
src/Components/Utils/TalabeeField/View/CheckboxField.tsx
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
import React from 'react'
|
||||
import useFormField from '../../../../Hooks/useFormField';
|
||||
import { Checkbox } from 'antd';
|
||||
|
||||
const CheckboxField = ({ name, label, placeholder, isDisabled, option, isMulti, onChange,Group, props }: any) => {
|
||||
|
||||
const { t, formik } = useFormField(name, props)
|
||||
const CheckboxhandleChange = (value:any) => {
|
||||
console.log(value.target.checked);
|
||||
|
||||
formik.setFieldValue(name, value.target.checked)
|
||||
|
||||
};
|
||||
return (
|
||||
<div className={Group ? "d-inline mt-3 Checkboxs" :``}>
|
||||
<Checkbox
|
||||
onChange={onChange || CheckboxhandleChange}
|
||||
disabled={isDisabled}
|
||||
checked={formik.getFieldProps(name).value}
|
||||
|
||||
>
|
||||
{t(label)}
|
||||
</Checkbox>
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default CheckboxField
|
||||
40
src/Components/Utils/TalabeeField/View/DataRange.tsx
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
import { Form, DatePicker } from 'antd'
|
||||
|
||||
import React from 'react'
|
||||
import useFormField from '../../../../Hooks/useFormField';
|
||||
|
||||
const { RangePicker } = DatePicker;
|
||||
|
||||
const DataRange = ({ name, label, isDisabled, option, isMulti,Format ,props }: any) => {
|
||||
|
||||
const { errorMsg, isError, t, formik } = useFormField(name, props)
|
||||
const onCalendarChange = (value: any) => {
|
||||
|
||||
formik.setFieldValue(name, value)
|
||||
|
||||
};
|
||||
return (
|
||||
|
||||
<div className='TalabeeField'>
|
||||
<label htmlFor={name} className="text">
|
||||
{t(`${label}`)}
|
||||
</label>
|
||||
<Form.Item
|
||||
hasFeedback
|
||||
validateStatus={isError ? "error" : ""}
|
||||
help={isError ? errorMsg : ""}
|
||||
>
|
||||
<RangePicker
|
||||
allowClear
|
||||
className='w-100'
|
||||
format={Format}
|
||||
onCalendarChange={onCalendarChange}
|
||||
/>
|
||||
|
||||
|
||||
</Form.Item>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default DataRange
|
||||
40
src/Components/Utils/TalabeeField/View/Date.tsx
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
import { Form, DatePicker } from 'antd'
|
||||
import React from 'react'
|
||||
import useFormField from '../../../../Hooks/useFormField';
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
const Date = ({ name, label, isDisabled, option, isMulti,picker="date" ,props }: any) => {
|
||||
|
||||
const { errorMsg, isError, t, formik } = useFormField(name, props)
|
||||
const onCalendarChange = (value: any) => {
|
||||
|
||||
formik.setFieldValue(name, value)
|
||||
|
||||
};
|
||||
return (
|
||||
|
||||
<div className='TalabeeField'>
|
||||
<label htmlFor={name} className="text">
|
||||
{t(`${label}`)}
|
||||
</label>
|
||||
<Form.Item
|
||||
hasFeedback
|
||||
validateStatus={isError ? "error" : ""}
|
||||
help={isError ? errorMsg : ""}
|
||||
>
|
||||
<DatePicker
|
||||
picker={picker}
|
||||
allowClear
|
||||
className='w-100'
|
||||
// defaultValue={formik.values[name]}
|
||||
|
||||
onChange={onCalendarChange} />
|
||||
|
||||
|
||||
|
||||
</Form.Item>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Date
|
||||
32
src/Components/Utils/TalabeeField/View/Default.tsx
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
import { Form, Input } from 'antd'
|
||||
import React from 'react'
|
||||
import useFormField from '../../../../Hooks/useFormField';
|
||||
|
||||
const Default = ({ name, label, placeholder, isDisabled, onChange, props,inputType }: any) => {
|
||||
const { Field, formik, isError, errorMsg, t } = useFormField(name, props);
|
||||
|
||||
|
||||
return (
|
||||
<div className="TalabeeField">
|
||||
<label htmlFor={name} className="text">
|
||||
{t(`${label ? label : name}`)}
|
||||
</label>
|
||||
<Form.Item
|
||||
hasFeedback
|
||||
validateStatus={isError ? 'error' : ''}
|
||||
help={isError ? t(name)+ ' ' + t('is requierd') : ''}
|
||||
>
|
||||
<Field
|
||||
as={Input}
|
||||
type={inputType ? inputType : 'text'}
|
||||
placeholder={t(`${placeholder ?placeholder : name}`)}
|
||||
name={name}
|
||||
disabled={isDisabled}
|
||||
// onChange={onChange ? onChange : handleChange}
|
||||
/>
|
||||
</Form.Item>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Default;
|
||||
58
src/Components/Utils/TalabeeField/View/File.tsx
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
import { Button, Upload, UploadFile } from 'antd'
|
||||
import useFormField from '../../../../Hooks/useFormField';
|
||||
import { UploadOutlined } from '@ant-design/icons';
|
||||
import { BaseURL, BaseURL_IMAGE } from '../../../../api/config';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { ErrorMessage } from 'formik';
|
||||
|
||||
|
||||
const File = ({ name, label, onChange, isDisabled, props }: any) => {
|
||||
const { formik, t } = useFormField(name, props)
|
||||
const imageUrl = formik.values[name] ? BaseURL_IMAGE + formik.values[name] : '';
|
||||
|
||||
const fileList: UploadFile[] = [
|
||||
|
||||
{
|
||||
uid: '-1',
|
||||
name: '',
|
||||
status: 'done',
|
||||
url: imageUrl,
|
||||
thumbUrl: imageUrl,
|
||||
}
|
||||
];
|
||||
const FilehandleChange = (value:any) => {
|
||||
|
||||
formik.setFieldValue(name, value.file.originFileObj)
|
||||
|
||||
};
|
||||
const customRequest = async ({ onSuccess}: any) => {
|
||||
onSuccess();
|
||||
};
|
||||
return (
|
||||
<div className="TalabeeField">
|
||||
<label htmlFor={name} className="text">
|
||||
{t(`${label || name}`)}
|
||||
</label>
|
||||
|
||||
<Upload
|
||||
disabled={isDisabled}
|
||||
listType="picture"
|
||||
maxCount={1}
|
||||
className='w-100'
|
||||
defaultFileList={[...fileList]}
|
||||
onChange={onChange || FilehandleChange}
|
||||
customRequest={customRequest}
|
||||
|
||||
>
|
||||
<Button className='w-100' icon={<UploadOutlined />}>{t("upload_image")}</Button>
|
||||
<ErrorMessage name={name}>{msg => <div className='error'>{t(msg)}</div>}</ErrorMessage>
|
||||
|
||||
</Upload>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default File
|
||||
44
src/Components/Utils/TalabeeField/View/SearchField.tsx
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
import { Input } from 'antd';
|
||||
import { SearchProps } from 'antd/es/input'
|
||||
import { useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useLocation, useNavigate, useSearchParams } from 'react-router-dom';
|
||||
const { Search } = Input;
|
||||
|
||||
const SearchField = () => {
|
||||
const navigate = useNavigate()
|
||||
const [searchParams,] = useSearchParams();
|
||||
const location =useLocation()
|
||||
const {t} = useTranslation();
|
||||
|
||||
const [searchValue, setSearchValue] = useState(searchParams.get('search')|| "");
|
||||
|
||||
const onSearch: SearchProps['onSearch'] = (value, _e, info) => {
|
||||
// console.log(value);
|
||||
|
||||
navigate(`${location?.pathname}?search=${value}`, { replace: true });
|
||||
}
|
||||
const onChange = (e :any) => {
|
||||
setSearchValue(e.target.value);
|
||||
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<div className='SearchField'>
|
||||
<Search
|
||||
allowClear
|
||||
enterButton={t("search")}
|
||||
size="middle"
|
||||
placeholder={t("search")}
|
||||
onSearch={onSearch}
|
||||
style={{ width: 250 }}
|
||||
value={searchValue}
|
||||
onChange={onChange}
|
||||
/>
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default SearchField
|
||||
37
src/Components/Utils/TalabeeField/View/SelectField.tsx
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
import { Form, Select } from 'antd'
|
||||
import React from 'react'
|
||||
import useFormField from '../../../../Hooks/useFormField';
|
||||
|
||||
const SelectField = ({ name, label, placeholder, isDisabled,option,isMulti,onChange, 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='TalabeeField'>
|
||||
<label htmlFor={name} className="text">
|
||||
{t(`${label? label : ''}`)}
|
||||
</label>
|
||||
<Form.Item
|
||||
hasFeedback
|
||||
validateStatus={isError ? "error" : ""}
|
||||
help={isError ? errorMsg : ""}
|
||||
>
|
||||
<Select
|
||||
placeholder={t(`${placeholder ?placeholder : name}`)}
|
||||
disabled={isDisabled}
|
||||
options={option}
|
||||
defaultValue={formik.values[name]}
|
||||
allowClear
|
||||
{...(isMulti && { mode: "multiple" })}
|
||||
onChange={onChange || SelecthandleChange}
|
||||
|
||||
/>
|
||||
</Form.Item>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default SelectField
|
||||
38
src/Components/Utils/TalabeeField/View/Time.tsx
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
import { Form, TimePicker } from 'antd'
|
||||
import React from 'react'
|
||||
import useFormField from '../../../../Hooks/useFormField';
|
||||
|
||||
const Time = ({ name, label,props }: any) => {
|
||||
|
||||
const { errorMsg, isError, t, formik } = useFormField(name, props)
|
||||
const onCalendarChange = (value: any) => {
|
||||
|
||||
formik.setFieldValue(name, value)
|
||||
|
||||
};
|
||||
return (
|
||||
|
||||
<div className='TalabeeField'>
|
||||
<label htmlFor={name} className="text">
|
||||
{t(`${label}`)}
|
||||
</label>
|
||||
<Form.Item
|
||||
hasFeedback
|
||||
validateStatus={isError ? "error" : ""}
|
||||
help={isError ? errorMsg : ""}
|
||||
>
|
||||
<TimePicker
|
||||
allowClear
|
||||
className='w-100'
|
||||
defaultValue={formik.values[name]}
|
||||
onChange={onCalendarChange} />
|
||||
|
||||
|
||||
|
||||
|
||||
</Form.Item>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Time
|
||||
22
src/Components/Utils/TalabeeField/View/index.tsx
Normal 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";
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
export {
|
||||
Time,
|
||||
SelectField,
|
||||
Date,
|
||||
DataRange,
|
||||
CheckboxField,
|
||||
Default,
|
||||
File
|
||||
|
||||
}
|
||||
16
src/Components/Utils/TalabeeField/index.tsx
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
import { useState } from 'react';
|
||||
import { ErrorMessage, useField, Field, useFormikContext } from 'formik';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { FaExclamationCircle } from 'react-icons/fa';
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
export {
|
||||
useState,
|
||||
ErrorMessage, useField, Field, useFormikContext,
|
||||
useTranslation,
|
||||
FaExclamationCircle
|
||||
|
||||
}
|
||||
41
src/Components/Utils/Theme.tsx
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
import React from 'react';
|
||||
import { MenuProps } from 'antd';
|
||||
import { Button, Dropdown, Space } from 'antd';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { BsFillMoonStarsFill, BsFillSunFill } from 'react-icons/bs';
|
||||
import { useChangeTheme } from '../../Hooks/useChangeTheme';
|
||||
import { ChangeModeHelper, ChangeModeComp } from '../../helper/ChangeMode';
|
||||
import { ThemeModeEnum } from '../../enums/ThemeMode';
|
||||
|
||||
const Theme: React.FC = () => {
|
||||
const { currentTheme, changeTheme } = useChangeTheme();
|
||||
const { DARK_MODE, LIGHT_MODE } = ThemeModeEnum;
|
||||
const { t } = useTranslation();
|
||||
|
||||
const themeClickHandler =(theme:string) =>{
|
||||
return ChangeModeHelper({
|
||||
ChangeModeFunction: changeTheme,
|
||||
ChangeFunctionAttr: theme
|
||||
});
|
||||
}
|
||||
const items: MenuProps['items'] = [
|
||||
{
|
||||
key: '1',
|
||||
label: <ChangeModeComp onClickFunction={themeClickHandler(LIGHT_MODE)} isImage={false} icon={<BsFillSunFill/>} modeText={LIGHT_MODE} />,
|
||||
},
|
||||
{
|
||||
key: '2',
|
||||
label: <ChangeModeComp onClickFunction={themeClickHandler(DARK_MODE)} isImage={false} icon={<BsFillMoonStarsFill/>} modeText={DARK_MODE} />,
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<Space direction="vertical">
|
||||
<Dropdown menu={{ items }} placement="top">
|
||||
<Button className='theme_mode_button'>{t(currentTheme || 'Theme Mode')}</Button>
|
||||
</Dropdown>
|
||||
</Space>
|
||||
);
|
||||
};
|
||||
|
||||
export default Theme;
|
||||
40
src/Components/Utils/Translate.tsx
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
import React from 'react';
|
||||
import type { MenuProps } from 'antd';
|
||||
import { Button, Dropdown, Space } from 'antd';
|
||||
import { useChangeLanguage } from '../../Hooks/useChangeLanguage';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { ChangeModeHelper, ChangeModeComp } from '../../helper/ChangeMode';
|
||||
import { TranslateEnum } from '../../enums/Translate';
|
||||
|
||||
const Translate: React.FC = () => {
|
||||
const { currentLanguage, changeLanguage } = useChangeLanguage();
|
||||
const { ARABIC, ENGLISH } = TranslateEnum;
|
||||
const { t } = useTranslation();
|
||||
|
||||
const handleLanguageChange = (language: string) => {
|
||||
return ChangeModeHelper({
|
||||
ChangeModeFunction: changeLanguage,
|
||||
ChangeFunctionAttr: language
|
||||
});
|
||||
};
|
||||
|
||||
const items = [
|
||||
{
|
||||
key: '1',
|
||||
label: <ChangeModeComp onClickFunction={handleLanguageChange(ENGLISH)} src="../Layout/En.svg" modeText={ENGLISH} />,
|
||||
},
|
||||
{
|
||||
key: '2',
|
||||
label: <ChangeModeComp onClickFunction={handleLanguageChange(ARABIC)} src="../Layout/Ar.svg" modeText={ARABIC} />,
|
||||
},
|
||||
];
|
||||
return (
|
||||
<Space direction="vertical">
|
||||
<Dropdown menu={{ items }} placement="top">
|
||||
<Button className='Translate' disabled>{t(currentLanguage)}</Button>
|
||||
</Dropdown>
|
||||
</Space>
|
||||
);
|
||||
};
|
||||
|
||||
export default Translate;
|
||||
31
src/Components/Works/Works.tsx
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
import CustomTitle from "../Ui/CustomTitle"
|
||||
import WorksSwiper from "./WorksSwiper";
|
||||
|
||||
const Works = ({data, isLoading}:{data:any,isLoading:boolean}) => {
|
||||
const {t} = useTranslation();
|
||||
const worksData = data?.Works
|
||||
|
||||
return (
|
||||
<div className='works'>
|
||||
|
||||
<picture>
|
||||
<source className="works_image" srcSet="/Works/WorksBgRes.png" media="(max-width: 500px)" />
|
||||
<img className="works_image" src="/Works/Works.png" alt="MDN" />
|
||||
</picture>
|
||||
|
||||
<div className="works_container">
|
||||
<div className="works_top">
|
||||
<CustomTitle title="project"/>
|
||||
<h1>{t("What")} <span>{t("OUR WORKS")}</span></h1>
|
||||
<p>{t("We design and develop professional educational applications that help parents follow their children's progress in study, track attendance and absence, and submit academic reports ")}</p>
|
||||
</div>
|
||||
|
||||
<div className="swiper_container">
|
||||
<WorksSwiper isLoading={isLoading} data={worksData}/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Works
|
||||
52
src/Components/Works/WorksSwiper.tsx
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
import { useRef, useState } from 'react';
|
||||
import { Swiper, SwiperSlide } from 'swiper/react';
|
||||
import 'swiper/css';
|
||||
import 'swiper/css/free-mode';
|
||||
import 'swiper/css/pagination';
|
||||
import { A11y, Autoplay, Navigation,Scrollbar } from 'swiper/modules';
|
||||
import { BaseURL_IMAGE } from '../../api/config';
|
||||
import Spinner from '../Utils/Loading/Spinner';
|
||||
|
||||
|
||||
|
||||
const WorksSwiper = ({data,isLoading}:{data:any,isLoading:boolean}) => {
|
||||
const language = localStorage.getItem('language') ;
|
||||
|
||||
const [swiperDirection, setSwiperDirection] = useState(language === "ar" ? "rtl" : "ltr");
|
||||
const swiperRef = useRef<any>(null);
|
||||
|
||||
|
||||
return (
|
||||
<div className='works_Swiper'>
|
||||
<Swiper
|
||||
dir={swiperDirection}
|
||||
slidesPerView={5}
|
||||
spaceBetween={66}
|
||||
breakpoints={{
|
||||
0: { slidesPerView: 1 },
|
||||
400: { slidesPerView: 1 },
|
||||
600: { slidesPerView: 3 },
|
||||
900: { slidesPerView: 4 },
|
||||
1200: { slidesPerView: 5 },
|
||||
1500: { slidesPerView: 5 },
|
||||
}}
|
||||
autoplay={true}
|
||||
modules={[Navigation, Scrollbar, A11y, Autoplay]}
|
||||
pagination={{ clickable: true }}
|
||||
className="mySwiper"
|
||||
onSwiper={(swiper:any) => (swiperRef.current = swiper)} // Store swiper instance
|
||||
>
|
||||
{
|
||||
isLoading ? <Spinner/> :
|
||||
data?.map((item:any, index:number) => (
|
||||
<SwiperSlide key={index}>
|
||||
<img src={BaseURL_IMAGE + item?.image} alt="Works" />
|
||||
|
||||
</SwiperSlide>
|
||||
))}
|
||||
</Swiper>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default WorksSwiper;
|
||||
43
src/Components/about/About.tsx
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
import AnimationButton from '../Ui/AnimationButton';
|
||||
import CustomTitle from '../Ui/CustomTitle'
|
||||
import { IoIosArrowDroprightCircle } from "react-icons/io";
|
||||
import HeaderLink from '../Ui/HeaderLink';
|
||||
import Spinner from '../Utils/Loading/Spinner';
|
||||
import { THeaderPage } from '../../type/app';
|
||||
|
||||
const About = ({isHaveHeader = false, data,isLoading}:THeaderPage) => {
|
||||
|
||||
const {t} = useTranslation();
|
||||
const aboutData = data?.Static_info[0]
|
||||
|
||||
return (
|
||||
<div className='about' id='about'>
|
||||
<picture>
|
||||
<source className="about_image" srcSet="/App/WhiteBgRes.png" media="(max-width: 600px)" />
|
||||
<img className="about_image" src="/App/WhiteBg.png" alt="MDN" />
|
||||
</picture>
|
||||
<div className='main_container'>
|
||||
{
|
||||
isHaveHeader ? <HeaderLink text='About' /> : ""
|
||||
}
|
||||
<div className="about_container">
|
||||
<div className="about_left">
|
||||
<img src="/Home/about_left_image.png" alt="" />
|
||||
</div>
|
||||
|
||||
<div className="about_right">
|
||||
<CustomTitle title={"Our Story"}/>
|
||||
<h1>{t(isLoading ? <Spinner/> :aboutData?.key)}</h1>
|
||||
<p>{t("We are specialists in financial planning and reporting.")}</p>
|
||||
<p>{isLoading ? <Spinner/> :aboutData?.value}</p>
|
||||
<div className='button_container'>
|
||||
<AnimationButton link='/about' icon={<IoIosArrowDroprightCircle/>} text="Learn More Now" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default About
|
||||
45
src/Components/contact/Contact.tsx
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
import { THeaderPage, TPageHeader } from '../../type/app'
|
||||
import HeaderLink from '../Ui/HeaderLink'
|
||||
import LoadingAntd from '../Utils/Loading/LoadingAntd'
|
||||
import Spinner from '../Utils/Loading/Spinner'
|
||||
import ContactOneSection from './ContactOneSection'
|
||||
|
||||
const Contact = ({isHaveHeader = false, data, isLoading}:THeaderPage) => {
|
||||
|
||||
const contactData = data?.Contact;
|
||||
|
||||
return (
|
||||
<div className='contact'>
|
||||
<picture>
|
||||
<source className="contact_image" srcSet="/App/WhiteBgRes.png" media="(max-width: 600px)" />
|
||||
<img className="contact_image" src="/App/WhiteBg.png" alt="MDN" />
|
||||
</picture>
|
||||
<div className="contact_container">
|
||||
{isHaveHeader ? <HeaderLink text='Contact' /> : ""}
|
||||
{
|
||||
isLoading ? <Spinner /> :
|
||||
contactData?.map((item: any) => {
|
||||
const subTitleWords = item?.sub_title.split(' ');
|
||||
const text = subTitleWords[0];
|
||||
const subText = subTitleWords.slice(1).join(' ');
|
||||
|
||||
return (
|
||||
<ContactOneSection
|
||||
key={item?.id} // Assuming there's a unique id for each item
|
||||
title={item?.title}
|
||||
text={text}
|
||||
subText={subText}
|
||||
isHaveButton={item?.is_have_button}
|
||||
rowRevers={item?.direction}
|
||||
bottomText={item?.description}
|
||||
image={item?.image}
|
||||
/>
|
||||
);
|
||||
})
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Contact;
|
||||
39
src/Components/contact/ContactOneSection.tsx
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
import React from 'react'
|
||||
import CustomTitle from '../Ui/CustomTitle'
|
||||
import { IoIosArrowDroprightCircle } from 'react-icons/io';
|
||||
import AnimationButton from '../Ui/AnimationButton';
|
||||
import { BaseURL_IMAGE } from '../../api/config';
|
||||
|
||||
interface ContactOneSectionProps {
|
||||
title:string,
|
||||
text:string,
|
||||
subText:string,
|
||||
bottomText:string,
|
||||
isHaveButton:boolean,
|
||||
rowRevers:boolean,
|
||||
image:string
|
||||
}
|
||||
const ContactOneSection = ({title,text,subText,bottomText,isHaveButton,rowRevers,image}:ContactOneSectionProps) => {
|
||||
const {t} = useTranslation();
|
||||
return (
|
||||
<div className="contact_section" style={rowRevers?{flexDirection:"row-reverse"}:{flexDirection:"row"}}>
|
||||
<div className='image_container'>
|
||||
<img src={BaseURL_IMAGE + image} alt="contact_image" />
|
||||
</div>
|
||||
<div className='right'>
|
||||
<CustomTitle title={title}/>
|
||||
<h1>{t(text)}<span> { t(subText)}</span></h1>
|
||||
<p>{t(bottomText)}</p>
|
||||
{isHaveButton ?
|
||||
<div className='button_container'>
|
||||
<AnimationButton link='/contact' icon={<IoIosArrowDroprightCircle/>} text="Contact Us Now" />
|
||||
</div>
|
||||
:""
|
||||
}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default ContactOneSection
|
||||
54
src/HighOrderComponent/WithDrawer.tsx
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
import React, { useState, ReactNode, ReactElement } from 'react';
|
||||
import type { DrawerProps } from 'antd';
|
||||
import { Drawer, Space } from 'antd';
|
||||
|
||||
interface WithDrawerProps {
|
||||
button: React.ReactNode;
|
||||
children: (props: { closeDrawer: () => void }) => ReactElement;
|
||||
title: string;
|
||||
className?: string;
|
||||
width?: string;
|
||||
turn_off?: boolean;
|
||||
onClick?: any;
|
||||
}
|
||||
|
||||
const WithDrawer: React.FC<WithDrawerProps> = ({
|
||||
button,
|
||||
children,
|
||||
title = "Basic Drawer",
|
||||
className,
|
||||
width = 250,
|
||||
turn_off,
|
||||
}) => {
|
||||
const [open, setOpen] = useState(false);
|
||||
const [placement, setPlacement] = useState<DrawerProps['placement']>('right');
|
||||
|
||||
const closeDrawer = () => {
|
||||
setOpen(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Space>
|
||||
{React.cloneElement(button as React.ReactElement, {
|
||||
onClick: () => setOpen(true),
|
||||
})}
|
||||
</Space>
|
||||
<Drawer
|
||||
title={title}
|
||||
placement={placement}
|
||||
closable={false}
|
||||
onClose={closeDrawer}
|
||||
open={turn_off ? false : open}
|
||||
key={placement}
|
||||
width={width}
|
||||
>
|
||||
<div className={className}>
|
||||
{children({ closeDrawer })}
|
||||
</div>
|
||||
</Drawer>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default WithDrawer;
|
||||
36
src/HighOrderComponent/WithFormik.tsx
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
import { Form, Formik } from 'formik'
|
||||
import React from 'react'
|
||||
import * as Yup from "yup";
|
||||
|
||||
|
||||
const WithFormik = ({children , handleSubmit , getInitialValues , getValidationSchema,FormClassName}:WithFormikProps) => {
|
||||
|
||||
return (
|
||||
<>
|
||||
{
|
||||
<Formik
|
||||
initialValues={getInitialValues()}
|
||||
validationSchema={getValidationSchema()}
|
||||
onSubmit={handleSubmit}
|
||||
enableReinitialize
|
||||
>
|
||||
{(formik) => (
|
||||
<Form className={FormClassName}>
|
||||
{children}
|
||||
</Form>
|
||||
)}
|
||||
</Formik>
|
||||
}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default WithFormik
|
||||
|
||||
interface WithFormikProps {
|
||||
children: React.ReactNode;
|
||||
handleSubmit: (values: any, formikHelpers: any) => void;
|
||||
getInitialValues: () => any;
|
||||
getValidationSchema: () => Yup.Schema<any>;
|
||||
FormClassName?:string;
|
||||
}
|
||||
28
src/Hooks/mapTranslatedProperties.tsx
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
export const mapTranslatedProperties = (
|
||||
arrayOfDetails :any,
|
||||
properties:any ,
|
||||
language_id : '1'|'2' |1 |2
|
||||
) => {
|
||||
|
||||
if (!arrayOfDetails || !properties || !language_id) return "";
|
||||
if (Array.isArray(arrayOfDetails) && arrayOfDetails.length === 0) return "";
|
||||
|
||||
const target = arrayOfDetails.find(
|
||||
(item:any) => item.locale == language_id
|
||||
);
|
||||
if (!target) {
|
||||
return "";
|
||||
}
|
||||
|
||||
if (!Array.isArray(properties)) {
|
||||
return target[properties];
|
||||
}
|
||||
|
||||
// [prop1, prop2, prop3, ....] is passed
|
||||
const ret:any = {};
|
||||
properties.forEach((prop:string) => {
|
||||
ret[prop] = target[prop];
|
||||
});
|
||||
return ret;
|
||||
};
|
||||
|
||||
22
src/Hooks/useAuth.ts
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
import { useSelector } from "react-redux";
|
||||
import { authStorage } from "../auth/AuthStorage";
|
||||
|
||||
export const useAuth = () => {
|
||||
const { user, token, isAuthenticated } = useSelector(
|
||||
(state:any) => state.auth
|
||||
);
|
||||
|
||||
const logout = () => {
|
||||
authStorage.remove()
|
||||
};
|
||||
|
||||
return {
|
||||
user,
|
||||
token,
|
||||
isAuthenticated,
|
||||
logout,
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
65
src/Hooks/useChangeLanguage.tsx
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
import { useCallback, useEffect, useState } from "react";
|
||||
import translationEN from '../translate/en.json';
|
||||
import translationAR from '../translate/ar.json';
|
||||
import { initReactI18next } from 'react-i18next';
|
||||
import i18n from 'i18next';
|
||||
import { TranslateEnum } from "../enums/Translate";
|
||||
|
||||
i18n.use(initReactI18next).init({
|
||||
resources: {
|
||||
en: {
|
||||
translation: translationEN
|
||||
},
|
||||
ar: {
|
||||
translation: translationAR
|
||||
}
|
||||
},
|
||||
lng: localStorage.getItem('language') ?? 'en',
|
||||
interpolation: {
|
||||
escapeValue: false
|
||||
}
|
||||
});
|
||||
|
||||
export const useChangeLanguage = () => {
|
||||
const { ARABIC, ENGLISH } = TranslateEnum;
|
||||
const [currentLanguage, setCurrentLanguage] = useState(localStorage.getItem('language') ?? ENGLISH);
|
||||
const [userSelectedLanguage, setUserSelectedLanguage] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const storedLanguage = localStorage.getItem('language');
|
||||
|
||||
if (storedLanguage) {
|
||||
setCurrentLanguage(storedLanguage);
|
||||
setUserSelectedLanguage(true);
|
||||
} else {
|
||||
const languageMediaQuery = window.matchMedia('(prefers-language: ar)');
|
||||
setCurrentLanguage(languageMediaQuery.matches ? ARABIC : ENGLISH);
|
||||
setUserSelectedLanguage(false);
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (userSelectedLanguage) {
|
||||
if (currentLanguage === ARABIC) {
|
||||
i18n.changeLanguage(ARABIC);
|
||||
document.body.setAttribute('dir', 'rtl');
|
||||
document.body.classList.add(ARABIC);
|
||||
document.body.classList.remove(ENGLISH);
|
||||
} else {
|
||||
i18n.changeLanguage(ENGLISH);
|
||||
document.body.setAttribute('dir', 'ltr');
|
||||
document.body.classList.add(ENGLISH);
|
||||
document.body.classList.remove(ARABIC);
|
||||
}
|
||||
|
||||
localStorage.setItem('language', currentLanguage);
|
||||
}
|
||||
}, [currentLanguage, ARABIC, ENGLISH, userSelectedLanguage]);
|
||||
|
||||
const changeLanguage = useCallback((newLanguage: string) => {
|
||||
setCurrentLanguage(newLanguage);
|
||||
setUserSelectedLanguage(true);
|
||||
}, []);
|
||||
|
||||
return { currentLanguage, changeLanguage };
|
||||
};
|
||||
31
src/Hooks/useChangeTheme.tsx
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
import React, { useEffect, useState } from "react";
|
||||
import { ThemeModeEnum } from "../enums/ThemeMode";
|
||||
|
||||
export const useChangeTheme = () => {
|
||||
const { DARK_MODE, LIGHT_MODE } = ThemeModeEnum;
|
||||
const [currentTheme, setCurrentTheme] = useState<ThemeModeEnum | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
const storedTheme = localStorage.getItem('theme');
|
||||
|
||||
if (storedTheme) {
|
||||
setCurrentTheme(storedTheme as ThemeModeEnum);
|
||||
} else {
|
||||
const darkModeMediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
|
||||
setCurrentTheme(darkModeMediaQuery.matches ? DARK_MODE : LIGHT_MODE);
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (currentTheme) {
|
||||
document.body.classList.toggle(DARK_MODE, currentTheme === DARK_MODE);
|
||||
localStorage.setItem('theme', currentTheme);
|
||||
}
|
||||
}, [currentTheme]);
|
||||
|
||||
const changeTheme = (newTheme: ThemeModeEnum) => {
|
||||
setCurrentTheme(newTheme);
|
||||
};
|
||||
|
||||
return { currentTheme, changeTheme };
|
||||
};
|
||||
16
src/Hooks/useFormField.tsx
Normal 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;
|
||||
9
src/Hooks/useImageError.tsx
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
import React from 'react'
|
||||
import { UserImageURL } from '../Layout/app/Const';
|
||||
|
||||
const useImageError = ({currentTarget}:any) => {
|
||||
currentTarget.onerror = null;
|
||||
currentTarget.src=`${UserImageURL}`;
|
||||
}
|
||||
|
||||
export default useImageError
|
||||
13
src/Hooks/useLangCode.ts
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
import React from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
function useLangCode() {
|
||||
|
||||
const {i18n} = useTranslation()
|
||||
|
||||
return (
|
||||
i18n.language == 'en' ?'1' :'2'
|
||||
)
|
||||
}
|
||||
|
||||
export default useLangCode
|
||||
21
src/Hooks/useLoadingState.tsx
Normal 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;
|
||||
22
src/Hooks/useSearchResults.tsx
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
import { useEffect, useState } from 'react';
|
||||
|
||||
const useSearchResults = (data: any[] | undefined, query: string | null) => {
|
||||
const [results, setResults] = useState<any[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
const filteredResults = data?.filter((item: any) =>
|
||||
item?.toLowerCase()?.includes(query?.toLowerCase())
|
||||
) ?? [];
|
||||
|
||||
setResults(filteredResults);
|
||||
|
||||
if(results?.length === 0 && query != null && query?.length > 1 ){
|
||||
}
|
||||
}, [query]);
|
||||
|
||||
return results;
|
||||
};
|
||||
|
||||
export default useSearchResults;
|
||||
|
||||
|
||||
20
src/Hooks/useWindowResize.tsx
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
import React, { useEffect, useState } from 'react'
|
||||
|
||||
export const useWindowResize = () => {
|
||||
const [windowWidth, setWindowWidth] = useState(window.innerWidth);
|
||||
|
||||
useEffect(() => {
|
||||
window.addEventListener('resize', handleResize);
|
||||
// Cleanup function to remove the event listener
|
||||
return () => {
|
||||
window.removeEventListener('resize', handleResize);
|
||||
};
|
||||
}, [windowWidth]);
|
||||
|
||||
const handleResize = () => {
|
||||
setWindowWidth(window.innerWidth);
|
||||
};
|
||||
|
||||
return {windowWidth , handleResize};
|
||||
}
|
||||
|
||||
90
src/Layout/Footer.tsx
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
import MediaButton from '../Components/Ui/MediaButton';
|
||||
import SingleLink from '../Components/Ui/SingleLink';
|
||||
import { HomelinksArray, QuicklinksArray, ServicelinksArray } from '../data/Links';
|
||||
import FooterTItleWithSeparator from '../Components/Ui/FooterTItleWithSeperator';
|
||||
import ContactInfo from '../Components/Ui/ContactInfo';
|
||||
import { useGetHome } from '../api/home';
|
||||
import { BaseURL_IMAGE } from '../api/config';
|
||||
|
||||
const Footer = () => {
|
||||
const { t } = useTranslation();
|
||||
const {data} = useGetHome();
|
||||
const mediaArray = data?.Social_media
|
||||
const contactNumber = data?.Static_info[3]
|
||||
const contactEmail = data?.Static_info[4]
|
||||
const Logo = data?.Static_info[5]
|
||||
|
||||
return (
|
||||
<div className='footer_contianer'>
|
||||
<img className='footer_image' src="/Layout/FooterImage.png" alt="footer_image" />
|
||||
<div className='Footer'>
|
||||
<div className='logo_section'>
|
||||
<img src={BaseURL_IMAGE + Logo?.value} width={100} />
|
||||
<p>{t("We implement the corporate performance software for consolidation, planning and reporting porspises.")}</p>
|
||||
<FooterTItleWithSeparator title="Follow Us :"/>
|
||||
<div className='media_container'>
|
||||
{mediaArray?.map((media: { id: number; image: string; link:string}) => (
|
||||
<MediaButton key={media?.id} img={media?.image} link={media?.link} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className='home_links_section'>
|
||||
<FooterTItleWithSeparator title="Home"/>
|
||||
<div className="links_container">
|
||||
{HomelinksArray.map((link, index) => (
|
||||
<SingleLink key={index} href={link.href} name={link.name} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className='service_links_section'>
|
||||
<FooterTItleWithSeparator title="Service"/>
|
||||
<div className="links_container">
|
||||
{ServicelinksArray.map((link, index) => (
|
||||
<SingleLink key={index} href={link.href} name={link.name} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className='quick_links_section'>
|
||||
<FooterTItleWithSeparator title="Quick Links"/>
|
||||
<div className="links_container">
|
||||
{QuicklinksArray.map((link, index) => (
|
||||
<SingleLink key={index} href={link.href} name={link.name} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className='contact_links_section'>
|
||||
<FooterTItleWithSeparator title="Contact Us"/>
|
||||
<div className='media_container_info'>
|
||||
<div className='single_contact_info'>
|
||||
<MediaButton isStatic={true} img={MdLocalPhone}/>
|
||||
<ContactInfo
|
||||
title={contactNumber?.key}
|
||||
info={contactNumber?.value}/>
|
||||
</div>
|
||||
<div className='single_contact_info'>
|
||||
<MediaButton isStatic={true} img={CiMail}/>
|
||||
<ContactInfo
|
||||
title={contactEmail?.key}
|
||||
info={contactEmail?.value}/>
|
||||
</div>
|
||||
</div>
|
||||
<div className='responsive_sections'>
|
||||
<FooterTItleWithSeparator title="Follow Us :"/>
|
||||
<div className='media_container'>
|
||||
{mediaArray?.map((media: { id: number; image: string; link:string}) => (
|
||||
<MediaButton key={media?.id} img={media?.image} link={media?.link} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Footer;
|
||||
33
src/Layout/app/Header.tsx
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
import { HedaerLinksArray } from '../../data/HeaderLinks'
|
||||
import AnimationButton from '../../Components/Ui/AnimationButton';
|
||||
import HeaderMenu from './HeaderMenu';
|
||||
import { useGetHome } from '../../api/home';
|
||||
import { BaseURL_IMAGE } from '../../api/config';
|
||||
|
||||
const Header = () => {
|
||||
const {data} = useGetHome();
|
||||
const Logo = data?.Static_info[5]
|
||||
|
||||
return (
|
||||
<div className='header_container'>
|
||||
|
||||
<div className='image_container'>
|
||||
<img src={BaseURL_IMAGE + Logo?.value} alt='Misbar Logo' width={65}/>
|
||||
</div>
|
||||
<div className='Header_links'>
|
||||
{
|
||||
HedaerLinksArray.map((link,index) => (
|
||||
<Link style={link.isOnlyDrawer ? {display:"none"}:{display:"flex"}} key={index} to={link.href} className='Link'><h4>{link.name}</h4></Link>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
<div className="button_container">
|
||||
<AnimationButton link='/contact' text='Contact Us Now' icon={<FaTelegram/>}/>
|
||||
</div>
|
||||
|
||||
<HeaderMenu/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Header
|
||||
38
src/Layout/app/HeaderMenu.tsx
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
import WithDrawer from '../../HighOrderComponent/WithDrawer';
|
||||
import { Button } from 'antd';
|
||||
import { MenuOutlined } from '@ant-design/icons';
|
||||
import { HedaerLinksArray } from '../../data/HeaderLinks';
|
||||
import DrawerLink from '../../Components/Ui/DrawerLink';
|
||||
|
||||
const HeaderMenu = () => {
|
||||
return (
|
||||
<div className='menu_nav'>
|
||||
<WithDrawer
|
||||
title=''
|
||||
button={<Button icon={<MenuOutlined />} type='primary' />}
|
||||
>
|
||||
{({ closeDrawer }) => (
|
||||
<>
|
||||
<div className='header_logo'>
|
||||
<img src='./Logo/MisbarLogo.png' alt='logo' className='logo_drawer' />
|
||||
</div>
|
||||
<ul className='DrawerLinks'>
|
||||
{HedaerLinksArray.map((drawerLink, index) => (
|
||||
<DrawerLink
|
||||
isOnlyDrawer={drawerLink.isOnlyDrawer}
|
||||
icon={<drawerLink.icon />}
|
||||
key={index}
|
||||
href={drawerLink.href}
|
||||
name={drawerLink.name}
|
||||
closeDrawer={closeDrawer}
|
||||
/>
|
||||
))}
|
||||
</ul>
|
||||
</>
|
||||
)}
|
||||
</WithDrawer>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default HeaderMenu;
|
||||
19
src/Layout/app/Layout.tsx
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
import React from 'react';
|
||||
import Header from './Header';
|
||||
import Footer from '../Footer';
|
||||
|
||||
const Layout = (({ children, className = "" }: { children: React.ReactNode, className?: string }) => {
|
||||
|
||||
|
||||
return (
|
||||
<div className='Layout'>
|
||||
<Header />
|
||||
<main className={`${className} Layout_Body`}>
|
||||
{children}
|
||||
</main>
|
||||
<Footer />
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
export default Layout;
|
||||
13
src/Pages/About/Page.tsx
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
import About from '../../Components/about/About'
|
||||
import { useGetHome } from '../../api/home';
|
||||
|
||||
const AboutUS = () => {
|
||||
const {data} = useGetHome();
|
||||
return (
|
||||
<>
|
||||
<About data={data} isHaveHeader={true} />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default AboutUS
|
||||
14
src/Pages/Contact/Page.tsx
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
import Contact from "../../Components/contact/Contact"
|
||||
import { useGetHome } from "../../api/home"
|
||||
|
||||
const Page = () => {
|
||||
const {data} = useGetHome();
|
||||
|
||||
return (
|
||||
<div className='contact_container'>
|
||||
<Contact data={data} isHaveHeader={true}/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Page
|
||||
27
src/Pages/Home/Page.tsx
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
import HeroSection from "../../Components/Home/HeroSection";
|
||||
import Recent from "../../Components/Recent/Recent";
|
||||
import Service from "../../Components/Service/Service";
|
||||
import Works from "../../Components/Works/Works";
|
||||
import About from "../../Components/about/About";
|
||||
import Contact from "../../Components/contact/Contact";
|
||||
import { useGetHome } from "../../api/home";
|
||||
|
||||
|
||||
const Page = () => {
|
||||
const {data,isLoading} = useGetHome()
|
||||
console.log(data);
|
||||
|
||||
return (
|
||||
<>
|
||||
<HeroSection data={data} isLoading={isLoading}/>
|
||||
<About isHaveHeader={false} data={data} isLoading={isLoading} />
|
||||
<Service data={data} isHaveHeader={false} isLoading={isLoading} />
|
||||
<Works data={data} isLoading={isLoading} />
|
||||
<Contact data={data} isHaveHeader={false} isLoading={isLoading} />
|
||||
<Recent data={data} isLoading={isLoading} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Page;
|
||||
// footer -contact split
|
||||
19
src/Pages/Privacy/Page.tsx
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
import Info from "../../Components/Info/Info"
|
||||
import { useGetHome } from "../../api/home";
|
||||
import { PrivacyData } from "../../data/Info"
|
||||
|
||||
const Page = () => {
|
||||
const {data} = useGetHome();
|
||||
console.log(data?.Static_info);
|
||||
|
||||
const privacyData = data?.Static_info[2];
|
||||
return (
|
||||
<Info
|
||||
headerText="Privacy Policy"
|
||||
title={privacyData?.key}
|
||||
response={privacyData?.value}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export default Page
|
||||
38
src/Pages/Projects/Page.tsx
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
import { IoIosArrowDroprightCircle } from "react-icons/io";
|
||||
import AnimationButton from "../../Components/Ui/AnimationButton";
|
||||
import HeaderLink from "../../Components/Ui/HeaderLink"
|
||||
import { ProjectsArray } from "../../data/Projects";
|
||||
import ProjectCard from "../../Components/Projects/ProjectCard";
|
||||
import { useGetProject } from "../../api/project";
|
||||
import Spinner from "../../Components/Utils/Loading/Spinner";
|
||||
|
||||
const Page = () => {
|
||||
const {t} = useTranslation();
|
||||
const {data ,isLoading} = useGetProject();
|
||||
console.log(data);
|
||||
// const projectData = data?.
|
||||
|
||||
return (
|
||||
<div className="projects">
|
||||
<div className="projects_container">
|
||||
<HeaderLink text="Projects"/>
|
||||
<h1>{t("Explore the premium apps we offer for you.")}</h1>
|
||||
|
||||
<div className="single_project_container">
|
||||
{
|
||||
isLoading ? <Spinner/> :
|
||||
data?.map((item:any,index:number)=>(
|
||||
<ProjectCard data={item} key={index}/>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
|
||||
<div className='button_container'>
|
||||
<AnimationButton link='/' icon={<IoIosArrowDroprightCircle/>} text="View More" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Page
|
||||
14
src/Pages/Services/Page.tsx
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
import Service from '../../Components/Service/Service'
|
||||
import { useGetHome } from '../../api/home';
|
||||
|
||||
const Services = () => {
|
||||
const {data} = useGetHome();
|
||||
|
||||
return (
|
||||
<>
|
||||
<Service data={data} isHaveHeader={true}/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default Services
|
||||
40
src/Pages/SingleProject/Page.tsx
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
import { useState } from 'react';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { IoIosArrowDroprightCircle } from "react-icons/io";
|
||||
import AnimationButton from "../../Components/Ui/AnimationButton";
|
||||
import HeaderLink from "../../Components/Ui/HeaderLink";
|
||||
import { useGetProject } from '../../api/project';
|
||||
import { BaseURL_IMAGE } from '../../api/config';
|
||||
import Spinner from '../../Components/Utils/Loading/Spinner';
|
||||
import ReactPlayer from 'react-player';
|
||||
|
||||
const SingleProjectPage = () => {
|
||||
const { id } = useParams<{ id: string }>();
|
||||
const { data, isLoading } = useGetProject();
|
||||
const [playing, setPlaying] = useState(false);
|
||||
|
||||
const project = data?.find((p: { id: { toString: () => string | undefined; }; }) => p.id.toString() === id);
|
||||
|
||||
const handlePlayPause = () => {
|
||||
setPlaying(!playing);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className='projects single_projects'>
|
||||
<div className="projects_container">
|
||||
<HeaderLink text="View Application" isMulti={true} extraLink="/projects" extraText="Projects" />
|
||||
<h1>{isLoading ? <Spinner /> : project?.title}</h1>
|
||||
|
||||
<div className="video_section" id="video-section">
|
||||
<ReactPlayer onPlay={handlePlayPause} url={BaseURL_IMAGE + project?.video} playing={playing} controls={true} />
|
||||
</div>
|
||||
|
||||
<div className='button_container'>
|
||||
<AnimationButton link='/contact' icon={<IoIosArrowDroprightCircle />} text="Contact Us Now" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default SingleProjectPage;
|
||||