diff --git a/.env b/.env deleted file mode 100644 index d3e6955..0000000 --- a/.env +++ /dev/null @@ -1,5 +0,0 @@ -NODE_ENV=development -API_URL=http://localhost:3001/api/ -EXTERNAL_LOGIN=true -CKEDITOR_LICENSE_KEY=GPL -STICKER_TEXT=Source \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 8551ab6..ee41b3c 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -15,37 +15,34 @@ "background": { "activeOnStart": true, "beginsPattern": "^.*", - "endsPattern": "listening on|started|ready" + "endsPattern": "proxy" } } }, { - "label": "Start CRA", + "label": "Start Vite", "type": "process", "command": "npm", - "args": ["start"], + "args": ["run", "dev"], "isBackground": true, "runOptions": { "reevaluateOnRerun": true, "terminateOnExit": true }, - "options": { - "env": { - "BROWSER": "none" - } - }, "problemMatcher": { - "pattern": { "regexp": ".*" }, + "pattern": { + "regexp": ".*" + }, "background": { "activeOnStart": true, - "beginsPattern": "^.*", - "endsPattern": "Compiled successfully|webpack compiled" + "beginsPattern": "vite", + "endsPattern": "ready in" } } }, { "label": "Start All", - "dependsOn": ["Start Proxy", "Start CRA"], + "dependsOn": ["Start Proxy", "Start Vite"], "dependsOrder": "parallel" }, { diff --git a/Dockerfile b/Dockerfile index 342155e..a2ec430 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,32 +1,28 @@ -#Stage 1 - the build process +# Stage 1 - Build Vite app FROM node:latest as build-deps WORKDIR /app -#COPY package.json . + COPY . . RUN npm install RUN npm run build RUN npm run build-css -#Stage 2 - the production environment +# Stage 2 - Production environment (Nginx) FROM nginx:latest -ENV EXTERNAL_LOGIN=true - -RUN apt-get update && apt-get upgrade -y && \ - apt-get install -y nodejs \ - npm # note this one -WORKDIR /usr/share/nginx/html +# Copy Nginx config COPY nginx/nginx.conf /etc/nginx/conf.d/default.conf -COPY --from=build-deps /app/build /usr/share/nginx/html -copy --from=build-deps /app/public/styles.css /usr/share/nginx/html -# copy .env.example as .env to the container -COPY .env.example .env +# Copy built Vite output +COPY --from=build-deps /app/dist /usr/share/nginx/html -RUN npm install -g cross-env -RUN npm install -g runtime-env-cra - -EXPOSE 80 -EXPOSE 443 - -CMD ["/bin/sh", "-c", "runtime-env-cra && nginx -g \"daemon off;\""] \ No newline at end of file +# Create env.js at container startup +# This injects runtime environment variables into window._env_ +CMD ["/bin/sh", "-c", "\ + echo \"window._env_ = { \ + API_URL: '${API_URL}', \ + EXTERNAL_LOGIN: true, \ + CKEDITOR_LICENSE_KEY: '${CKEDITOR_LICENSE_KEY}', \ + STICKER_TEXT: '${STICKER_TEXT}' \ + };\" > /usr/share/nginx/html/env.js && \ + nginx -g 'daemon off;'"] \ No newline at end of file diff --git a/config-overrides.js b/config-overrides.js deleted file mode 100644 index 485793a..0000000 --- a/config-overrides.js +++ /dev/null @@ -1,77 +0,0 @@ -//const { styles } = require( '@ckeditor/ckeditor5-dev-utils' ); - -module.exports = function override(config, env) { - if (!config.plugins) { - config.plugins = []; - } - - for ( const rule of config.module.rules ) - { - if (rule.oneOf !== undefined) { - //loader: require.resolve('file-loader'), - rule.oneOf[2].use[1].options = { - // Exclude `js` files to keep the "css" loader working as it injects - // its runtime that would otherwise be processed through the "file" loader. - // Also exclude `html` and `json` extensions so they get processed - // by webpack's internal loaders. - exclude: [ - /\.(js|mjs|jsx|ts|tsx)$/, - /\.html$/, - /\.json$/, - /ckeditor5-[^/\\]+[/\\]theme[/\\]icons[/\\][^/\\]+\.svg$/, - /ckeditor5-[^/\\]+[/\\]theme[/\\].+\.css$/ - ], - name: 'static/media/[name].[hash:8].[ext]', - } - - //test: cssRegex, - rule.oneOf[5].exclude = [ - /\.module\.css$/, - /ckeditor5-[^/\\]+[/\\]theme[/\\].+\.css$/, - ]; - - //test: cssModuleRegex, - rule.oneOf[6].exclude = [ - /ckeditor5-[^/\\]+[/\\]theme[/\\].+\.css$/, - ]; - - //Added items - // rule.oneOf.unshift( { - // test: /ckeditor5-[^/\\]+[/\\]theme[/\\].+\.css$/, - // use: [ - // { - // loader: 'style-loader', - // options: { - // injectType: 'singletonStyleTag', - // attributes: { - // 'data-cke': true - // } - // } - // }, - // 'css-loader', - // { - // loader: 'postcss-loader', - // options: { - // postcssOptions: styles.getPostCssConfig( { - // themeImporter: { - // themePath: require.resolve( '@ckeditor/ckeditor5-theme-lark' ) - // }, - // minify: true - // } ) - // } - // } - // ] - // } - // ); - - // rule.oneOf.unshift( { - // test: /ckeditor5-[^/\\]+[/\\]theme[/\\]icons[/\\][^/\\]+\.svg$/, - // use: [ 'raw-loader' ] - // } - // ); - - } - } - - return config; -} \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 0000000..da8896c --- /dev/null +++ b/index.html @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + e-suite + + + + + + + + + +
+ + + diff --git a/package.json b/package.json index e7071a4..4c3495c 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,6 @@ "react-helmet-async": "^2.0.5", "react-i18next": "^16.5.4", "react-router-dom": "^7.13.0", - "react-scripts": "^5.0.1", "react-toastify": "^11.0.5", "react-toggle": "^4.1.3", "runtime-env-cra": "^0.2.4", @@ -54,13 +53,10 @@ "scripts": { "build-css": "sass src/Sass/global.scss public/styles.css", "watch-css": "nodemon -e scss -x \"npm run build-css\" ", - "start-react": "cross-env NODE_ENV=development runtime-env-cra --config-name=./public/runtime-env.js && react-app-rewired start", "prestart": "node scripts/generate-locales.js", - "start": "concurrently \"npm run start-react\" \"npm run watch-css\" ", - "prebuild": "node scripts/generate-locales.js", - "build": "react-app-rewired build", - "test": "react-app-rewired test", - "eject": "react-scripts eject", + "dev": "vite", + "build": "vite build", + "preview": "vite preview", "i18n:extract": "i18next \"src/**/*.{ts,tsx,js,jsx}\" \"!src/components/common/ckeditor/**\" --config i18next-parser.config.js", "i18n:unused": "i18n-unused display-unused", "i18n:missed": "i18n-unused display-missed", @@ -87,9 +83,10 @@ "devDependencies": { "@types/node": "^22.13.5", "@types/react-toggle": "^4.0.5", + "@vitejs/plugin-react": "^5.1.4", "i18n-unused": "^0.19.0", "i18next-parser": "^9.3.0", - "react-app-rewired": "^2.2.1", - "typescript": "^4.9.5" + "typescript": "^5.9.3", + "vite": "^7.3.1" } } diff --git a/public/env.js b/public/env.js new file mode 100644 index 0000000..38005c9 --- /dev/null +++ b/public/env.js @@ -0,0 +1,6 @@ +window._env_ = { + API_URL: "http://localhost:3001/api/", + EXTERNAL_LOGIN: true, + CKEDITOR_LICENSE_KEY: "GPL", + STICKER_TEXT: "Source", +}; diff --git a/public/index.html b/public/index.html deleted file mode 100644 index 8f385bb..0000000 --- a/public/index.html +++ /dev/null @@ -1,67 +0,0 @@ - - - - - - - - - - - - - - - - - - e-suite - - - - - - - - - -
- - - diff --git a/public/runtime-env.js b/public/runtime-env.js deleted file mode 100644 index 2be6a9b..0000000 --- a/public/runtime-env.js +++ /dev/null @@ -1 +0,0 @@ -window.__RUNTIME_CONFIG__ = {"NODE_ENV":"development","API_URL":"http://localhost:3001/api/","EXTERNAL_LOGIN":"true","CKEDITOR_LICENSE_KEY":"GPL","STICKER_TEXT":"Source"}; \ No newline at end of file diff --git a/src/components/common/ckeditor/TextEditor.jsx b/src/components/common/ckeditor/TextEditor.jsx index 7e24beb..6d7ab42 100644 --- a/src/components/common/ckeditor/TextEditor.jsx +++ b/src/components/common/ckeditor/TextEditor.jsx @@ -2,6 +2,8 @@ import { useState, useEffect, useRef } from "react"; import { CKEditor } from "@ckeditor/ckeditor5-react"; import Field from "./plugins/field/field"; +import { CKEDITOR_LICENSE_KEY } from "../../../environment"; + import { DecoupledEditor, AccessibilityHelp, @@ -198,7 +200,7 @@ export default function TextEditor(props) { customfields = props.customFields; } - const licenseKey = window.__RUNTIME_CONFIG__?.CKEDITOR_LICENSE_KEY || "GPL"; + const licenseKey = CKEDITOR_LICENSE_KEY || "GPL"; const editorConfig = { licenseKey: licenseKey, diff --git a/src/environment.ts b/src/environment.ts new file mode 100644 index 0000000..2214a21 --- /dev/null +++ b/src/environment.ts @@ -0,0 +1,4 @@ +export const API_URL = window._env_.API_URL; +export const EXTERNAL_LOGIN = window._env_.EXTERNAL_LOGIN; +export const CKEDITOR_LICENSE_KEY = window._env_.CKEDITOR_LICENSE_KEY; +export const STICKER_TEXT = window._env_.STICKER_TEXT; diff --git a/src/i18n/generatedLocales.ts b/src/i18n/generatedLocales.ts index d3a8d32..522c0a0 100644 --- a/src/i18n/generatedLocales.ts +++ b/src/i18n/generatedLocales.ts @@ -10,22 +10,8 @@ export const availableLocales = [ "fr-CA", "fr-FR", "hi-IN", - "ur-AE", - "ur-AF", - "ur-AU", - "ur-BH", - "ur-CA", - "ur-GB", "ur-IN", - "ur-KW", - "ur-OM", - "ur-PK", - "ur-QA", - "ur-SA", - "ur-TJ", - "ur-US", - "ur-UZ", - "ur-ZA" + "ur-PK" ] as const; export const baseLocales = [ @@ -67,69 +53,13 @@ export const fallbackLng = { "hi-IN": [ "en" ], - "ur-AE": [ - "ur", - "en" - ], - "ur-AF": [ - "ur", - "en" - ], - "ur-AU": [ - "ur", - "en" - ], - "ur-BH": [ - "ur", - "en" - ], - "ur-CA": [ - "ur", - "en" - ], - "ur-GB": [ - "ur", - "en" - ], "ur-IN": [ "ur", "en" ], - "ur-KW": [ - "ur", - "en" - ], - "ur-OM": [ - "ur", - "en" - ], "ur-PK": [ "ur", "en" - ], - "ur-QA": [ - "ur", - "en" - ], - "ur-SA": [ - "ur", - "en" - ], - "ur-TJ": [ - "ur", - "en" - ], - "ur-US": [ - "ur", - "en" - ], - "ur-UZ": [ - "ur", - "en" - ], - "ur-ZA": [ - "ur", - "en" ] } as const; diff --git a/src/index.css b/src/index.css deleted file mode 100644 index ec2585e..0000000 --- a/src/index.css +++ /dev/null @@ -1,13 +0,0 @@ -body { - margin: 0; - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', - 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', - sans-serif; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -code { - font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', - monospace; -} diff --git a/src/logo.svg b/src/logo.svg deleted file mode 100644 index 9dfc1c0..0000000 --- a/src/logo.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/index.tsx b/src/main.tsx similarity index 96% rename from src/index.tsx rename to src/main.tsx index d330605..3a9e1ae 100644 --- a/src/index.tsx +++ b/src/main.tsx @@ -1,4 +1,4 @@ -import "./i18n/i18n"; +//import "./i18n/i18n"; import React from "react"; import ReactDOM from "react-dom/client"; import App from "./App"; diff --git a/src/modules/frame/components/LoginForm.tsx b/src/modules/frame/components/LoginForm.tsx index e4d9f9f..08fc45c 100644 --- a/src/modules/frame/components/LoginForm.tsx +++ b/src/modules/frame/components/LoginForm.tsx @@ -1,8 +1,9 @@ +import { EXTERNAL_LOGIN } from "../../../environment"; import ExternalLoginForm from "./ExternalLoginForm"; import InternalLoginForm from "./InternalLoginForm"; const LoginForm: React.FC = () => { - if (window.__RUNTIME_CONFIG__.EXTERNAL_LOGIN) { + if (EXTERNAL_LOGIN) { return ( <> diff --git a/src/modules/frame/components/Logout.tsx b/src/modules/frame/components/Logout.tsx index 2b9d529..b39de20 100644 --- a/src/modules/frame/components/Logout.tsx +++ b/src/modules/frame/components/Logout.tsx @@ -2,13 +2,14 @@ import React, { useEffect } from "react"; import { useTranslation } from "react-i18next"; import { Namespaces } from "../../../i18n/i18n"; import authentication from "../services/authenticationService"; +import { EXTERNAL_LOGIN } from "../../../environment"; const Logout: React.FC = () => { const { t } = useTranslation(Namespaces.Common); useEffect(() => { authentication.logout(); - if (window.__RUNTIME_CONFIG__.EXTERNAL_LOGIN) { + if (EXTERNAL_LOGIN) { window.location.href = "/account/logout"; } else { window.location.href = "/"; diff --git a/src/modules/frame/components/Sticker.tsx b/src/modules/frame/components/Sticker.tsx index ba7bb6c..7b2bd45 100644 --- a/src/modules/frame/components/Sticker.tsx +++ b/src/modules/frame/components/Sticker.tsx @@ -1,14 +1,14 @@ +import { STICKER_TEXT } from "../../../environment"; + const isBlank = (value: string | null | undefined) => !value || value.trim().length === 0; const Sticker: React.FC = () => { - if (isBlank(window.__RUNTIME_CONFIG__.STICKER_TEXT)) { + if (isBlank(STICKER_TEXT)) { return null; } - return ( - {window.__RUNTIME_CONFIG__.STICKER_TEXT} - ); + return {STICKER_TEXT}; }; export default Sticker; diff --git a/src/modules/frame/services/authenticationService.ts b/src/modules/frame/services/authenticationService.ts index 98c57aa..e012c19 100644 --- a/src/modules/frame/services/authenticationService.ts +++ b/src/modules/frame/services/authenticationService.ts @@ -3,6 +3,7 @@ import Cookies from "js-cookie"; import httpService from "../../../services/httpService"; import { IEmailUserAction } from "../models/IEmailUserAction"; import JwtToken from "../models/JwtToken"; +import { EXTERNAL_LOGIN } from "../../../environment"; const apiEndpoint = "/Authentication"; //const tokenKey = "token"; @@ -37,7 +38,7 @@ async function refreshToken() { const fiveMinutesFromNow: Date = new Date(Date.now() + 5 * 60 * 1000); if (currentUser.expiry < fiveMinutesFromNow) { - const refreshTokenRoute = window.__RUNTIME_CONFIG__.EXTERNAL_LOGIN + const refreshTokenRoute = EXTERNAL_LOGIN ? "/../account/refreshToken" : apiEndpoint + "/refreshToken"; diff --git a/src/modules/homepage/Env.tsx b/src/modules/homepage/Env.tsx index befc6b6..72b5075 100644 --- a/src/modules/homepage/Env.tsx +++ b/src/modules/homepage/Env.tsx @@ -1,4 +1,10 @@ import React from "react"; +import { + API_URL, + CKEDITOR_LICENSE_KEY, + EXTERNAL_LOGIN, + STICKER_TEXT, +} from "../../environment"; const EnvPage: React.FC = () => { return ( @@ -9,23 +15,16 @@ const EnvPage: React.FC = () => { window.__RUNTIME_CONFIG__.NODE_ENV ={" "} {window.__RUNTIME_CONFIG__.NODE_ENV}

-

- window.__RUNTIME_CONFIG__.API_URL = {window.__RUNTIME_CONFIG__.API_URL} -

+

window.__RUNTIME_CONFIG__.API_URL = {API_URL}

window.__RUNTIME_CONFIG__.EXTERNAL_LOGIN ={" "} - {window.__RUNTIME_CONFIG__.EXTERNAL_LOGIN ? "true" : "false"} + {EXTERNAL_LOGIN ? "true" : "false"}

window.__RUNTIME_CONFIG__?.CKEDITOR_LICENSE_KEY ={" "} - {window.__RUNTIME_CONFIG__?.CKEDITOR_LICENSE_KEY === "GPL" - ? "GPL" - : "hidden"} -

-

- window.__RUNTIME_CONFIG__.STICKER_TEXT ={" "} - {window.__RUNTIME_CONFIG__.STICKER_TEXT} + {CKEDITOR_LICENSE_KEY === "GPL" ? "GPL" : "hidden"}

+

window.__RUNTIME_CONFIG__.STICKER_TEXT = {STICKER_TEXT}

); }; diff --git a/src/services/httpService.ts b/src/services/httpService.ts index be0ce93..a166670 100644 --- a/src/services/httpService.ts +++ b/src/services/httpService.ts @@ -6,6 +6,7 @@ import axios, { } from "axios"; import { isValid, parseISO } from "date-fns"; import { toast } from "react-toastify"; +import { API_URL } from "../environment"; Object.defineProperty(BigInt.prototype, "toJSON", { get() { @@ -55,7 +56,7 @@ export function setupInterceptorsTo( return axiosInstance; } -axios.defaults.baseURL = window.__RUNTIME_CONFIG__.API_URL; +axios.defaults.baseURL = API_URL; // window.__RUNTIME_CONFIG__.API_URL; setupInterceptorsTo(axios); export function setJwt(jwt: string | null) { diff --git a/stop-tasks.ps1 b/stop-tasks.ps1 index 6025f22..77d3906 100644 --- a/stop-tasks.ps1 +++ b/stop-tasks.ps1 @@ -4,8 +4,8 @@ Write-Host "Stopping development tasks..." # Find and stop processes by command line $processes = Get-WmiObject Win32_Process | Where-Object { ($_.CommandLine -like '*proxy.cmd*') -or - ($_.CommandLine -like '*npm*start*') -or - ($_.CommandLine -like '*react-scripts*') + ($_.CommandLine -like '*npm*run*dev*') -or + ($_.CommandLine -like '*vite*') } foreach ($proc in $processes) { diff --git a/vite.config.ts b/vite.config.ts new file mode 100644 index 0000000..a25bb64 --- /dev/null +++ b/vite.config.ts @@ -0,0 +1,12 @@ +import { defineConfig } from "vite"; +import react from "@vitejs/plugin-react"; + +export default defineConfig({ + plugins: [react()], + server: { + port: 3000, + strictPort: true, + host: true, + allowedHosts: ["host.docker.internal"], + }, +});