first push

This commit is contained in:
Moaz Dawalibi 2024-07-02 17:26:43 +03:00
parent 2005ea9a5d
commit d49b1c46e1
180 changed files with 53955 additions and 0 deletions

23
.gitignore vendored Normal file
View 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
View File

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

48
db.json Normal file
View 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
View 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

File diff suppressed because it is too large Load Diff

104
package.json Normal file
View 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

File diff suppressed because it is too large Load Diff

BIN
public/App/DarkBlueBg.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 283 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

BIN
public/App/WhiteBg.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 861 KiB

BIN
public/App/WhiteBgRes.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 354 KiB

BIN
public/Home/HeroBg.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

BIN
public/Home/HeroBgRes.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 KiB

View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 384 KiB

BIN
public/Home/scrollDown.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

1
public/Layout/Ar.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 10 KiB

1
public/Layout/En.svg Normal file
View File

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

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 624 KiB

1
public/Layout/dark.svg Normal file
View 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
View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

108
public/MainPartnerr.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 87 KiB

BIN
public/Works/Works.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 313 KiB

BIN
public/Works/WorksBgRes.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 115 KiB

25
public/manifest.json Normal file
View File

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

3
public/robots.txt Normal file
View File

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

34
src/App.tsx Normal file
View 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;

View 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

View 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

View 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

View 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;

View 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

View 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

View 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

View 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;

View 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;

View 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

View 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

View 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

View 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;

View 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;

View 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;

View 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

View 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;

View 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;

View 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',
},
];

View 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;

View 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

View 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%;
}
}
}

View 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

View 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

View 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;
}

View File

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

View File

@ -0,0 +1,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

View 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 };

View 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

View 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;
}

View 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;

View 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

View 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

View 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

View 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;

View 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

View 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

View 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

View 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

View File

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

View 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
}

View 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;

View 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;

View 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

View 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;

View 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

View 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;

View 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

View 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;

View 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;
}

View 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
View 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,
};
};

View 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 };
};

View 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 };
};

View File

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

View File

@ -0,0 +1,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
View 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

View File

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

View File

@ -0,0 +1,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;

View 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
View 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
View 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

View 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
View 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
View 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

View 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
View 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

View 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

View 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

View 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

View 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;

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