From a366aa80b10ef98ad9d2e43ed9363a5610032de3 Mon Sep 17 00:00:00 2001 From: Adewole Ridwan Date: Thu, 21 Aug 2025 00:38:05 +0100 Subject: [PATCH] feat: implement installing redux toolkit and react bindings (react-redux) feat: implement selection of testing library (jest) saving as dev dependency --- index.js | 211 ++++++++++++--------- test/test-react/.gitignore | 24 +++ test/test-react/README.md | 127 +++++++++++++ test/test-react/eslint.config.js | 29 +++ test/test-react/index.html | 13 ++ test/test-react/package.json | 36 ++++ test/test-react/public/vite.svg | 1 + test/test-react/src/App.jsx | 34 ++++ test/test-react/src/assets/react.svg | 1 + test/test-react/src/index.css | 1 + test/test-react/src/main.jsx | 15 ++ test/test-react/src/utils/axiosInstance.js | 41 ++++ test/test-react/vite.config.js | 9 + 13 files changed, 453 insertions(+), 89 deletions(-) create mode 100644 test/test-react/.gitignore create mode 100644 test/test-react/README.md create mode 100644 test/test-react/eslint.config.js create mode 100644 test/test-react/index.html create mode 100644 test/test-react/package.json create mode 100644 test/test-react/public/vite.svg create mode 100644 test/test-react/src/App.jsx create mode 100644 test/test-react/src/assets/react.svg create mode 100644 test/test-react/src/index.css create mode 100644 test/test-react/src/main.jsx create mode 100644 test/test-react/src/utils/axiosInstance.js create mode 100644 test/test-react/vite.config.js diff --git a/index.js b/index.js index eed4526..96f24cc 100644 --- a/index.js +++ b/index.js @@ -1,102 +1,135 @@ #!/usr/bin/env node -import inquirer from "inquirer"; -import path from "path"; -import { run, createFolder, deleteFile } from './lib/utils.js'; -import { initializePWA } from './lib/pwa.js'; -import { setupCSSFramework } from './lib/css-frameworks.js'; -import { createAxiosSetup, createAppComponent, setupRouterMain, createPWAReadme } from './lib/templates.js'; +import inquirer from "inquirer" +import path from "path" +import { run, createFolder, deleteFile } from "./lib/utils.js" +import { initializePWA } from "./lib/pwa.js" +import { setupCSSFramework } from "./lib/css-frameworks.js" +import { + createAxiosSetup, + createAppComponent, + setupRouterMain, + createPWAReadme, +} from "./lib/templates.js" +;(async () => { + // 1. Collect user inputs + const answers = await inquirer.prompt([ + { + type: "input", + name: "projectName", + message: "Enter project name:", + }, + { + type: "list", + name: "cssFramework", + message: "Choose a CSS framework:", + choices: ["Tailwind", "Bootstrap (CDN)", "React Bootstrap", "MUI"], + }, + { + type: "confirm", + name: "isPWA", + message: "Do you want to make this a Progressive Web App (PWA)?", + default: false, + }, + { + type: "checkbox", + name: "packages", + message: "Select optional packages:", + choices: [ + { name: "Axios", value: "axios" }, + { name: "React Icons", value: "react-icons" }, + { name: "React Hook Form", value: "react-hook-form" }, + { name: "Yup", value: "yup" }, + { name: "Formik", value: "formik" }, + { name: "Moment.js", value: "moment" }, + { name: "ReduxJs/Toolkit", value: "@reduxjs/toolkit" }, + { name: "React Bindings (React-Redux)", value: "react-redux" }, + ], + }, + { + type: "checkbox", + name: "devPackages", + message: "Select dev packages to install:", + choices: [{ name: "Jest", value: "jest" }], + }, + ]) -(async () => { - // 1. Collect user inputs - const answers = await inquirer.prompt([ - { - type: "input", - name: "projectName", - message: "Enter project name:" - }, - { - type: "list", - name: "cssFramework", - message: "Choose a CSS framework:", - choices: ["Tailwind", "Bootstrap (CDN)", "React Bootstrap", "MUI"] - }, - { - type: "confirm", - name: "isPWA", - message: "Do you want to make this a Progressive Web App (PWA)?", - default: false - }, - { - type: "checkbox", - name: "packages", - message: "Select optional packages:", - choices: [ - { name: "Axios", value: "axios" }, - { name: "React Icons", value: "react-icons" }, - { name: "React Hook Form", value: "react-hook-form" }, - { name: "Yup", value: "yup" }, - { name: "Formik", value: "formik" }, - { name: "Moment.js", value: "moment" } - ] - } - ]); + const { projectName, cssFramework, isPWA, packages, devPackages } = answers + const projectPath = path.join(process.cwd(), projectName) - const { projectName, cssFramework, isPWA, packages } = answers; - const projectPath = path.join(process.cwd(), projectName); + console.log( + `\nšŸš€ Creating ${projectName}${isPWA ? " with PWA capabilities" : ""}...` + ) - console.log(`\nšŸš€ Creating ${projectName}${isPWA ? ' with PWA capabilities' : ''}...`); + // 2. Create Vite project + run(`npm create vite@latest ${projectName} -- --template react`) - // 2. Create Vite project - run(`npm create vite@latest ${projectName} -- --template react`); + // 3. Create all necessary folder structure first + const folders = ["components", "pages", "hooks", "store", "utils", "assets"] + folders.forEach((folder) => { + createFolder(path.join(projectPath, "src", folder)) + }) - // 3. Create all necessary folder structure first - const folders = ["components", "pages", "hooks", "store", "utils", "assets"]; - folders.forEach((folder) => { - createFolder(path.join(projectPath, "src", folder)); - }); + // 4. Install packages + const defaultPackages = ["react-router-dom"] + const allPackages = [...defaultPackages, ...packages] + if (allPackages.length > 0) { + run(`npm install ${allPackages.join(" ")}`, projectPath) + } - // 4. Install packages - const defaultPackages = ["react-router-dom"]; - const allPackages = [...defaultPackages, ...packages]; - if (allPackages.length > 0) { - run(`npm install ${allPackages.join(" ")}`, projectPath); - } + if (devPackages.length > 0) { + run(`npm install --save-dev ${devPackages.join(" ")}`, projectPath) + } - // 5. Setup PWA if selected (after folder structure is created) - if (isPWA) { - initializePWA(projectPath, projectName); - } + // 5. Setup PWA if selected (after folder structure is created) + if (isPWA) { + initializePWA(projectPath, projectName) + } - // 6. Setup CSS framework - setupCSSFramework(cssFramework, projectPath); + // 6. Setup CSS framework + setupCSSFramework(cssFramework, projectPath) - // 7. Setup Axios if selected - if (packages.includes("axios")) { - createAxiosSetup(projectPath); - } + // 7. Setup Axios if selected + if (packages.includes("axios")) { + createAxiosSetup(projectPath) + } - // 8. Clean up default boilerplate files - deleteFile(path.join(projectPath, "src", "App.css")); - if (cssFramework !== "Tailwind") { - deleteFile(path.join(projectPath, "src", "index.css")); - } + // 8. Clean up default boilerplate files + deleteFile(path.join(projectPath, "src", "App.css")) + if (cssFramework !== "Tailwind") { + deleteFile(path.join(projectPath, "src", "index.css")) + } - // 9. Generate clean templates - createAppComponent(projectPath, projectName, isPWA); - setupRouterMain(projectPath, cssFramework); - - // 10. Create comprehensive README - createPWAReadme(projectPath, projectName, cssFramework, packages, isPWA); + // 9. Generate clean templates + createAppComponent(projectPath, projectName, isPWA) + setupRouterMain(projectPath, cssFramework) - // 11. Success message - console.log("\nāœ… Setup complete!"); - if (isPWA) { - console.log("šŸ“± PWA features enabled - your app can be installed on mobile devices!"); - console.log("āš ļø Important: Replace placeholder SVG icons with proper PNG icons for production"); - } - console.log(`\nNext steps:\n cd ${projectName}\n npm install\n npm run dev`); - - if (isPWA) { - console.log(`\nšŸ“± To test PWA:\n npm run build\n npm run preview\n Open http://localhost:5173 and test install/offline features`); - } -})(); + // 10. Create comprehensive README + createPWAReadme(projectPath, projectName, cssFramework, packages, isPWA) + + // 11. Success message + console.log("\nāœ… Setup complete!") + if (isPWA) { + console.log( + "šŸ“± PWA features enabled - your app can be installed on mobile devices!" + ) + console.log( + "āš ļø Important: Replace placeholder SVG icons with proper PNG icons for production" + ) + } + console.log( + `\nNext steps:\n cd ${projectName}\n npm install\n npm run dev` + ) + + if (isPWA) { + console.log( + `\nšŸ“± To test PWA:\n npm run build\n npm run preview\n Open http://localhost:5173 and test install/offline features` + ) + } + + if (devPackages.includes("jest")) { + console.log( + "Setting up Jest configuration... \n Add the following to your package.json:" + ) + console.log(`\n "scripts": {\n "test": "jest"\n }`) + } +})() diff --git a/test/test-react/.gitignore b/test/test-react/.gitignore new file mode 100644 index 0000000..a547bf3 --- /dev/null +++ b/test/test-react/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/test/test-react/README.md b/test/test-react/README.md new file mode 100644 index 0000000..dbb4249 --- /dev/null +++ b/test/test-react/README.md @@ -0,0 +1,127 @@ +# test-react + +A modern React application built with Vite. + +## šŸš€ Features + +- ⚔ **Vite** - Fast build tool and development server +- āš›ļø **React 18** - Latest React with modern hooks +- šŸŽØ **Tailwind** - Styling framework +- šŸ›£ļø **React Router** - Client-side routing + +- šŸ“¦ **Additional Packages**: axios, react-icons, formik, @reduxjs/toolkit, react-redux + +## šŸ“‹ Prerequisites + +- Node.js (v16 or higher) +- npm or yarn + +## šŸ› ļø Installation + +1. Navigate to the project directory: + ```bash + cd test-react + ``` + +2. Install dependencies: + ```bash + npm install + ``` + +## šŸƒā€ā™‚ļø Running the Application + +### Development Mode +```bash +npm run dev +``` +The app will be available at `http://localhost:5173` + +### Production Build +```bash +npm run build +``` + +### Preview Production Build +```bash +npm run preview +``` + +## šŸ“ Project Structure + +``` +test-react/ +ā”œā”€ā”€ public/ +ā”œā”€ā”€ src/ +│ ā”œā”€ā”€ components/ # Reusable components +│ ā”œā”€ā”€ pages/ # Page components +│ ā”œā”€ā”€ hooks/ # Custom React hooks +│ ā”œā”€ā”€ store/ # State management +│ ā”œā”€ā”€ utils/ # Utility functions +│ │ └── axiosInstance.js # Axios configuration +│ ā”œā”€ā”€ assets/ # Static assets +│ ā”œā”€ā”€ App.jsx # Main App component +│ └── main.jsx # Entry point +ā”œā”€ā”€ vite.config.js # Vite configuration +└── package.json +``` + +## šŸŽØ Styling + +This project uses **Tailwind** for styling: + +- Classes are available globally +- Configuration in `vite.config.js` +- Customize in `src/index.css` + +## 🌐 API Integration + +Axios is pre-configured in `src/utils/axiosInstance.js`: + +```javascript +import { api } from './utils/axiosInstance'; + +// GET request +const data = await api.get('/users'); + +// POST request +const response = await api.post('/users', { name: 'John' }); +``` + +### Environment Variables +Create a `.env` file: +``` +VITE_API_URL=https://your-api-url.com +``` + +## šŸ”§ Available Scripts + +- `npm run dev` - Start development server +- `npm run build` - Build for production +- `npm run preview` - Preview production build +- `npm run lint` - Run ESLint (if configured) + +## šŸš€ Deployment + +### Vercel +```bash +npm install -g vercel +vercel --prod +``` + +### Netlify +```bash +npm run build +# Upload dist/ folder to Netlify +``` + +## šŸŽÆ Next Steps + +1. **Add Components**: Start building your app components +2. **Set up Routing**: Add more routes in main.jsx +3. **Configure API**: Set up your API endpoints if using Axios +4. **Add State Management**: Implement Redux/Zustand if needed +5. **Deploy**: Deploy to your preferred hosting service + +--- + +Built with ā¤ļø by harsh & Sameer using React + Vite diff --git a/test/test-react/eslint.config.js b/test/test-react/eslint.config.js new file mode 100644 index 0000000..cee1e2c --- /dev/null +++ b/test/test-react/eslint.config.js @@ -0,0 +1,29 @@ +import js from '@eslint/js' +import globals from 'globals' +import reactHooks from 'eslint-plugin-react-hooks' +import reactRefresh from 'eslint-plugin-react-refresh' +import { defineConfig, globalIgnores } from 'eslint/config' + +export default defineConfig([ + globalIgnores(['dist']), + { + files: ['**/*.{js,jsx}'], + extends: [ + js.configs.recommended, + reactHooks.configs['recommended-latest'], + reactRefresh.configs.vite, + ], + languageOptions: { + ecmaVersion: 2020, + globals: globals.browser, + parserOptions: { + ecmaVersion: 'latest', + ecmaFeatures: { jsx: true }, + sourceType: 'module', + }, + }, + rules: { + 'no-unused-vars': ['error', { varsIgnorePattern: '^[A-Z_]' }], + }, + }, +]) diff --git a/test/test-react/index.html b/test/test-react/index.html new file mode 100644 index 0000000..0c589ec --- /dev/null +++ b/test/test-react/index.html @@ -0,0 +1,13 @@ + + + + + + + Vite + React + + +
+ + + diff --git a/test/test-react/package.json b/test/test-react/package.json new file mode 100644 index 0000000..f148342 --- /dev/null +++ b/test/test-react/package.json @@ -0,0 +1,36 @@ +{ + "name": "test-react", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "lint": "eslint .", + "preview": "vite preview" + }, + "dependencies": { + "@reduxjs/toolkit": "^2.8.2", + "@tailwindcss/vite": "^4.1.12", + "axios": "^1.11.0", + "formik": "^2.4.6", + "react": "^19.1.1", + "react-dom": "^19.1.1", + "react-icons": "^5.5.0", + "react-redux": "^9.2.0", + "react-router-dom": "^7.8.1", + "tailwindcss": "^4.1.12" + }, + "devDependencies": { + "@eslint/js": "^9.33.0", + "@types/react": "^19.1.10", + "@types/react-dom": "^19.1.7", + "@vitejs/plugin-react": "^5.0.0", + "eslint": "^9.33.0", + "eslint-plugin-react-hooks": "^5.2.0", + "eslint-plugin-react-refresh": "^0.4.20", + "globals": "^16.3.0", + "jest": "^30.0.5", + "vite": "^7.1.2" + } +} diff --git a/test/test-react/public/vite.svg b/test/test-react/public/vite.svg new file mode 100644 index 0000000..e7b8dfb --- /dev/null +++ b/test/test-react/public/vite.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/test/test-react/src/App.jsx b/test/test-react/src/App.jsx new file mode 100644 index 0000000..6a8be7c --- /dev/null +++ b/test/test-react/src/App.jsx @@ -0,0 +1,34 @@ +export default function App() { + return ( +
+

+ Welcome to{" "} + test-react šŸš€ +

+

+ Your project is ready. Start building amazing things! +

+ + +
+ ); +} \ No newline at end of file diff --git a/test/test-react/src/assets/react.svg b/test/test-react/src/assets/react.svg new file mode 100644 index 0000000..6c87de9 --- /dev/null +++ b/test/test-react/src/assets/react.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/test/test-react/src/index.css b/test/test-react/src/index.css new file mode 100644 index 0000000..f1d8c73 --- /dev/null +++ b/test/test-react/src/index.css @@ -0,0 +1 @@ +@import "tailwindcss"; diff --git a/test/test-react/src/main.jsx b/test/test-react/src/main.jsx new file mode 100644 index 0000000..bb246a7 --- /dev/null +++ b/test/test-react/src/main.jsx @@ -0,0 +1,15 @@ +import './index.css'; +import React from 'react'; +import ReactDOM from 'react-dom/client'; +import { BrowserRouter, Routes, Route } from 'react-router-dom'; +import App from './App'; + +ReactDOM.createRoot(document.getElementById('root')).render( + + + + } /> + + + +); \ No newline at end of file diff --git a/test/test-react/src/utils/axiosInstance.js b/test/test-react/src/utils/axiosInstance.js new file mode 100644 index 0000000..83d5f2f --- /dev/null +++ b/test/test-react/src/utils/axiosInstance.js @@ -0,0 +1,41 @@ +import axios from "axios"; + +export const api = axios.create({ + baseURL: import.meta.env.VITE_API_URL || "http://localhost:5000", + headers: { "Content-Type": "application/json" }, + timeout: 10000 +}); + +// āœ… Request Interceptor +api.interceptors.request.use( + (config) => { + const token = localStorage.getItem("token"); + if (token) { + config.headers.Authorization = `Bearer ${token}`; + } + return config; + }, + (error) => { + return Promise.reject(error); + } +); + +// āœ… Response Interceptor +api.interceptors.response.use( + (response) => { + return response.data; + }, + (error) => { + if (error.response) { + console.error("API Error:", error.response.data?.message || error.message); + if (error.response.status === 401) { + window.location.href = "/login"; + } + } else if (error.request) { + console.error("No response received from server."); + } else { + console.error("Request setup error:", error.message); + } + return Promise.reject(error); + } +); \ No newline at end of file diff --git a/test/test-react/vite.config.js b/test/test-react/vite.config.js new file mode 100644 index 0000000..c3088bd --- /dev/null +++ b/test/test-react/vite.config.js @@ -0,0 +1,9 @@ +import tailwindcss from '@tailwindcss/vite' +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' + +// https://vite.dev/config/ +export default defineConfig({ + plugins: [ + tailwindcss(),react()], +})