├── src ├── web │ ├── public │ │ ├── icons │ │ │ ├── icon-384x384.png │ │ │ ├── icon-512x512.png │ │ │ ├── icon-72x72.png │ │ │ ├── icon-192x192.png │ │ │ ├── icon-96x96.png │ │ │ ├── icon-152x152.png │ │ │ ├── icon-128x128.png │ │ │ └── icon-144x144.png │ │ ├── robots.txt │ │ ├── favicon.ico │ │ └── locales │ │ │ ├── en │ │ │ └── messages.json │ │ │ └── ar │ │ │ ├── payment.json │ │ │ └── messages.json │ ├── .prettierrc │ ├── .env.example │ ├── .dockerignore │ ├── next-env.d.ts │ ├── tsconfig.json │ ├── src │ │ ├── types │ │ │ └── environment.d.ts │ │ ├── constants │ │ │ └── categories.ts │ │ ├── interfaces │ │ │ └── location.interface.ts │ │ └── pages │ │ │ └── categories │ │ │ └── index.tsx │ └── .eslintrc.json └── backend │ ├── lerna.json │ ├── nodemon.json │ ├── messaging-service │ ├── tsconfig.json │ ├── Dockerfile │ ├── src │ │ └── interfaces │ │ │ └── message.interface.ts │ └── package.json │ ├── .prettierrc │ ├── payment-service │ ├── tsconfig.json │ └── Dockerfile │ ├── location-service │ ├── tsconfig.json │ └── Dockerfile │ ├── api-gateway │ ├── package.json │ ├── tsconfig.json │ ├── Dockerfile │ └── src │ │ └── config │ │ └── cors.config.ts │ ├── .eslintrc.json │ ├── marketplace-service │ ├── tsconfig.json │ └── Dockerfile │ ├── auth-service │ ├── tsconfig.json │ └── package.json │ ├── tsconfig.json │ ├── shared │ ├── interfaces │ │ └── base.interface.ts │ └── constants │ │ └── languages.ts │ ├── .dockerignore │ ├── Dockerfile │ └── .env.example ├── frontend ├── .env ├── src │ ├── App.css │ ├── App.js │ ├── features │ │ ├── MultiLanguage │ │ │ ├── LanguageSelector.css │ │ │ ├── LanguageSelector.js │ │ │ └── i18n.js │ │ ├── ARShopping │ │ │ ├── ARService.js │ │ │ ├── ARShopping.js │ │ │ ├── ARShopping.css │ │ │ └── ARViewer.js │ │ ├── SocialCommerce │ │ │ ├── SocialService.js │ │ │ ├── SocialFeed.css │ │ │ ├── ShareButton.js │ │ │ └── SocialFeed.js │ │ ├── Recommendations │ │ │ ├── RecommendationService.js │ │ │ ├── RecommendationList.css │ │ │ └── RecommendationList.js │ │ ├── Delivery │ │ │ ├── DeliveryService.js │ │ │ ├── DeliveryTracker.css │ │ │ └── DeliveryTracker.js │ │ ├── Chatbot │ │ │ ├── ChatbotService.js │ │ │ ├── Chatbot.css │ │ │ └── Chatbot.js │ │ ├── Escrow │ │ │ ├── EscrowService.js │ │ │ ├── EscrowPayment.css │ │ │ └── EscrowPayment.js │ │ ├── Gamification │ │ │ ├── GamificationService.js │ │ │ ├── GamificationDashboard.css │ │ │ └── GamificationDashboard.js │ │ ├── EducationalContent │ │ │ ├── EducationalService.js │ │ │ ├── EducationalArticle.css │ │ │ └── EducationalArticle.js │ │ ├── Sustainability │ │ │ ├── SustainabilityService.js │ │ │ ├── SustainabilityList.css │ │ │ └── SustainabilityList.js │ │ ├── Subscription │ │ │ ├── SubscriptionService.js │ │ │ ├── SubscriptionForm.css │ │ │ └── SubscriptionForm.js │ │ ├── LoyaltyProgram │ │ │ ├── LoyaltyProgram.css │ │ │ ├── LoyaltyService.js │ │ │ └── LoyaltyProgram.js │ │ ├── Events │ │ │ ├── EventList.css │ │ │ ├── EventService.js │ │ │ ├── EventDetail.js │ │ │ └── EventList.js │ │ ├── Reviews │ │ │ ├── ReviewService.js │ │ │ ├── ReviewList.js │ │ │ └── ReviewForm.js │ │ └── UserGeneratedContent │ │ │ ├── UserContentService.js │ │ │ ├── UserContentList.css │ │ │ ├── UserContentForm.js │ │ │ └── UserContentList.js │ ├── index.js │ └── routes.js └── package.json ├── .github ├── ISSUE_TEMPLATE │ ├── custom.md │ └── bug_report.md ├── dependabot.yml └── CODEOWNERS ├── .whitesource ├── documentation └── Input Prompt.md ├── LICENSE └── infrastructure ├── terraform ├── modules │ ├── cdn │ │ ├── outputs.tf │ │ └── variables.tf │ ├── s3 │ │ └── outputs.tf │ └── eks │ │ └── outputs.tf ├── backend.tf └── providers.tf └── kubernetes ├── namespaces.yaml ├── services.yaml ├── autoscaling ├── vpa.yaml └── hpa.yaml ├── storage └── persistent-volumes.yaml ├── secrets.yaml └── configmaps.yaml /src/web/public/icons/icon-384x384.png: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/.env: -------------------------------------------------------------------------------- 1 | # .env 2 | 3 | REACT_APP_API_BASE_URL=http://localhost:5000/api 4 | REACT_APP_GOOGLE_MAPS_API_KEY=your_google_maps_api_key 5 | REACT_APP_STRIPE_PUBLIC_KEY=your_stripe_public_key 6 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/custom.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Custom issue template 3 | about: Describe this issue template's purpose here. 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | 11 | -------------------------------------------------------------------------------- /frontend/src/App.css: -------------------------------------------------------------------------------- 1 | /* src/App.css */ 2 | 3 | .app { 4 | font-family: Arial, sans-serif; 5 | margin: 0; 6 | padding: 0; 7 | background-color: #f0f0f0; 8 | min-height: 100vh; 9 | } 10 | -------------------------------------------------------------------------------- /.whitesource: -------------------------------------------------------------------------------- 1 | { 2 | "scanSettings": { 3 | "baseBranches": [] 4 | }, 5 | "checkRunSettings": { 6 | "vulnerableCheckRunConclusionLevel": "failure", 7 | "displayMode": "diff", 8 | "useMendCheckNames": true 9 | }, 10 | "issueSettings": { 11 | "minSeverityLevel": "LOW", 12 | "issueType": "DEPENDENCY" 13 | } 14 | } -------------------------------------------------------------------------------- /frontend/src/App.js: -------------------------------------------------------------------------------- 1 | // src/App.js 2 | 3 | import React from 'react'; 4 | import { BrowserRouter as Router } from 'react-router-dom'; 5 | import routes from './routes'; 6 | import './App.css'; 7 | 8 | const App = () => { 9 | return ( 10 | 11 |
12 | {routes} 13 |
14 |
15 | ); 16 | }; 17 | 18 | export default App; 19 | -------------------------------------------------------------------------------- /frontend/src/features/MultiLanguage/LanguageSelector.css: -------------------------------------------------------------------------------- 1 | /* src/features/MultiLanguage/LanguageSelector.css */ 2 | 3 | .language-selector { 4 | margin: 20px 0; 5 | } 6 | 7 | .language-selector label { 8 | margin-right: 10px; 9 | font-weight: bold; 10 | } 11 | 12 | .language-selector select { 13 | padding: 5px; 14 | border: 1px solid #ccc; 15 | border-radius: 4px; 16 | font-size: 16px; 17 | } 18 | -------------------------------------------------------------------------------- /frontend/src/index.js: -------------------------------------------------------------------------------- 1 | // src/index.js 2 | 3 | import React from 'react'; 4 | import ReactDOM from 'react-dom'; 5 | import App from './App'; 6 | import './index.css'; // Global styles 7 | import './features/MultiLanguage/i18n'; // Import i18n configuration for multi-language support 8 | 9 | ReactDOM.render( 10 | 11 | 12 | , 13 | document.getElementById('root') 14 | ); 15 | -------------------------------------------------------------------------------- /frontend/src/features/ARShopping/ARService.js: -------------------------------------------------------------------------------- 1 | // src/features/ARShopping/ARService.js 2 | 3 | const API_BASE_URL = '/api/ar'; // Adjust this to your actual API base URL 4 | 5 | export const fetchProducts = async () => { 6 | const response = await fetch(`${API_BASE_URL}/products`, { 7 | method: 'GET', 8 | headers: { 9 | 'Content-Type': 'application/json', 10 | // Add authorization headers if needed 11 | }, 12 | }); 13 | if (!response.ok) { 14 | throw new Error('Failed to fetch products'); 15 | } 16 | const data = await response.json(); 17 | return data.products; 18 | }; 19 | -------------------------------------------------------------------------------- /frontend/src/features/SocialCommerce/SocialService.js: -------------------------------------------------------------------------------- 1 | // src/features/SocialCommerce/SocialService.js 2 | 3 | const API_BASE_URL = '/api/social'; // Adjust this to your actual API base URL 4 | 5 | export const fetchSocialPosts = async () => { 6 | const response = await fetch(`${API_BASE_URL}/posts`, { 7 | method: 'GET', 8 | headers: { 9 | 'Content-Type': 'application/json', 10 | // Add authorization headers if needed 11 | }, 12 | }); 13 | if (!response.ok) { 14 | throw new Error('Failed to fetch social posts'); 15 | } 16 | const data = await response.json(); 17 | return data.posts; 18 | }; 19 | -------------------------------------------------------------------------------- /frontend/src/features/Recommendations/RecommendationService.js: -------------------------------------------------------------------------------- 1 | // src/features/Recommendations/RecommendationService.js 2 | 3 | const API_BASE_URL = '/api/recommendations'; // Adjust this to your actual API base URL 4 | 5 | export const fetchRecommendations = async () => { 6 | const response = await fetch(API_BASE_URL, { 7 | method: 'GET', 8 | headers: { 9 | 'Content-Type': 'application/json', 10 | // Add authorization headers if needed 11 | }, 12 | }); 13 | if (!response.ok) { 14 | throw new Error('Failed to fetch recommendations'); 15 | } 16 | const data = await response.json(); 17 | return data.recommendations; 18 | }; 19 | -------------------------------------------------------------------------------- /frontend/src/features/Delivery/DeliveryService.js: -------------------------------------------------------------------------------- 1 | // src/features/Delivery/DeliveryService.js 2 | 3 | const API_BASE_URL = '/api/delivery'; // Adjust this to your actual API base URL 4 | 5 | export const trackDelivery = async (trackingNumber) => { 6 | const response = await fetch(`${API_BASE_URL}/track`, { 7 | method: 'POST', 8 | headers: { 9 | 'Content-Type': 'application/json', 10 | }, 11 | body: JSON.stringify({ trackingNumber }), 12 | }); 13 | 14 | if (!response.ok) { 15 | throw new Error('Failed to track delivery'); 16 | } 17 | 18 | const data = await response.json(); 19 | return data.status; // Assuming the response contains a status field 20 | }; 21 | -------------------------------------------------------------------------------- /frontend/src/features/Chatbot/ChatbotService.js: -------------------------------------------------------------------------------- 1 | // src/features/Chatbot/ChatbotService.js 2 | 3 | const API_BASE_URL = '/api/chatbot'; // Adjust this to your actual API base URL 4 | 5 | export const sendMessage = async (message) => { 6 | const response = await fetch(`${API_BASE_URL}/send`, { 7 | method: 'POST', 8 | headers: { 9 | 'Content-Type': 'application/json', 10 | }, 11 | body: JSON.stringify({ message }), 12 | }); 13 | 14 | if (!response.ok) { 15 | throw new Error('Failed to send message to the chatbot'); 16 | } 17 | 18 | const data = await response.json(); 19 | return { text: data.response, sender: 'bot' }; // Assuming the response structure 20 | }; 21 | -------------------------------------------------------------------------------- /frontend/src/features/Escrow/EscrowService.js: -------------------------------------------------------------------------------- 1 | // src/features/Escrow/EscrowService.js 2 | 3 | const API_BASE_URL = '/api/escrow'; // Adjust this to your actual API base URL 4 | 5 | export const createEscrowPayment = async ({ amount, recipient }) => { 6 | const response = await fetch(`${API_BASE_URL}/create`, { 7 | method: 'POST', 8 | headers: { 9 | 'Content-Type': 'application/json', 10 | }, 11 | body: JSON.stringify({ amount, recipient }), 12 | }); 13 | 14 | if (!response.ok) { 15 | throw new Error('Failed to create escrow payment'); 16 | } 17 | 18 | const data = await response.json(); 19 | return data; // Assuming the response contains payment details 20 | }; 21 | -------------------------------------------------------------------------------- /frontend/src/features/Gamification/GamificationService.js: -------------------------------------------------------------------------------- 1 | // src/features/Gamification/GamificationService.js 2 | 3 | const API_BASE_URL = '/api/gamification'; // Adjust this to your actual API base URL 4 | 5 | export const fetchUserProgress = async () => { 6 | const response = await fetch(`${API_BASE_URL}/progress`, { 7 | method: 'GET', 8 | headers: { 9 | 'Content-Type': 'application/json', 10 | // Add authorization headers if needed 11 | }, 12 | }); 13 | 14 | if (!response.ok) { 15 | throw new Error('Failed to fetch user progress'); 16 | } 17 | 18 | const data = await response.json(); 19 | return data; // Assuming the response contains user progress details 20 | }; 21 | -------------------------------------------------------------------------------- /frontend/src/features/EducationalContent/EducationalService.js: -------------------------------------------------------------------------------- 1 | // src/features/EducationalContent/EducationalService.js 2 | 3 | const API_BASE_URL = '/api/educational'; // Adjust this to your actual API base URL 4 | 5 | export const fetchEducationalArticles = async () => { 6 | const response = await fetch(`${API_BASE_URL}/articles`, { 7 | method: 'GET', 8 | headers: { 9 | 'Content-Type': 'application/json', 10 | // Add authorization headers if needed 11 | }, 12 | }); 13 | if (!response.ok) { 14 | throw new Error('Failed to fetch educational articles'); 15 | } 16 | const data = await response.json(); 17 | return data.articles; // Assuming the response contains an articles array 18 | }; 19 | -------------------------------------------------------------------------------- /frontend/src/features/Sustainability/SustainabilityService.js: -------------------------------------------------------------------------------- 1 | // src/features/Sustainability/SustainabilityService.js 2 | 3 | const API_BASE_URL = '/api/sustainability'; // Adjust this to your actual API base URL 4 | 5 | export const fetchSustainableProducts = async () => { 6 | const response = await fetch(`${API_BASE_URL}/products`, { 7 | method: 'GET', 8 | headers: { 9 | 'Content-Type': 'application/json', 10 | // Add authorization headers if needed 11 | }, 12 | }); 13 | if (!response.ok) { 14 | throw new Error('Failed to fetch sustainable products'); 15 | } 16 | const data = await response.json(); 17 | return data.products; // Assuming the response contains a products array 18 | }; 19 | -------------------------------------------------------------------------------- /src/web/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "semi": true, 3 | "singleQuote": true, 4 | "trailingComma": "es5", 5 | "printWidth": 100, 6 | "tabWidth": 2, 7 | "useTabs": false, 8 | "bracketSpacing": true, 9 | "jsxBracketSameLine": false, 10 | "arrowParens": "always", 11 | "endOfLine": "lf", 12 | "jsxSingleQuote": true, 13 | "quoteProps": "as-needed", 14 | "htmlWhitespaceSensitivity": "css", 15 | "embeddedLanguageFormatting": "auto", 16 | "proseWrap": "preserve", 17 | "overrides": [ 18 | { 19 | "files": ["*.ts", "*.tsx"], 20 | "options": { 21 | "parser": "typescript" 22 | } 23 | }, 24 | { 25 | "files": ["*.json", "*.jsonc"], 26 | "options": { 27 | "parser": "json" 28 | } 29 | } 30 | ] 31 | } -------------------------------------------------------------------------------- /frontend/src/features/Subscription/SubscriptionService.js: -------------------------------------------------------------------------------- 1 | // src/features/Subscription/SubscriptionService.js 2 | 3 | const API_BASE_URL = '/api/subscription'; // Adjust this to your actual API base URL 4 | 5 | export const createSubscription = async ({ plan, paymentInfo }) => { 6 | const response = await fetch(`${API_BASE_URL}/create`, { 7 | method: 'POST', 8 | headers: { 9 | 'Content-Type': 'application/json', 10 | }, 11 | body: JSON.stringify({ plan, paymentInfo }), 12 | }); 13 | 14 | if (!response.ok) { 15 | throw new Error('Failed to create subscription'); 16 | } 17 | 18 | const data = await response.json(); 19 | return data; // Assuming the response contains subscription details 20 | }; 21 | -------------------------------------------------------------------------------- /src/backend/lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1.0.0", 3 | "npmClient": "npm", 4 | "useWorkspaces": true, 5 | "packages": [ 6 | "api-gateway", 7 | "auth-service", 8 | "location-service", 9 | "marketplace-service", 10 | "messaging-service", 11 | "payment-service", 12 | "shared" 13 | ], 14 | "command": { 15 | "bootstrap": { 16 | "hoist": true, 17 | "npmClientArgs": [ 18 | "--no-package-lock" 19 | ] 20 | }, 21 | "publish": { 22 | "conventionalCommits": true, 23 | "message": "chore(release): publish %s", 24 | "registry": "https://registry.npmjs.org/" 25 | }, 26 | "version": { 27 | "conventionalCommits": true, 28 | "message": "chore(release): version %s", 29 | "changelogPreset": "angular" 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /documentation/Input Prompt.md: -------------------------------------------------------------------------------- 1 | EGYPTIAN Map Of Pi is a Pi ecosystem app. USED  Pi Browser to access it and more in the Pi ecosystem. WANT DO IT FOR EGYPT PIONEERS LOCAL MARKER SELLERS AND BUYER 2 | 3 | Works: 4 | 5 | Map of Pi is an innovative phone app designed for pioneers within the Pi Network. Here's a brief overview of Map of Pi and how it functions: 6 | 7 | Map of Pi allows pioneers to Search, Buy & Sell goods and services using Pi directly between Pi Wallets. 8 | 9 | It was selected as the winner of the 2024 Commerce Hackathon by the Pi Core Team. 10 | 11 | To access Map of Pi, you can visit mapofpi.pinet.com in the Pi Browser. 12 | 13 | Additional Resource: 14 | 15 | You can learn more about Map of Pi and its features by exploring the app in the Pi Browser. Feel free to ask more specific questions for detailed information! -------------------------------------------------------------------------------- /src/backend/nodemon.json: -------------------------------------------------------------------------------- 1 | { 2 | "watch": [ 3 | "src/**/*.ts", 4 | "src/**/*.json", 5 | "shared/**/*.ts", 6 | "shared/**/*.json", 7 | "config/**/*.ts", 8 | "config/**/*.json" 9 | ], 10 | "ignore": [ 11 | "**/*.test.ts", 12 | "**/*.spec.ts", 13 | "**/__tests__/**", 14 | "**/__mocks__/**", 15 | "node_modules", 16 | "dist", 17 | "coverage", 18 | ".git", 19 | "logs" 20 | ], 21 | "exec": "ts-node --project tsconfig.json", 22 | "ext": ".ts,.js,.json,.mjs", 23 | "delay": 2000, 24 | "verbose": true, 25 | "legacyWatch": false, 26 | "polling": false, 27 | "restartable": "rs", 28 | "colours": true, 29 | "env": { 30 | "NODE_ENV": "development", 31 | "TS_NODE_PROJECT": "tsconfig.json", 32 | "TS_NODE_TRANSPILE_ONLY": "false", 33 | "DEBUG": "egyptian-map-pi:*" 34 | } 35 | } -------------------------------------------------------------------------------- /frontend/src/features/MultiLanguage/LanguageSelector.js: -------------------------------------------------------------------------------- 1 | // src/features/MultiLanguage/LanguageSelector.js 2 | 3 | import React from 'react'; 4 | import { useTranslation } from 'react-i18next'; 5 | import './LanguageSelector.css'; 6 | 7 | const LanguageSelector = () => { 8 | const { i18n } = useTranslation(); 9 | 10 | const handleLanguageChange = (event) => { 11 | i18n.changeLanguage(event.target.value); 12 | }; 13 | 14 | return ( 15 |
16 | 17 | 23 |
24 | ); 25 | }; 26 | 27 | export default LanguageSelector; 28 | -------------------------------------------------------------------------------- /frontend/src/features/SocialCommerce/SocialFeed.css: -------------------------------------------------------------------------------- 1 | /* src/features/SocialCommerce/SocialFeed.css */ 2 | 3 | .social-feed { 4 | padding: 20px; 5 | background-color: #f9f9f9; 6 | border-radius: 8px; 7 | box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); 8 | } 9 | 10 | .social-feed h2 { 11 | color: #333; 12 | } 13 | 14 | .social-post { 15 | background-color: white; 16 | border: 1px solid #ddd; 17 | border-radius: 8px; 18 | padding: 10px; 19 | margin-bottom: 20px; 20 | } 21 | 22 | .social-post img { 23 | max-width: 100%; 24 | border-radius: 4px; 25 | } 26 | 27 | .social-post h3 { 28 | color: #555; 29 | } 30 | 31 | .social-post p { 32 | color: #777; 33 | } 34 | 35 | .share-button { 36 | background-color: #4CAF50; 37 | color: white; 38 | border: none; 39 | border-radius: 4px; 40 | padding: 10px 15px; 41 | cursor: pointer; 42 | } 43 | 44 | .share-button:hover { 45 | background-color: #45a049; 46 | } 47 | -------------------------------------------------------------------------------- /frontend/src/features/Gamification/GamificationDashboard.css: -------------------------------------------------------------------------------- 1 | /* src/features/Gamification/GamificationDashboard.css */ 2 | 3 | .gamification-dashboard { 4 | padding: 20px; 5 | background-color: #f9f9f9; 6 | border-radius: 8px; 7 | box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); 8 | max-width: 400px; 9 | margin: auto; 10 | } 11 | 12 | .gamification-dashboard h2 { 13 | color: #333; 14 | } 15 | 16 | .points { 17 | font-size: 24px; 18 | font-weight: bold; 19 | margin-bottom: 20px; 20 | } 21 | 22 | .achievements { 23 | margin-bottom: 20px; 24 | } 25 | 26 | .achievements ul { 27 | list-style-type: none; 28 | padding: 0; 29 | } 30 | 31 | .progress { 32 | margin-top: 20px; 33 | } 34 | 35 | .progress-bar { 36 | width: 100%; 37 | background-color: #ddd; 38 | border-radius: 4px; 39 | overflow: hidden; 40 | } 41 | 42 | .progress-fill { 43 | height: 10px; 44 | background-color: #4CAF50; 45 | transition: width 0.3s ease; 46 | } 47 | -------------------------------------------------------------------------------- /frontend/src/features/LoyaltyProgram/LoyaltyProgram.css: -------------------------------------------------------------------------------- 1 | /* src/features/LoyaltyProgram/LoyaltyProgram.css */ 2 | 3 | .loyalty-program { 4 | padding: 20px; 5 | background-color: #f9f9f9; 6 | border-radius: 8px; 7 | box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); 8 | } 9 | 10 | .loyalty-program h2 { 11 | color: #333; 12 | } 13 | 14 | .loyalty-program h3 { 15 | margin-top: 20px; 16 | color: #555; 17 | } 18 | 19 | .loyalty-program ul { 20 | list-style-type: none; 21 | padding: 0; 22 | } 23 | 24 | .loyalty-program li { 25 | display: flex; 26 | justify-content: space-between; 27 | align-items: center; 28 | padding: 10px; 29 | border-bottom: 1px solid #ddd; 30 | } 31 | 32 | .loyalty-program button { 33 | background-color: #4CAF50; 34 | color: white; 35 | border: none; 36 | border-radius: 4px; 37 | padding: 5px 10px; 38 | cursor: pointer; 39 | } 40 | 41 | .loyalty-program button:hover { 42 | background-color: #45a049; 43 | } 44 | -------------------------------------------------------------------------------- /frontend/src/features/Events/EventList.css: -------------------------------------------------------------------------------- 1 | /* src/features/Events/EventList.css */ 2 | 3 | .event-list { 4 | padding: 20px; 5 | background-color: #f9f9f9; 6 | border-radius: 8px; 7 | box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); 8 | } 9 | 10 | .event-list h2 { 11 | color: #333; 12 | margin-bottom: 20px; 13 | } 14 | 15 | .event-list ul { 16 | list-style-type: none; 17 | padding: 0; 18 | } 19 | 20 | .event-list li { 21 | background-color: white; 22 | border: 1px solid #ddd; 23 | border-radius: 8px; 24 | padding: 15px; 25 | margin-bottom: 15px; 26 | transition: box-shadow 0.3s ease; 27 | } 28 | 29 | .event-list li:hover { 30 | box-shadow: 0 4px 20px rgba(0, 0, 0, 0.2); 31 | } 32 | 33 | .event-list h3 { 34 | color: #555; 35 | margin: 0; 36 | } 37 | 38 | .event-list p { 39 | color: #777; 40 | margin: 5px 0 0; 41 | } 42 | 43 | .event-list a { 44 | text-decoration: none; 45 | color: inherit; /* Inherit color from parent */ 46 | } 47 | -------------------------------------------------------------------------------- /frontend/src/features/EducationalContent/EducationalArticle.css: -------------------------------------------------------------------------------- 1 | /* src/features/EducationalContent/EducationalArticle.css */ 2 | 3 | .educational-article { 4 | padding: 20px; 5 | background-color: #f9f9f9; 6 | border-radius: 8px; 7 | box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); 8 | } 9 | 10 | .educational-article h2 { 11 | color: #333; 12 | } 13 | 14 | .educational-article ul { 15 | list-style-type: none; 16 | padding: 0; 17 | } 18 | 19 | .educational-article li { 20 | padding: 10px; 21 | border-bottom: 1px solid #ddd; 22 | } 23 | 24 | .educational-article li h3 { 25 | margin: 0; 26 | color: #007BFF; 27 | } 28 | 29 | .educational-article li p { 30 | color: #777; 31 | margin: 5px 0 0; 32 | } 33 | 34 | .educational-article button { 35 | background-color: #4CAF50; 36 | color: white; 37 | border: none; 38 | border-radius: 4px; 39 | padding: 10px; 40 | cursor: pointer; 41 | } 42 | 43 | .educational-article button:hover { 44 | background-color: #45a049; 45 | } 46 | -------------------------------------------------------------------------------- /frontend/src/features/Escrow/EscrowPayment.css: -------------------------------------------------------------------------------- 1 | /* src/features/Escrow/EscrowPayment.css */ 2 | 3 | .escrow-payment { 4 | padding: 20px; 5 | background-color: #f9f9f9; 6 | border-radius: 8px; 7 | box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); 8 | max-width: 400px; 9 | margin: auto; 10 | } 11 | 12 | .escrow-payment h2 { 13 | color: #333; 14 | } 15 | 16 | .escrow-payment label { 17 | display: block; 18 | margin: 10px 0 5px; 19 | } 20 | 21 | .escrow-payment input { 22 | width: 100%; 23 | padding: 10px; 24 | border: 1px solid #ccc; 25 | border-radius: 4px; 26 | margin-bottom: 10px; 27 | } 28 | 29 | .escrow-payment button { 30 | background-color: #4CAF50; 31 | color: white; 32 | border: none; 33 | border-radius: 4px; 34 | padding: 10px; 35 | cursor: pointer; 36 | } 37 | 38 | .escrow-payment button:hover { 39 | background-color: #45a049; 40 | } 41 | 42 | .error { 43 | color: red; 44 | margin-bottom: 10px; 45 | } 46 | 47 | .success { 48 | color: green; 49 | margin-bottom: 10px; 50 | } 51 | -------------------------------------------------------------------------------- /src/backend/messaging-service/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "rootDir": "./src", 5 | "outDir": "./dist", 6 | "baseUrl": "./src", 7 | "paths": { 8 | "@shared/*": ["../../shared/*"], 9 | "@models/*": ["models/*"], 10 | "@services/*": ["services/*"], 11 | "@controllers/*": ["controllers/*"], 12 | "@interfaces/*": ["interfaces/*"], 13 | "@config/*": ["config/*"], 14 | "@utils/*": ["utils/*"] 15 | }, 16 | "typeRoots": [ 17 | "./node_modules/@types", 18 | "./src/types" 19 | ], 20 | "types": [ 21 | "node", 22 | "jest", 23 | "socket.io" 24 | ] 25 | }, 26 | "include": [ 27 | "src/**/*.ts", 28 | "src/**/*.json" 29 | ], 30 | "exclude": [ 31 | "node_modules", 32 | "dist", 33 | "coverage", 34 | "**/*.test.ts", 35 | "**/*.spec.ts" 36 | ], 37 | "references": [ 38 | { 39 | "path": "../shared" 40 | } 41 | ], 42 | "ts-node": { 43 | "transpileOnly": true, 44 | "files": true 45 | } 46 | } -------------------------------------------------------------------------------- /frontend/src/features/Delivery/DeliveryTracker.css: -------------------------------------------------------------------------------- 1 | /* src/features/Delivery/DeliveryTracker.css */ 2 | 3 | .delivery-tracker { 4 | padding: 20px; 5 | background-color: #f9f9f9; 6 | border-radius: 8px; 7 | box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); 8 | max-width: 400px; 9 | margin: auto; 10 | } 11 | 12 | .delivery-tracker h2 { 13 | color: #333; 14 | } 15 | 16 | .delivery-tracker input { 17 | width: 100%; 18 | padding: 10px; 19 | border: 1px solid #ccc; 20 | border-radius: 4px; 21 | margin-bottom: 10px; 22 | } 23 | 24 | .delivery-tracker button { 25 | background-color: #4CAF50; 26 | color: white; 27 | border: none; 28 | border-radius: 4px; 29 | padding: 10px; 30 | cursor: pointer; 31 | } 32 | 33 | .delivery-tracker button:hover { 34 | background-color: #45a049; 35 | } 36 | 37 | .error { 38 | color: red; 39 | margin-top: 10px; 40 | } 41 | 42 | .delivery-status { 43 | margin-top: 20px; 44 | padding: 10px; 45 | border: 1px solid #ddd; 46 | border-radius: 4px; 47 | background-color: #e7f3fe; 48 | } 49 | -------------------------------------------------------------------------------- /src/web/.env.example: -------------------------------------------------------------------------------- 1 | # Core API communication settings for backend services 2 | # Version: v1.0.0 3 | NEXT_PUBLIC_API_BASE_URL=http://localhost:3000/api/v1 4 | NEXT_PUBLIC_API_TIMEOUT=30000 5 | 6 | # Maps Configuration 7 | # Mapbox integration settings for location services and geospatial features 8 | # Version: v2.0.0 9 | NEXT_PUBLIC_MAPBOX_ACCESS_TOKEN=your_mapbox_access_token_here 10 | 11 | # Pi Network Configuration 12 | # Pi Network integration settings for authentication and transactions 13 | # Version: v1.0.0 14 | NEXT_PUBLIC_PI_API_KEY=your_pi_network_api_key_here 15 | NEXT_PUBLIC_PI_NETWORK_URL=https://api.minepi.com 16 | 17 | # Application Configuration 18 | # General application settings including environment and localization 19 | NEXT_PUBLIC_ENVIRONMENT=development 20 | NEXT_PUBLIC_DEFAULT_LANGUAGE=ar 21 | NEXT_PUBLIC_FALLBACK_LANGUAGE=en 22 | NEXT_PUBLIC_APP_NAME=Egyptian Map of Pi 23 | 24 | # Upload Configuration 25 | # File upload constraints and configurations 26 | NEXT_PUBLIC_MAX_UPLOAD_SIZE=5242880 27 | NEXT_PUBLIC_SUPPORTED_IMAGE_TYPES=image/jpeg,image/png,image/webp 28 | NEXT_PUBLIC_MAX_LISTING_IMAGES=5 -------------------------------------------------------------------------------- /frontend/src/features/Events/EventService.js: -------------------------------------------------------------------------------- 1 | // src/features/Events/EventService.js 2 | 3 | const API_BASE_URL = '/api/events'; // Adjust this to your actual API base URL 4 | 5 | export const fetchEvents = async () => { 6 | const response = await fetch(API_BASE_URL, { 7 | method: 'GET', 8 | headers: { 9 | 'Content-Type': 'application/json', 10 | // Add authorization headers if needed 11 | }, 12 | }); 13 | if (!response.ok) { 14 | throw new Error('Failed to fetch events'); 15 | } 16 | const data = await response.json(); 17 | return data.events; 18 | }; 19 | 20 | export const fetchEventDetails = async (eventId) => { 21 | const response = await fetch(`${API_BASE_URL}/${eventId}`, { 22 | method: 'GET', 23 | headers: { 24 | 'Content-Type': 'application/json', 25 | // Add authorization headers if needed 26 | }, 27 | }); 28 | if (!response.ok) { 29 | throw new Error('Failed to fetch event details'); 30 | } 31 | const data = await response.json(); 32 | return data.event; 33 | }; 34 | -------------------------------------------------------------------------------- /frontend/src/features/Subscription/SubscriptionForm.css: -------------------------------------------------------------------------------- 1 | /* src/features/Subscription/SubscriptionForm.css */ 2 | 3 | .subscription-form { 4 | padding: 20px; 5 | background-color: #f9f9f9; 6 | border-radius: 8px; 7 | box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); 8 | max-width: 400px; 9 | margin: auto; 10 | } 11 | 12 | .subscription-form h2 { 13 | color: #333; 14 | } 15 | 16 | .subscription-form label { 17 | display: block; 18 | margin: 10px 0 5px; 19 | } 20 | 21 | .subscription-form select, 22 | .subscription-form input { 23 | width: 100%; 24 | padding: 10px; 25 | border: 1px solid #ccc; 26 | border-radius: 4px; 27 | margin-bottom: 10px; 28 | } 29 | 30 | .subscription-form button { 31 | background-color: #4CAF50; 32 | color: white; 33 | border: none; 34 | border-radius: 4px; 35 | padding: 10px; 36 | cursor: pointer; 37 | } 38 | 39 | .subscription-form button:hover { 40 | background-color: #45a049; 41 | } 42 | 43 | .error { 44 | color: red; 45 | margin-bottom: 10px; 46 | } 47 | 48 | .success { 49 | color: green; 50 | margin-bottom: 10px; 51 | } 52 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Egyptian Map of Pi Team 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /frontend/src/features/SocialCommerce/ShareButton.js: -------------------------------------------------------------------------------- 1 | // src/features/SocialCommerce/ShareButton.js 2 | 3 | import React from 'react'; 4 | 5 | const ShareButton = ({ post }) => { 6 | const handleShare = () => { 7 | const shareUrl = `https://www.example.com/products/${post.id}`; // Replace with actual product URL 8 | const shareText = `Check out this product: ${post.productName}`; 9 | const shareData = { 10 | title: post.productName, 11 | text: shareText, 12 | url: shareUrl, 13 | }; 14 | 15 | if (navigator.share) { 16 | navigator.share(shareData) 17 | .then(() => console.log('Share successful')) 18 | .catch((error) => console.error('Error sharing:', error)); 19 | } else { 20 | // Fallback for browsers that do not support the Web Share API 21 | alert(`Share this link: ${shareUrl}`); 22 | } 23 | }; 24 | 25 | return ( 26 | 29 | ); 30 | }; 31 | 32 | export default ShareButton; 33 | -------------------------------------------------------------------------------- /src/backend/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 100, 3 | "tabWidth": 2, 4 | "useTabs": false, 5 | "semi": true, 6 | "singleQuote": true, 7 | "quoteProps": "as-needed", 8 | "trailingComma": "es5", 9 | "bracketSpacing": true, 10 | "bracketSameLine": false, 11 | "arrowParens": "always", 12 | "endOfLine": "lf", 13 | "parser": "typescript", 14 | "proseWrap": "preserve", 15 | "htmlWhitespaceSensitivity": "css", 16 | "embeddedLanguageFormatting": "auto", 17 | "overrides": [ 18 | { 19 | "files": "*.{ts,tsx}", 20 | "options": { 21 | "parser": "typescript" 22 | } 23 | }, 24 | { 25 | "files": "*.json", 26 | "options": { 27 | "parser": "json" 28 | } 29 | }, 30 | { 31 | "files": "*.graphql", 32 | "options": { 33 | "parser": "graphql" 34 | } 35 | } 36 | ], 37 | "ignore": [ 38 | "dist", 39 | "node_modules", 40 | "*.generated.ts", 41 | "*.min.js", 42 | "*.d.ts" 43 | ], 44 | "editorconfig": true, 45 | "requireConfig": true, 46 | "vscode": { 47 | "formatOnSave": true, 48 | "packageManager": "npm" 49 | } 50 | } -------------------------------------------------------------------------------- /frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "egyptian-map-of-pi--eiweuo", 3 | "version": "1.0.0", 4 | "private": true, 5 | "scripts": { 6 | "start": "react-scripts start", 7 | "build": "react-scripts build", 8 | "test": "react-scripts test", 9 | "eject": "react-scripts eject" 10 | }, 11 | "dependencies": { 12 | "react": "^17.0.2", 13 | "react-dom": "^17.0.2", 14 | "react-scripts": "4.0.3", 15 | "react-router-dom": "^5.2.0", 16 | "i18next": "^21.6.3", 17 | "react-i18next": "^11.8.5", 18 | "axios": "^0.21.1", 19 | "redux": "^4.1.0", 20 | "react-redux": "^7.2.4", 21 | "styled-components": "^5.3.0" 22 | }, 23 | "devDependencies": { 24 | "eslint": "^7.32.0", 25 | "eslint-plugin-react": "^7.27.1" 26 | }, 27 | "eslintConfig": { 28 | "extends": [ 29 | "react-app", 30 | "react-app/jest" 31 | ] 32 | }, 33 | "browserslist": { 34 | "production": [ 35 | ">0.2%", 36 | "not dead", 37 | "not op_mini all" 38 | ], 39 | "development": [ 40 | "last 1 chrome version", 41 | "last 1 firefox version", 42 | "last 1 safari version" 43 | ] 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /frontend/src/features/MultiLanguage/i18n.js: -------------------------------------------------------------------------------- 1 | // src/features/MultiLanguage/i18n.js 2 | 3 | import i18n from 'i18next'; 4 | import { initReactI18next } from 'react-i18next'; 5 | 6 | const resources = { 7 | en: { 8 | translation: { 9 | welcome: "Welcome to the Egyptian Map of Pi", 10 | // Add more English translations here 11 | }, 12 | }, 13 | ar: { 14 | translation: { 15 | welcome: "مرحبًا بكم في خريطة بي المصرية", 16 | // Add more Arabic translations here 17 | }, 18 | }, 19 | fr: { 20 | translation: { 21 | welcome: "Bienvenue sur la carte égyptienne de Pi", 22 | // Add more French translations here 23 | }, 24 | }, 25 | // Add more languages as needed 26 | }; 27 | 28 | i18n 29 | .use(initReactI18next) // Passes i18n down to react-i18next 30 | .init({ 31 | resources, 32 | lng: "en", // Default language 33 | fallbackLng: "en", // Fallback language 34 | interpolation: { 35 | escapeValue: false, // React already escapes values 36 | }, 37 | }); 38 | 39 | export default i18n; 40 | -------------------------------------------------------------------------------- /frontend/src/features/Recommendations/RecommendationList.css: -------------------------------------------------------------------------------- 1 | /* src/features/Recommendations/RecommendationList.css */ 2 | 3 | .recommendation-list { 4 | padding: 20px; 5 | background-color: #f9f9f9; 6 | border-radius: 8px; 7 | box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); 8 | } 9 | 10 | .recommendation-list h2 { 11 | color: #333; 12 | } 13 | 14 | .recommendation-items { 15 | display: flex; 16 | flex-wrap: wrap; 17 | gap: 20px; 18 | } 19 | 20 | .recommendation-item { 21 | background-color: white; 22 | border: 1px solid #ddd; 23 | border-radius: 8px; 24 | padding: 10px; 25 | text-align: center; 26 | width: 200px; 27 | } 28 | 29 | .recommendation-item img { 30 | max-width: 100%; 31 | border-radius: 4px; 32 | } 33 | 34 | .recommendation-item h3 { 35 | color: #555; 36 | } 37 | 38 | .recommendation-item p { 39 | color: #777; 40 | } 41 | 42 | .recommendation-item button { 43 | background-color: #4CAF50; 44 | color: white; 45 | border: none; 46 | border-radius: 4px; 47 | padding: 5px 10px; 48 | cursor: pointer; 49 | } 50 | 51 | .recommendation-item button:hover { 52 | background-color: #45a049; 53 | } 54 | -------------------------------------------------------------------------------- /frontend/src/features/Reviews/ReviewService.js: -------------------------------------------------------------------------------- 1 | // src/features/Reviews/ReviewService.js 2 | 3 | const API_BASE_URL = '/api/reviews'; // Adjust this to your actual API base URL 4 | 5 | export const fetchReviews = async (productId) => { 6 | const response = await fetch(`${API_BASE_URL}?productId=${productId}`, { 7 | method: 'GET', 8 | headers: { 9 | 'Content-Type': 'application/json', 10 | // Add authorization headers if needed 11 | }, 12 | }); 13 | if (!response.ok) { 14 | throw new Error('Failed to fetch reviews'); 15 | } 16 | const data = await response.json(); 17 | return data.reviews; 18 | }; 19 | 20 | export const submitReview = async ({ productId, content, rating }) => { 21 | const response = await fetch(`${API_BASE_URL}`, { 22 | method: 'POST', 23 | headers: { 24 | 'Content-Type': 'application/json', 25 | // Add authorization headers if needed 26 | }, 27 | body: JSON.stringify({ productId, content, rating }), 28 | }); 29 | if (!response.ok) { 30 | throw new Error('Failed to submit review'); 31 | } 32 | const data = await response.json(); 33 | return data.review; 34 | }; 35 | -------------------------------------------------------------------------------- /frontend/src/features/Sustainability/SustainabilityList.css: -------------------------------------------------------------------------------- 1 | /* src/features/Sustainability/SustainabilityList.css */ 2 | 3 | .sustainability-list { 4 | padding: 20px; 5 | background-color: #f9f9f9; 6 | border-radius: 8px; 7 | box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); 8 | } 9 | 10 | .sustainability-list h2 { 11 | color: #333; 12 | } 13 | 14 | .sustainability-list ul { 15 | list-style-type: none; 16 | padding: 0; 17 | } 18 | 19 | .sustainability-list li { 20 | background-color: white; 21 | border: 1px solid #ddd; 22 | border-radius: 8px; 23 | padding: 15px; 24 | margin-bottom: 15px; 25 | transition: box-shadow 0.3s ease; 26 | } 27 | 28 | .sustainability-list li:hover { 29 | box-shadow: 0 4px 20px rgba(0, 0, 0, 0.2); 30 | } 31 | 32 | .sustainability-list h3 { 33 | color: #555; 34 | margin: 0; 35 | } 36 | 37 | .sustainability-list p { 38 | color: #777; 39 | margin: 5px 0 0; 40 | } 41 | 42 | .sustainability-list button { 43 | background-color: #4CAF50; 44 | color: white; 45 | border: none; 46 | border-radius: 4px; 47 | padding: 10px; 48 | cursor: pointer; 49 | } 50 | 51 | .sustainability-list button:hover { 52 | background-color: #45a049; 53 | } 54 | -------------------------------------------------------------------------------- /src/web/.dockerignore: -------------------------------------------------------------------------------- 1 | .git 2 | .gitignore 3 | 4 | # Dependencies 5 | node_modules 6 | 7 | # Build Outputs 8 | .next 9 | out 10 | coverage 11 | 12 | # Environment & Configuration 13 | .env*.local 14 | pi-network*.json 15 | 16 | # Test Files 17 | tests 18 | cypress 19 | *.test.ts 20 | *.test.tsx 21 | *.spec.ts 22 | *.spec.tsx 23 | 24 | # Documentation 25 | README*.md 26 | 27 | # Development Configurations 28 | .eslintrc* 29 | .prettierrc* 30 | tsconfig*.json 31 | 32 | # Logs 33 | *.log 34 | 35 | # IDE and Editor Files 36 | .idea 37 | .vscode 38 | *.swp 39 | *.swo 40 | .DS_Store 41 | 42 | # Cache Directories 43 | .cache 44 | .npm 45 | .yarn 46 | 47 | # Temporary Files 48 | tmp 49 | temp 50 | *.tmp 51 | 52 | # Development Assets 53 | __mocks__ 54 | __tests__ 55 | .storybook 56 | storybook-static 57 | 58 | # Build Analysis 59 | bundle-analysis 60 | stats.json 61 | 62 | # Development Scripts 63 | scripts 64 | dev-tools 65 | 66 | # Backup Files 67 | *.bak 68 | *.backup 69 | 70 | # Local Development Certificates 71 | *.pem 72 | *.crt 73 | *.key 74 | 75 | # Dependency Lock Files (will be regenerated) 76 | yarn.lock 77 | package-lock.json 78 | pnpm-lock.yaml 79 | 80 | # Miscellaneous 81 | .dockerignore 82 | Dockerfile* 83 | docker-compose* 84 | CHANGELOG.md 85 | CONTRIBUTING.md 86 | LICENSE -------------------------------------------------------------------------------- /src/web/next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | /// 4 | 5 | // NOTE: This file is auto-generated by Next.js 6 | // Version: next@13.0.0 7 | // Do not modify this file manually 8 | 9 | declare global { 10 | namespace NodeJS { 11 | interface ProcessEnv { 12 | // Environment 13 | NEXT_PUBLIC_APP_ENV: 'development' | 'staging' | 'production' 14 | 15 | // API Configuration 16 | NEXT_PUBLIC_API_URL: string 17 | NEXT_PUBLIC_SOCKET_URL: string 18 | NEXT_PUBLIC_CDN_URL: string 19 | 20 | // Map Configuration 21 | NEXT_PUBLIC_MAPBOX_ACCESS_TOKEN: string 22 | NEXT_PUBLIC_MAP_STYLE_URL: string 23 | 24 | // Pi Network Configuration 25 | NEXT_PUBLIC_PI_API_KEY: string 26 | 27 | // App Configuration 28 | NEXT_PUBLIC_DEFAULT_LANGUAGE: 'ar' | 'en' 29 | NEXT_PUBLIC_DEFAULT_THEME: 'light' | 'dark' 30 | } 31 | } 32 | 33 | // Augment JSX namespace for Next.js specific elements 34 | namespace JSX { 35 | interface IntrinsicElements { 36 | // Allow Next.js specific elements in JSX 37 | } 38 | } 39 | } 40 | 41 | // Ensure this is treated as a module 42 | export {} -------------------------------------------------------------------------------- /frontend/src/features/Chatbot/Chatbot.css: -------------------------------------------------------------------------------- 1 | /* src/features/Chatbot/Chatbot.css */ 2 | 3 | .chatbot { 4 | padding: 20px; 5 | background-color: #f9f9f9; 6 | border-radius: 8px; 7 | box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); 8 | max-width: 400px; 9 | margin: auto; 10 | } 11 | 12 | .chat-window { 13 | height: 300px; 14 | overflow-y: auto; 15 | border: 1px solid #ddd; 16 | border-radius: 4px; 17 | padding: 10px; 18 | margin-bottom: 10px; 19 | background-color: white; 20 | } 21 | 22 | .message { 23 | margin: 5px 0; 24 | padding: 8px; 25 | border-radius: 4px; 26 | } 27 | 28 | .message.user { 29 | background-color: #d1e7dd; 30 | text-align: right; 31 | } 32 | 33 | .message.bot { 34 | background-color: #f8d7da; 35 | text-align: left; 36 | } 37 | 38 | .chat-input { 39 | display: flex; 40 | } 41 | 42 | .chat-input input { 43 | flex: 1; 44 | padding: 10px; 45 | border: 1px solid #ccc; 46 | border-radius: 4px; 47 | } 48 | 49 | .chat-input button { 50 | padding: 10px; 51 | border: none; 52 | border-radius: 4px; 53 | background-color: #4CAF50; 54 | color: white; 55 | margin-left: 5px; 56 | cursor: pointer; 57 | } 58 | 59 | .chat-input button:hover { 60 | background-color: #45a049; 61 | } 62 | -------------------------------------------------------------------------------- /frontend/src/features/UserGeneratedContent/UserContentService.js: -------------------------------------------------------------------------------- 1 | // src/features/UserGeneratedContent/UserContentService.js 2 | 3 | const API_BASE_URL = '/api/user-content'; // Adjust this to your actual API base URL 4 | 5 | export const fetchUser Content = async () => { 6 | const response = await fetch(`${API_BASE_URL}`, { 7 | method: 'GET', 8 | headers: { 9 | 'Content-Type': 'application/json', 10 | // Add authorization headers if needed 11 | }, 12 | }); 13 | if (!response.ok) { 14 | throw new Error('Failed to fetch user-generated content'); 15 | } 16 | const data = await response.json(); 17 | return data.content; // Assuming the response contains a content array 18 | }; 19 | 20 | export const submitUser Content = async (content) => { 21 | const response = await fetch(`${API_BASE_URL}/submit`, { 22 | method: 'POST', 23 | headers: { 24 | 'Content-Type': 'application/json', 25 | }, 26 | body: JSON.stringify(content), 27 | }); 28 | 29 | if (!response.ok) { 30 | throw new Error('Failed to submit user-generated content'); 31 | } 32 | 33 | const data = await response.json(); 34 | return data; // Assuming the response contains the submitted content details 35 | }; 36 | -------------------------------------------------------------------------------- /frontend/src/features/UserGeneratedContent/UserContentList.css: -------------------------------------------------------------------------------- 1 | /* src/features/UserGeneratedContent/UserContentList.css */ 2 | 3 | .user-content-list { 4 | padding: 20px; 5 | background-color: #f9f9f9; 6 | border-radius: 8px; 7 | box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); 8 | max-width: 600px; 9 | margin: auto; 10 | } 11 | 12 | .user-content-list h2 { 13 | color: #333; 14 | } 15 | 16 | .user-content-list ul { 17 | list-style-type: none; 18 | padding: 0; 19 | } 20 | 21 | .user-content-list li { 22 | padding: 10px; 23 | border-bottom: 1px solid #ddd; 24 | } 25 | 26 | .user-content-list li h3 { 27 | margin: 0; 28 | color: #007BFF; 29 | } 30 | 31 | .user-content-form { 32 | margin-bottom: 20px; 33 | } 34 | 35 | .user-content-form input, 36 | .user-content-form textarea { 37 | width: 100%; 38 | padding: 10px; 39 | border: 1px solid #ccc; 40 | border-radius: 4px; 41 | margin-bottom: 10px; 42 | } 43 | 44 | .user-content-form button { 45 | background-color: #4CAF50; 46 | color: white; 47 | border: none; 48 | border-radius: 4px; 49 | padding: 10px; 50 | cursor: pointer; 51 | } 52 | 53 | .user-content-form button:hover { 54 | background-color: #45a049; 55 | } 56 | 57 | .error { 58 | color: red; 59 | margin-top: 10px; 60 | } 61 | 62 | .success { 63 | color: green; 64 | margin-top: 10px; 65 | } 66 | -------------------------------------------------------------------------------- /src/web/public/robots.txt: -------------------------------------------------------------------------------- 1 | # Egyptian Map of Pi - Robots.txt Configuration 2 | # Last Updated: 2023 3 | # Review Frequency: Monthly 4 | 5 | # Default rules for all crawlers 6 | User-agent: * 7 | # Allow public marketplace sections 8 | Allow: / 9 | Allow: /categories 10 | Allow: /listings 11 | Allow: /search 12 | 13 | # Protect sensitive endpoints and private data 14 | Disallow: /api/ 15 | Disallow: /messages/ 16 | Disallow: /payments/ 17 | Disallow: /profile/ 18 | Disallow: /*.json$ 19 | Disallow: /admin/ 20 | Disallow: /auth/ 21 | 22 | # Implement rate control for server stability 23 | Crawl-delay: 10 24 | 25 | # Reference to complete sitemap 26 | Sitemap: https://egyptianmapofpi.com/sitemap.xml 27 | 28 | # Block AI training bots 29 | User-agent: GPTBot 30 | Disallow: / 31 | 32 | User-agent: ChatGPT-User 33 | Disallow: / 34 | 35 | User-agent: GoogleBot-Extended 36 | Disallow: / 37 | 38 | User-agent: CCBot 39 | Disallow: / 40 | 41 | # Block potential data harvesting bots 42 | User-agent: PetalBot 43 | Disallow: / 44 | 45 | User-agent: Bytespider 46 | Disallow: / 47 | 48 | # Regional search engine support 49 | User-agent: Arabbot 50 | Allow: / 51 | Allow: /categories 52 | Allow: /listings 53 | Allow: /search 54 | Disallow: /api/ 55 | Disallow: /messages/ 56 | Disallow: /payments/ 57 | Disallow: /profile/ 58 | Disallow: /*.json$ 59 | Disallow: /admin/ 60 | Disallow: /auth/ 61 | Crawl-delay: 5 62 | 63 | # Host-specific directive 64 | Host: egyptianmapofpi.com -------------------------------------------------------------------------------- /frontend/src/features/Events/EventDetail.js: -------------------------------------------------------------------------------- 1 | // src/features/Events/EventDetail.js 2 | 3 | import React, { useEffect, useState } from 'react'; 4 | import { fetchEventDetails } from './EventService'; 5 | import { useParams } from 'react-router-dom'; 6 | import './EventDetail.css'; 7 | 8 | const EventDetail = () => { 9 | const { eventId } = useParams(); 10 | const [event, setEvent] = useState(null); 11 | const [loading, setLoading] = useState(true); 12 | const [error, setError] = useState(null); 13 | 14 | useEffect(() => { 15 | const loadEventDetails = async () => { 16 | try { 17 | const fetchedEvent = await fetchEventDetails(eventId); 18 | setEvent(fetchedEvent); 19 | } catch (err) { 20 | setError('Failed to fetch event details'); 21 | } finally { 22 | setLoading(false); 23 | } 24 | }; 25 | loadEventDetails(); 26 | }, [eventId]); 27 | 28 | if (loading) return
Loading event details...
; 29 | if (error) return
{error}
; 30 | 31 | return ( 32 |
33 |

{event.title}

34 |

Date: {event.date}

35 |

Location: {event.location}

36 |

Description: {event.description}

37 | 38 |
39 | ); 40 | }; 41 | 42 | export default EventDetail; 43 | -------------------------------------------------------------------------------- /frontend/src/routes.js: -------------------------------------------------------------------------------- 1 | // src/routes.js 2 | 3 | import React from 'react'; 4 | import { Route, Switch } from 'react-router-dom'; 5 | import Home from './features/Home/Home'; // Example home component 6 | import EducationalArticle from './features/EducationalContent/EducationalArticle'; 7 | import UserContentList from './features/UserGeneratedContent/UserContentList'; 8 | import DeliveryTracker from './features/Delivery/DeliveryTracker'; 9 | import SubscriptionForm from './features/Subscription/SubscriptionForm'; 10 | import SustainabilityList from './features/Sustainability/SustainabilityList'; 11 | import Chatbot from './features/Chatbot/Chatbot'; 12 | import ARShopping from './features/ARShopping/ARShopping'; 13 | import LoyaltyProgram from './features/LoyaltyProgram/LoyaltyProgram'; 14 | 15 | const routes = ( 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | {/* Add more routes as needed */} 27 | 28 | ); 29 | 30 | export default routes; 31 | -------------------------------------------------------------------------------- /src/web/public/icons/icon-512x512.png: -------------------------------------------------------------------------------- 1 | Dimensions: 512x512 pixels 2 | Format: PNG 3 | MIME type: image/png 4 | Color Profile: sRGB 5 | Purpose: any maskable 6 | 7 | Design Elements: 8 | 1. Primary Color: #1B4D89 (Pi Network Blue) 9 | 2. Secondary Color: #D4AF37 (Egyptian Gold) 10 | 3. Background: #F5F5F5 (Light Gray) 11 | 12 | Key Design Components: 13 | 1. Center Safe Area (409.6x409.6px with 51.2px margin) 14 | 2. Material Design Principles 15 | 3. Egyptian Design Motifs 16 | 4. Pi Network Symbol Integration 17 | 5. RTL-Compatible Layout 18 | 19 | Technical Requirements: 20 | - File size target: < 100KB 21 | - Lossless compression 22 | - High DPI support 23 | - Maskable icon support 24 | - Minimum contrast ratio: 4.5:1 25 | 26 | Usage Contexts: 27 | - PWA installation 28 | - App splash screen 29 | - App store listings 30 | - High-resolution displays 31 | - Marketplace listings 32 | - Social media sharing 33 | 34 | Implementation Notes: 35 | 1. The icon should be created from the SVG source file at src/assets/icons/source/icon-512x512.svg 36 | 2. Export with lossless PNG compression 37 | 3. Verify color accuracy in sRGB color space 38 | 4. Test visibility at multiple sizes (16x16 to 512x512) 39 | 5. Validate maskable icon compliance 40 | 6. Ensure cultural sensitivity in design elements 41 | 42 | Legal Requirements: 43 | © 2024 Egyptian Map of Pi 44 | All rights reserved 45 | Trademark verified 46 | 47 | The icon should be implemented by a professional graphic designer following these exact specifications to create the actual PNG file. -------------------------------------------------------------------------------- /src/web/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | // ES2022 target as specified in requirements for modern JavaScript features 4 | "target": "es2022", 5 | 6 | // Include necessary lib files for web development 7 | "lib": [ 8 | "dom", 9 | "dom.iterable", 10 | "esnext" 11 | ], 12 | 13 | // Module configuration 14 | "module": "esnext", 15 | "moduleResolution": "node", 16 | "resolveJsonModule": true, 17 | "isolatedModules": true, 18 | "esModuleInterop": true, 19 | 20 | // React configuration 21 | "jsx": "preserve", 22 | 23 | // Strict type checking 24 | "strict": true, 25 | "forceConsistentCasingInFileNames": true, 26 | "skipLibCheck": true, 27 | 28 | // Build configuration 29 | "noEmit": true, 30 | "incremental": true, 31 | "allowJs": true, 32 | 33 | // Path aliases for cleaner imports 34 | "baseUrl": ".", 35 | "paths": { 36 | "@/*": ["src/*"] 37 | }, 38 | 39 | // Type definitions 40 | "types": [ 41 | "node", 42 | "jest", 43 | "react", 44 | "react-dom" 45 | ] 46 | }, 47 | 48 | // Files to include in compilation 49 | "include": [ 50 | "next-env.d.ts", 51 | "src/types/environment.d.ts", 52 | "src/**/*.ts", 53 | "src/**/*.tsx" 54 | ], 55 | 56 | // Files to exclude from compilation 57 | "exclude": [ 58 | "node_modules", 59 | ".next", 60 | "out", 61 | "coverage", 62 | "**/*.test.ts", 63 | "**/*.test.tsx" 64 | ] 65 | } -------------------------------------------------------------------------------- /frontend/src/features/SocialCommerce/SocialFeed.js: -------------------------------------------------------------------------------- 1 | // src/features/SocialCommerce/SocialFeed.js 2 | 3 | import React, { useEffect, useState } from 'react'; 4 | import { fetchSocialPosts } from './SocialService'; 5 | import ShareButton from './ShareButton'; 6 | import './SocialFeed.css'; 7 | 8 | const SocialFeed = () => { 9 | const [posts, setPosts] = useState([]); 10 | const [loading, setLoading] = useState(true); 11 | const [error, setError] = useState(null); 12 | 13 | useEffect(() => { 14 | const loadPosts = async () => { 15 | try { 16 | const fetchedPosts = await fetchSocialPosts(); 17 | setPosts(fetchedPosts); 18 | } catch (err) { 19 | setError('Failed to fetch social posts'); 20 | } finally { 21 | setLoading(false); 22 | } 23 | }; 24 | loadPosts(); 25 | }, []); 26 | 27 | if (loading) return
Loading...
; 28 | if (error) return
{error}
; 29 | 30 | return ( 31 |
32 |

Social Commerce Feed

33 | {posts.map((post) => ( 34 |
35 | {post.productName} 36 |

{post.productName}

37 |

{post.description}

38 | 39 |
40 | ))} 41 |
42 | ); 43 | }; 44 | 45 | export default SocialFeed; 46 | -------------------------------------------------------------------------------- /src/web/public/icons/icon-72x72.png: -------------------------------------------------------------------------------- 1 | Image Specifications: 2 | - Dimensions: 72x72 pixels 3 | - Format: PNG with transparency 4 | - Color Depth: 32-bit 5 | - Max File Size: 5KB 6 | - Purpose: any maskable 7 | 8 | Design Elements: 9 | 1. Base Shape: 10 | - Material Design square with 12px rounded corners 11 | - Primary color: #1B4D89 (Egyptian Map of Pi brand blue) 12 | - Background: #F5F5F5 with transparency support 13 | 14 | 2. Icon Design: 15 | - Centered "π" symbol in modern geometric style 16 | - Egyptian cultural elements: 17 | - Subtle pyramid silhouette overlay 18 | - Hieroglyphic-inspired decorative border 19 | - 8px minimum padding from edges 20 | - High contrast for visibility 21 | - Optimized for small size display 22 | 23 | 3. Technical Optimizations: 24 | - Lossless PNG compression 25 | - Web-safe color palette 26 | - Essential PWA metadata preserved 27 | - Maskable icon support 28 | - Dark mode compatible 29 | 30 | 4. Accessibility Features: 31 | - High contrast ratio > 4.5:1 32 | - Color-blind friendly design 33 | - Recognizable at 72px size 34 | - Clear silhouette for adaptive icons 35 | 36 | Browser Support: 37 | - Pi Browser (latest): Maskable support 38 | - Chrome Mobile 80+: Adaptive icon 39 | - Safari iOS 12+: Retina optimized 40 | - Firefox Mobile 95+: Standard support 41 | - Opera Mobile 60+: Standard support 42 | 43 | Performance: 44 | - Load time < 100ms 45 | - Cache-first strategy 46 | - 30-day cache duration 47 | - Compressed size < 5KB 48 | 49 | [Note: The actual binary image file would be created according to these specifications using appropriate image creation tools] -------------------------------------------------------------------------------- /frontend/src/features/LoyaltyProgram/LoyaltyService.js: -------------------------------------------------------------------------------- 1 | // src/features/LoyaltyProgram/LoyaltyService.js 2 | 3 | const API_BASE_URL = '/api/loyalty'; // Adjust this to your actual API base URL 4 | 5 | export const getLoyaltyPoints = async () => { 6 | const response = await fetch(`${API_BASE_URL}/points`, { 7 | method: 'GET', 8 | headers: { 9 | 'Content-Type': 'application/json', 10 | // Add authorization headers if needed 11 | }, 12 | }); 13 | if (!response.ok) { 14 | throw new Error('Failed to fetch loyalty points'); 15 | } 16 | const data = await response.json(); 17 | return data.points; 18 | }; 19 | 20 | export const getRewards = async () => { 21 | const response = await fetch(`${API_BASE_URL}/rewards`, { 22 | method: 'GET', 23 | headers: { 24 | 'Content-Type': 'application/json', 25 | // Add authorization headers if needed 26 | }, 27 | }); 28 | if (!response.ok) { 29 | throw new Error('Failed to fetch rewards'); 30 | } 31 | const data = await response.json(); 32 | return data.rewards; 33 | }; 34 | 35 | export const redeemReward = async (rewardId) => { 36 | const response = await fetch(`${API_BASE_URL}/redeem`, { 37 | method: 'POST', 38 | headers: { 39 | 'Content-Type': 'application/json', 40 | // Add authorization headers if needed 41 | }, 42 | body: JSON.stringify({ rewardId }), 43 | }); 44 | if (!response.ok) { 45 | throw new Error('Failed to redeem reward'); 46 | } 47 | return await response.json(); 48 | }; 49 | -------------------------------------------------------------------------------- /src/backend/payment-service/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | // Root directories and output configuration 5 | "rootDir": "./src", 6 | "outDir": "./dist", 7 | "baseUrl": "./src", 8 | 9 | // Strict type checking for payment processing security 10 | "strict": true, 11 | "noImplicitAny": true, 12 | "strictNullChecks": true, 13 | "strictFunctionTypes": true, 14 | "strictBindCallApply": true, 15 | "strictPropertyInitialization": true, 16 | "noImplicitThis": true, 17 | "alwaysStrict": true, 18 | 19 | // Path aliases for payment service modules 20 | "paths": { 21 | "@interfaces/*": ["interfaces/*"], 22 | "@config/*": ["config/*"], 23 | "@models/*": ["models/*"], 24 | "@services/*": ["services/*"], 25 | "@controllers/*": ["controllers/*"], 26 | "@utils/*": ["utils/*"], 27 | "@shared/*": ["../../shared/*"] 28 | }, 29 | 30 | // Types and module resolution 31 | "types": ["node", "jest"], 32 | "moduleResolution": "node", 33 | "esModuleInterop": true, 34 | "resolveJsonModule": true, 35 | "sourceMap": true, 36 | "declaration": true 37 | }, 38 | 39 | // Project references 40 | "references": [ 41 | { 42 | "path": "../shared" 43 | } 44 | ], 45 | 46 | // Source files 47 | "include": [ 48 | "src/**/*.ts", 49 | "src/**/*.json" 50 | ], 51 | "exclude": [ 52 | "node_modules", 53 | "dist", 54 | "coverage", 55 | "**/*.test.ts", 56 | "**/*.spec.ts" 57 | ], 58 | 59 | // ts-node configuration for development 60 | "ts-node": { 61 | "transpileOnly": true, 62 | "files": true 63 | } 64 | } -------------------------------------------------------------------------------- /src/web/public/favicon.ico: -------------------------------------------------------------------------------- 1 | Multi-resolution ICO file containing 3 sizes: 2 | - 16x16 pixels 3 | - 32x32 pixels 4 | - 48x48 pixels 5 | 6 | Design Elements: 7 | 1. Base Icon: 8 | - Pi Network symbol (π) as the central element 9 | - Primary color: #1B4D89 (Pi Network blue) 10 | - Background color: #F5F5F5 (Light gray) 11 | 12 | 2. Cultural Elements: 13 | - Egyptian hieroglyphic-inspired decorative border 14 | - Subtle integration that maintains clarity at small sizes 15 | - Border elements simplified at 16x16 size 16 | 17 | 3. Material Design Features: 18 | - Subtle shadow depth for elevation effect 19 | - Crisp, defined boundaries 20 | - Flat design principles with minimal gradients 21 | - High contrast for visibility 22 | 23 | Technical Requirements: 24 | - Format: 32-bit RGBA ICO 25 | - Optimization: Size-specific detail levels 26 | - High-DPI support for modern displays 27 | - Clear rendering at all specified sizes 28 | - Cache-Control header: public, max-age=604800 29 | 30 | Size-Specific Optimizations: 31 | 16x16: 32 | - Simplified design 33 | - Enhanced edges 34 | - Basic Pi symbol only 35 | - Minimal cultural elements 36 | 37 | 32x32: 38 | - Balanced detail 39 | - Clear border elements 40 | - Full Pi symbol 41 | - Basic cultural accents 42 | 43 | 48x48: 44 | - Full detail 45 | - Complete cultural elements 46 | - Rich shadow depth 47 | - Maximum clarity 48 | 49 | The favicon should be created using professional image editing software that supports ICO format with multiple resolutions. The file should be optimized for web use while maintaining visual quality. 50 | 51 | Note: This is a binary file format and the actual implementation requires image creation in graphics software rather than code generation. -------------------------------------------------------------------------------- /frontend/src/features/ARShopping/ARShopping.js: -------------------------------------------------------------------------------- 1 | // src/features/ARShopping/ARShopping.js 2 | 3 | import React, { useEffect, useState } from 'react'; 4 | import { fetchProducts } from './ARService'; 5 | import ARViewer from './ARViewer'; 6 | import './ARShopping.css'; 7 | 8 | const ARShopping = () => { 9 | const [products, setProducts] = useState([]); 10 | const [selectedProduct, setSelectedProduct] = useState(null); 11 | const [showAR, setShowAR] = useState(false); 12 | 13 | useEffect(() => { 14 | const loadProducts = async () => { 15 | const productList = await fetchProducts(); 16 | setProducts(productList); 17 | }; 18 | loadProducts(); 19 | }, []); 20 | 21 | const handleARLaunch = (product) => { 22 | setSelectedProduct(product); 23 | setShowAR(true); 24 | }; 25 | 26 | const handleCloseAR = () => { 27 | setShowAR(false); 28 | setSelectedProduct(null); 29 | }; 30 | 31 | return ( 32 |
33 |

