diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 347e748..8fcb7ce 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -1,17 +1,95 @@ -name: Deploy to GitHub Pages +name: CI on: + pull_request: + branches: + - main push: branches: - main -permissions: - contents: write - jobs: - build-and-deploy: + lint: + name: Lint Code + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: npm + + - name: Install dependencies + run: npm ci + + - name: Run linter + run: npm run lint + + unit-tests: + name: Unit Tests runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: npm + + - name: Install dependencies + run: npm ci + + - name: Run unit tests + run: npm run test:run + + e2e-tests: + name: E2E Tests + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: npm + + - name: Install dependencies + run: npm ci + + - name: Install Playwright Browsers + run: npx playwright install --with-deps + + - name: Build site + env: + NODE_OPTIONS: --max_old_space_size=4096 + run: npm run build + + - name: Run E2E tests + run: npm run test:e2e + + - name: Upload test results + if: failure() + continue-on-error: true + uses: actions/upload-artifact@v4 + with: + name: playwright-report + path: playwright-report/ + retention-days: 7 + + build: + name: Build Check + runs-on: ubuntu-latest + steps: - name: Checkout uses: actions/checkout@v4 @@ -30,11 +108,10 @@ jobs: NODE_OPTIONS: --max_old_space_size=4096 run: npm run build - - name: Deploy to gh-pages - uses: JamesIves/github-pages-deploy-action@v4 + - name: Upload build artifacts + continue-on-error: true + uses: actions/upload-artifact@v4 with: - branch: gh-pages - folder: dist - clean: true - clean-exclude: | - pr-preview/ + name: build-output + path: dist/ + retention-days: 1 \ No newline at end of file diff --git a/README.md b/README.md index d31ce2f..2909ee1 100644 --- a/README.md +++ b/README.md @@ -2,15 +2,15 @@ A modern, responsive community platform built with React 19 and Vite, featuring comprehensive testing, cross-browser compatibility, and enterprise-grade security. -## โจ Features +## Features -- ๐ **Responsive Design** โ Mobile-first layout with smooth in-page navigation -- ๐งช **Automated Testing** โ Unit and Playwright coverage for critical journeys -- ๐ฑ **Cross-Browser Support** โ Chrome, Firefox, Safari (desktop + mobile) -- โก **Modern Stack** โ React 19, Vite, Playwright, and Vitest -- ๐ก๏ธ **Built-In Security** โ Strict Content Security Policy and lazy loading for heavy sections +- Responsive Design โ Mobile-first layout with smooth in-page navigation +- Automated Testing โ Unit and Playwright coverage for critical journeys +- Cross-Browser Support โ Chrome, Firefox, Safari (desktop + mobile) +- Modern Stack โ React 19, Vite, Playwright, and Vitest +- Built-In Security โ Strict Content Security Policy and lazy loading for heavy sections -## ๐ Quick Start +## Quick Start ### Prerequisites - Node.js 18+ @@ -32,8 +32,7 @@ npm run dev ### Environment Variables None required for local development. -## ๐๏ธ Project Structure - +## Project Structure ``` zatech-website/ โโโ public/ # Static assets served directly @@ -58,7 +57,7 @@ zatech-website/ โโโ README.md # This file ``` -## ๐ง Development +## Development ### Available Scripts ```bash @@ -90,22 +89,22 @@ npm run dev # - Rate limiting status ``` -## ๐งช Testing Cheat Sheet +## Testing Cheat Sheet ### Quick Test Commands ```bash -# ๐ FULL TEST SUITE (Run this before commits) +# FULL TEST SUITE (Run this before commits) npm run test:run && npm run test:e2e && npm run lint && npm audit -# ๐โโ๏ธ QUICK DEV CHECKS (During development) +# QUICK DEV CHECKS (During development) npm run test:run # Unit tests only (fast ~1-2 seconds) npm run lint # Code quality check (~1 second) npm run dev # Start dev server -# ๐ CROSS-BROWSER TESTING (Before releases) +# CROSS-BROWSER TESTING (Before releases) npm run test:e2e # Full browser compatibility (~10-30 seconds) -# ๐ SECURITY CHECK +# SECURITY CHECK npm audit # Check for vulnerabilities ``` @@ -115,7 +114,7 @@ npm audit # Check for vulnerabilities | **Add new component** | `npm run test:run` | Verify existing tests still pass | | **Change existing code** | `npm run test:run` | Check for regressions | | **Add new CSS/styles** | `npm run lint` | Catch style issues early | -| **Before committing** | Full test suite โฌ๏ธ | Ensure nothing is broken | +| **Before committing** | Full test suite | Ensure nothing is broken | | **Add new dependencies** | `npm audit` | Security check | | **Test mobile/responsive** | `npm run dev -- --host 0.0.0.0` | Test on phone | | **Before deployment** | `npm run test:e2e` | Cross-browser verification | @@ -147,7 +146,7 @@ npm run dev -- --host 0.0.0.0 # (Check terminal output for exact IP address) ``` -## ๐ก๏ธ Security & Quality +## Security & Quality ### Security Features - **Content Security Policy (CSP)**: Browser-level guardrails for third-party content @@ -167,7 +166,7 @@ Configured via `.browserslistrc`: - iOS Safari 14+, Android Chrome 88+ - Modern JavaScript features with graceful degradation -## ๐ค Contributing +## Contributing 1. Fork the repository 2. Create a feature branch (`git checkout -b feature/amazing-feature`) @@ -184,23 +183,23 @@ Configured via `.browserslistrc`: - Update documentation for significant changes - Follow security patterns established in the codebase -## ๐ Technical Achievements +## Technical Achievements This project demonstrates production-grade development practices: -- โ **Modern React Architecture** - Hooks, components, routing -- โ **Comprehensive Testing** - Unit, integration, E2E, cross-browser -- โ **Security First** - Multiple layers of protection -- โ **Performance Optimized** - Fast builds, optimized bundles -- โ **Mobile Ready** - Responsive design, touch-friendly -- โ **Developer Experience** - Hot reload, linting, type safety -- โ **Production Ready** - Build optimization, error handling +- Modern React Architecture - Hooks, components, routing +- Comprehensive Testing - Unit, integration, E2E, cross-browser +- Security First - Multiple layers of protection +- Performance Optimized - Fast builds, optimized bundles +- Mobile Ready - Responsive design, touch-friendly +- Developer Experience - Hot reload, linting, type safety +- Production Ready - Build optimization, error handling -## ๐ License +## License This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. -## ๐ Support & Resources +## Support & Resources - **Documentation**: This README covers all major aspects - **Issues**: Report bugs via [GitHub Issues](https://github.com/Accompany-VC/zatech-website/issues) @@ -209,4 +208,4 @@ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file --- -Built with โค๏ธ for the South African tech community +Built with love for the South African tech community \ No newline at end of file diff --git a/eslint.config.js b/eslint.config.js index d56420f..77cbc17 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -4,6 +4,7 @@ import reactHooks from 'eslint-plugin-react-hooks' import reactRefresh from 'eslint-plugin-react-refresh' import { defineConfig, globalIgnores } from 'eslint/config' +// ESLint configuration export default defineConfig([ globalIgnores(['dist']), { diff --git a/package-lock.json b/package-lock.json index bc7afa3..147e7b2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,10 +8,12 @@ "name": "zatech-website", "version": "0.0.0", "dependencies": { + "i18next": "^25.6.0", "lucide-react": "^0.544.0", "prop-types": "^15.8.1", "react": "^19.1.1", "react-dom": "^19.1.1", + "react-i18next": "^16.2.1", "react-router-dom": "^7.9.1" }, "devDependencies": { @@ -334,7 +336,6 @@ "version": "7.28.4", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz", "integrity": "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -3239,6 +3240,15 @@ "node": ">=18" } }, + "node_modules/html-parse-stringify": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz", + "integrity": "sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==", + "license": "MIT", + "dependencies": { + "void-elements": "3.1.0" + } + }, "node_modules/html-tags": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.3.1.tgz", @@ -3280,6 +3290,37 @@ "node": ">= 14" } }, + "node_modules/i18next": { + "version": "25.6.0", + "resolved": "https://registry.npmjs.org/i18next/-/i18next-25.6.0.tgz", + "integrity": "sha512-tTn8fLrwBYtnclpL5aPXK/tAYBLWVvoHM1zdfXoRNLcI+RvtMsoZRV98ePlaW3khHYKuNh/Q65W/+NVFUeIwVw==", + "funding": [ + { + "type": "individual", + "url": "https://locize.com" + }, + { + "type": "individual", + "url": "https://locize.com/i18next.html" + }, + { + "type": "individual", + "url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project" + } + ], + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.27.6" + }, + "peerDependencies": { + "typescript": "^5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, "node_modules/iconv-lite": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", @@ -4225,6 +4266,33 @@ "react": "^19.1.1" } }, + "node_modules/react-i18next": { + "version": "16.2.1", + "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-16.2.1.tgz", + "integrity": "sha512-z7TVwd8q4AjFo2n7oOwzNusY7xVL4uHykwX1zZRvasUQnmnXlp7Z1FZqXvhK/6hQaCvWTZmZW1bMaUWKowtvVw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.27.6", + "html-parse-stringify": "^3.0.1", + "use-sync-external-store": "^1.6.0" + }, + "peerDependencies": { + "i18next": ">= 25.5.2", + "react": ">= 16.8.0", + "typescript": "^5" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, "node_modules/react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", @@ -5035,6 +5103,15 @@ "punycode": "^2.1.0" } }, + "node_modules/use-sync-external-store": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", + "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -5043,9 +5120,9 @@ "license": "MIT" }, "node_modules/vite": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/vite/-/vite-7.1.6.tgz", - "integrity": "sha512-SRYIB8t/isTwNn8vMB3MR6E+EQZM/WG1aKmmIUCfDXfVvKfc20ZpamngWHKzAmmu9ppsgxsg4b2I7c90JZudIQ==", + "version": "7.1.12", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.1.12.tgz", + "integrity": "sha512-ZWyE8YXEXqJrrSLvYgrRP7p62OziLW7xI5HYGWFzOvupfAlrLvURSzv/FyGyy0eidogEM3ujU+kUG1zuHgb6Ug==", "dev": true, "license": "MIT", "dependencies": { @@ -5213,6 +5290,15 @@ } } }, + "node_modules/void-elements": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", + "integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/w3c-xmlserializer": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", diff --git a/package.json b/package.json index f43a0fe..0d580bf 100644 --- a/package.json +++ b/package.json @@ -18,10 +18,12 @@ "test:all": "npm run test:run && npm run test:e2e" }, "dependencies": { + "i18next": "^25.6.0", "lucide-react": "^0.544.0", "prop-types": "^15.8.1", "react": "^19.1.1", "react-dom": "^19.1.1", + "react-i18next": "^16.2.1", "react-router-dom": "^7.9.1" }, "devDependencies": { diff --git a/playwright-report/index.html b/playwright-report/index.html index 92fd0d5..b1c0af4 100644 --- a/playwright-report/index.html +++ b/playwright-report/index.html @@ -73,4 +73,4 @@