Augmented Reality Shopping

34 |
35 | {products.map((product) => ( 36 |
37 | {product.name} 38 |

{product.name}

39 | 40 |
41 | ))} 42 |
43 | {showAR && } 44 |
45 | ); 46 | }; 47 | 48 | export default ARShopping; 49 | -------------------------------------------------------------------------------- /src/backend/location-service/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "rootDir": "./src", 5 | "outDir": "./dist", 6 | "composite": true, 7 | "declaration": true, 8 | "sourceMap": true, 9 | "strict": true, 10 | "esModuleInterop": true, 11 | "skipLibCheck": true, 12 | "forceConsistentCasingInFileNames": true, 13 | "moduleResolution": "node", 14 | "target": "es2022", 15 | "module": "commonjs", 16 | "lib": [ 17 | "es2022", 18 | "dom" 19 | ], 20 | "baseUrl": ".", 21 | "paths": { 22 | "@shared/*": ["../shared/*"], 23 | "@models/*": ["src/models/*"], 24 | "@config/*": ["src/config/*"], 25 | "@controllers/*": ["src/controllers/*"], 26 | "@services/*": ["src/services/*"], 27 | "@utils/*": ["src/utils/*"], 28 | "@interfaces/*": ["src/interfaces/*"], 29 | "@geospatial/*": ["src/geospatial/*"] 30 | } 31 | }, 32 | "include": [ 33 | "src/**/*.ts", 34 | "src/**/*.json" 35 | ], 36 | "exclude": [ 37 | "node_modules", 38 | "dist", 39 | "coverage", 40 | "**/*.test.ts", 41 | "**/*.spec.ts" 42 | ], 43 | "references": [ 44 | { 45 | "path": "../shared" 46 | } 47 | ], 48 | "ts-node": { 49 | "transpileOnly": true, 50 | "files": true, 51 | "compilerOptions": { 52 | "module": "commonjs" 53 | } 54 | }, 55 | "watchOptions": { 56 | "watchFile": "useFsEvents", 57 | "watchDirectory": "useFsEvents", 58 | "fallbackPolling": "dynamicPriority", 59 | "synchronousWatchDirectory": true, 60 | "excludeDirectories": [ 61 | "**/node_modules", 62 | "**/dist", 63 | "**/coverage" 64 | ] 65 | } 66 | } -------------------------------------------------------------------------------- /frontend/src/features/Events/EventList.js: -------------------------------------------------------------------------------- 1 | // src/features/Events/EventList.js 2 | 3 | import React, { useEffect, useState } from 'react'; 4 | import { fetchEvents } from './EventService'; 5 | import { Link } from 'react-router-dom'; 6 | import './EventList.css'; 7 | 8 | const EventList = () => { 9 | const [events, setEvents] = useState([]); 10 | const [loading, setLoading] = useState(true); 11 | const [error, setError] = useState(null); 12 | 13 | useEffect(() => { 14 | const loadEvents = async () => { 15 | try { 16 | const fetchedEvents = await fetchEvents(); 17 | setEvents(fetchedEvents); 18 | } catch (err) { 19 | setError('Failed to fetch events'); 20 | } finally { 21 | setLoading(false); 22 | } 23 | }; 24 | loadEvents(); 25 | }, []); 26 | 27 | if (loading) return
Loading events...
; 28 | if (error) return
{error}
; 29 | 30 | return ( 31 |
32 |

Upcoming Events

33 | {events.length === 0 ? ( 34 |

No upcoming events.

35 | ) : ( 36 |
    37 | {events.map((event) => ( 38 |
  • 39 | 40 |

    {event.title}

    41 |

    {event.date}

    42 | 43 |
  • 44 | ))} 45 |
46 | )} 47 |
48 | ); 49 | }; 50 | 51 | export default EventList; 52 | -------------------------------------------------------------------------------- /frontend/src/features/ARShopping/ARShopping.css: -------------------------------------------------------------------------------- 1 | /* src/features/ARShopping/ARShopping.css */ 2 | 3 | .ar-shopping { 4 | padding: 20px; 5 | background-color: #f ```css 6 | /* src/features/ARShopping/ARShopping.css */ 7 | 8 | .ar-shopping { 9 | padding: 20px; 10 | background-color: #f9f9f9; 11 | border-radius: 8px; 12 | box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); 13 | } 14 | 15 | .ar-shopping h2 { 16 | color: #333; 17 | } 18 | 19 | .product-list { 20 | display: flex; 21 | flex-wrap: wrap; 22 | gap: 20px; 23 | } 24 | 25 | .product-item { 26 | background-color: white; 27 | border: 1px solid #ddd; 28 | border-radius: 8px; 29 | padding: 10px; 30 | text-align: center; 31 | width: 200px; 32 | } 33 | 34 | .product-item img { 35 | max-width: 100%; 36 | border-radius: 4px; 37 | } 38 | 39 | .product-item button { 40 | background-color: #4CAF50; 41 | color: white; 42 | border: none; 43 | border-radius: 4px; 44 | padding: 5px 10px; 45 | cursor: pointer; 46 | } 47 | 48 | .product-item button:hover { 49 | background-color: #45a049; 50 | } 51 | 52 | .ar-viewer { 53 | position: fixed; 54 | top: 0; 55 | left: 0; 56 | width: 100%; 57 | height: 100%; 58 | background-color: rgba(0, 0, 0, 0.8); 59 | display: flex; 60 | justify-content: center; 61 | align-items: center; 62 | z-index: 1000; 63 | } 64 | 65 | .close-button { 66 | position: absolute; 67 | top: 20px; 68 | right: 20px; 69 | background-color: #ff4d4d; 70 | color: white; 71 | border: none; 72 | border-radius: 4px; 73 | padding: 10px; 74 | cursor: pointer; 75 | } 76 | 77 | .close-button:hover { 78 | background-color: #ff1a1a; 79 | } 80 | -------------------------------------------------------------------------------- /src/web/public/icons/icon-192x192.png: -------------------------------------------------------------------------------- 1 | Format: PNG (image/png) 2 | Dimensions: 192x192 pixels 3 | Color Profile: sRGB 4 | Bit Depth: 32-bit (with alpha channel) 5 | Maximum File Size: 32KB 6 | 7 | Design Specifications: 8 | 1. Layout: 9 | - Safe Zone: 77px centered square (40% of total dimensions) 10 | - Internal Padding: 16px on all sides 11 | - Background: #F5F5F5 (light gray) 12 | - Primary Color: #1B4D89 (deep blue) 13 | 14 | 2. Design Elements: 15 | - Primary Icon: Stylized map marker incorporating Pi symbol 16 | - Egyptian Elements: Subtle hieroglyphic-inspired decorative elements 17 | - Material Design: Flat design with subtle elevation shadows 18 | - Maskable Support: All critical elements within safe zone 19 | 20 | 3. Technical Requirements: 21 | - Transparent background for flexible platform display 22 | - Anti-aliased edges for crisp rendering 23 | - Optimized paths for pixel-perfect display 24 | - High-DPI support for retina displays 25 | 26 | 4. Platform-Specific Considerations: 27 | - Android: Maskable icon format support 28 | - Chrome Web Store: Optimized for store listing 29 | - Pi Browser: Enhanced visibility in platform context 30 | - PWA: Standard compliant for home screen display 31 | 32 | 5. Optimization Guidelines: 33 | - PNG compression: Optimized for size/quality balance 34 | - Path optimization: Simplified vectors for clean scaling 35 | - Color optimization: Limited palette for file size reduction 36 | - Edge preservation: Maintain crispness after compression 37 | 38 | Implementation Notes: 39 | - Export with PNG-8 format where possible for size optimization 40 | - Use indexed color palette to reduce file size 41 | - Implement proper gamma correction for cross-platform display 42 | - Include metadata for PWA manifest compatibility -------------------------------------------------------------------------------- /src/backend/api-gateway/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@egyptian-map-pi/api-gateway", 3 | "version": "1.0.0", 4 | "private": true, 5 | "engines": { 6 | "node": ">=18.0.0", 7 | "npm": "9.8.0" 8 | }, 9 | "scripts": { 10 | "build": "tsc", 11 | "start": "node dist/app.js", 12 | "dev": "nodemon src/app.ts", 13 | "test": "jest", 14 | "test:coverage": "jest --coverage", 15 | "lint": "eslint . --ext .ts", 16 | "lint:fix": "eslint . --ext .ts --fix", 17 | "clean": "rimraf dist coverage" 18 | }, 19 | "dependencies": { 20 | "@egyptian-map-pi/shared": "^1.0.0", 21 | "@pinetwork-js/sdk": "^2.0.0", 22 | "axios": "^1.5.0", 23 | "compression": "^1.7.4", 24 | "cors": "^2.8.5", 25 | "dotenv": "^16.3.1", 26 | "express": "4.18.2", 27 | "express-rate-limit": "^6.9.0", 28 | "express-validator": "^7.0.1", 29 | "helmet": "^7.0.0", 30 | "http-proxy-middleware": "2.0.6", 31 | "jsonwebtoken": "^9.0.1", 32 | "morgan": "^1.10.0", 33 | "winston": "^3.10.0", 34 | "winston-daily-rotate-file": "4.7.1" 35 | }, 36 | "devDependencies": { 37 | "@types/express": "^4.17.17", 38 | "@types/jest": "29.5.3", 39 | "@types/node": "^18.0.0", 40 | "@typescript-eslint/eslint-plugin": "6.2.1", 41 | "@typescript-eslint/parser": "6.2.1", 42 | "eslint": "8.46.0", 43 | "eslint-config-prettier": "8.10.0", 44 | "eslint-plugin-import": "2.28.1", 45 | "eslint-plugin-jest": "27.2.3", 46 | "jest": "^29.0.0", 47 | "nodemon": "3.0.1", 48 | "prettier": "^3.0.0", 49 | "rimraf": "5.0.1", 50 | "ts-jest": "29.1.1", 51 | "ts-node": "10.9.1", 52 | "typescript": "5.1.6" 53 | }, 54 | "author": "Egyptian Map of Pi Team", 55 | "license": "MIT" 56 | } -------------------------------------------------------------------------------- /src/web/public/icons/icon-96x96.png: -------------------------------------------------------------------------------- 1 | Image Specifications: 2 | - Dimensions: 96x96 pixels 3 | - Format: PNG with transparency (32-bit with alpha channel) 4 | - File size: Optimized to <5KB 5 | - Color scheme: 6 | - Background: #F5F5F5 7 | - Theme color: #1B4D89 8 | - Color space: sRGB 9 | - Minimum contrast ratio: 4.5:1 10 | 11 | Design Elements: 12 | 1. Core Shape: 13 | - Circular base shape (80% of total width/height) 14 | - Material Design 3.0 elevation and shadow guidelines 15 | - 40% padding for maskable icon safe zone 16 | 17 | 2. Icon Elements: 18 | - Stylized "π" symbol in theme color #1B4D89 19 | - Egyptian pyramid silhouette overlay 20 | - Location marker integration 21 | - Material Design icon grid alignment 22 | 23 | 3. Safe Zone Implementation: 24 | - Primary content within 57.6x57.6 pixel central area 25 | - Edge padding following maskable icon guidelines 26 | - Pixel-perfect alignment at target resolution 27 | 28 | 4. Cultural Elements: 29 | - Egyptian architectural motifs 30 | - Modern minimalist interpretation 31 | - Balanced visual hierarchy 32 | 33 | Technical Implementation: 34 | 1. Image Optimization: 35 | - PNG compression with alpha channel 36 | - Optimized for <5KB file size 37 | - Pixel-perfect rendering at 96x96 38 | 39 | 2. Metadata: 40 | - Proper PNG chunks for web delivery 41 | - Color profile: sRGB 42 | - Transparency: Enabled 43 | 44 | 3. Cache Headers: 45 | Cache-Control: public, max-age=31536000, immutable 46 | Content-Type: image/png 47 | ETag: [Generated hash] 48 | 49 | Browser Support: 50 | - Pi Browser (latest): Full support 51 | - Chrome Mobile (80+): Maskable icon support 52 | - Safari iOS (12+): Standard icon support 53 | - Firefox Mobile (95+): Full maskable support 54 | - Opera Mobile (60+): Standard support -------------------------------------------------------------------------------- /frontend/src/features/Reviews/ReviewList.js: -------------------------------------------------------------------------------- 1 | // src/features/Reviews/ReviewList.js 2 | 3 | import React, { useEffect, useState } from 'react'; 4 | import { fetchReviews } from './ReviewService'; 5 | import ReviewForm from './ReviewForm'; 6 | import './ReviewList.css'; 7 | 8 | const ReviewList = ({ productId }) => { 9 | const [reviews, setReviews] = useState([]); 10 | const [loading, setLoading] = useState(true); 11 | const [error, setError] = useState(null); 12 | 13 | useEffect(() => { 14 | const loadReviews = async () => { 15 | try { 16 | const fetchedReviews = await fetchReviews(productId); 17 | setReviews(fetchedReviews); 18 | } catch (err) { 19 | setError('Failed to fetch reviews'); 20 | } finally { 21 | setLoading(false); 22 | } 23 | }; 24 | loadReviews(); 25 | }, [productId]); 26 | 27 | if (loading) return
Loading reviews...
; 28 | if (error) return
{error}
; 29 | 30 | return ( 31 |
32 |

Reviews

33 | 34 | {reviews.length === 0 ? ( 35 |

No reviews yet.

36 | ) : ( 37 | reviews.map((review) => ( 38 |
39 |

{review.author}

40 |

{review.content}

41 |

Rating: {review.rating} ⭐

42 |
43 | )) 44 | )} 45 |
46 | ); 47 | }; 48 | 49 | export default ReviewList; 50 | -------------------------------------------------------------------------------- /infrastructure/terraform/modules/cdn/outputs.tf: -------------------------------------------------------------------------------- 1 | # Output definitions for CloudFront CDN module 2 | # Version: 1.0 3 | # Provider compatibility: hashicorp/terraform ~> 1.5 4 | 5 | # CloudFront distribution ID output 6 | output "distribution_id" { 7 | description = "The ID of the CloudFront distribution for the Egyptian Map of Pi CDN" 8 | value = aws_cloudfront_distribution.main.id 9 | } 10 | 11 | # CloudFront distribution domain name output 12 | output "distribution_domain_name" { 13 | description = "The domain name of the CloudFront distribution for content delivery in Egypt" 14 | value = aws_cloudfront_distribution.main.domain_name 15 | } 16 | 17 | # CloudFront distribution hosted zone ID output 18 | output "distribution_hosted_zone_id" { 19 | description = "The Route 53 hosted zone ID for the CloudFront distribution enabling geolocation routing" 20 | value = aws_cloudfront_distribution.main.hosted_zone_id 21 | } 22 | 23 | # CloudFront Origin Access Identity path output 24 | output "origin_access_identity_path" { 25 | description = "The path for the CloudFront Origin Access Identity used in S3 bucket policies" 26 | value = aws_cloudfront_origin_access_identity.main.cloudfront_access_identity_path 27 | } 28 | 29 | # CloudFront distribution deployment status output 30 | output "distribution_status" { 31 | description = "The current status of the CloudFront distribution deployment" 32 | value = aws_cloudfront_distribution.main.status 33 | } 34 | 35 | # CloudFront Origin Access Identity IAM ARN output 36 | output "origin_access_identity_iam_arn" { 37 | description = "The IAM ARN of the Origin Access Identity for S3 bucket policy configuration" 38 | value = aws_cloudfront_origin_access_identity.main.iam_arn 39 | } -------------------------------------------------------------------------------- /frontend/src/features/ARShopping/ARViewer.js: -------------------------------------------------------------------------------- 1 | // src/features/ARShopping/ARViewer.js 2 | 3 | import React, { useEffect } from 'react'; 4 | import * as THREE from 'three'; 5 | import { ARButton } from 'three/examples/jsm/webxr/ARButton'; 6 | import './ARViewer.css'; 7 | 8 | const ARViewer = ({ product, onClose }) => { 9 | useEffect(() => { 10 | const scene = new THREE.Scene(); 11 | const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); 12 | const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true }); 13 | renderer.setSize(window.innerWidth, window.innerHeight); 14 | document.body.appendChild(renderer.domElement); 15 | document.body.appendChild(ARButton.createButton(renderer)); 16 | 17 | const geometry = new THREE.BoxGeometry(1, 1, 1); // Placeholder for product model 18 | const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 }); 19 | const cube = new THREE.Mesh(geometry, material); 20 | scene.add(cube); 21 | 22 | camera.position.z = 5; 23 | 24 | const animate = function () { 25 | requestAnimationFrame(animate); 26 | cube.rotation.x += 0.01; 27 | cube.rotation.y += 0.01; 28 | renderer.render(scene, camera); 29 | }; 30 | 31 | animate(); 32 | 33 | return () => { 34 | document.body.removeChild(renderer.domElement); 35 | }; 36 | }, [product]); 37 | 38 | return ( 39 |
40 | 41 | {/* AR content will be rendered here */} 42 |
43 | ); 44 | }; 45 | 46 | export default ARViewer; 47 | -------------------------------------------------------------------------------- /frontend/src/features/Reviews/ReviewForm.js: -------------------------------------------------------------------------------- 1 | // src/features/Reviews/ReviewForm.js 2 | 3 | import React, { useState } from 'react'; 4 | import { submitReview } from './ReviewService'; 5 | import './ReviewForm.css'; 6 | 7 | const ReviewForm = ({ productId, onReviewAdded }) => { 8 | const [content, setContent] = useState(''); 9 | const [rating, setRating] = useState(5); 10 | const [error, setError] = useState(null); 11 | 12 | const handleSubmit = async (e) => { 13 | e.preventDefault(); 14 | try { 15 | const newReview = await submitReview({ productId, content, rating }); 16 | onReviewAdded((prevReviews) => [...prevReviews, newReview]); 17 | setContent(''); 18 | setRating(5); 19 | } catch (err) { 20 | setError('Failed to submit review'); 21 | } 22 | }; 23 | 24 | return ( 25 |
26 |

Submit a Review

27 | {error &&
{error}
} 28 |