diff --git a/packages/app/.config.js b/packages/app/.config.js index 559c8337..1f2929a0 100644 --- a/packages/app/.config.js +++ b/packages/app/.config.js @@ -1,16 +1,17 @@ -const path = require('path') +const path = require("path") const aliases = { - '~/': `${path.resolve(__dirname, 'src')}/`, + "~/": `${path.resolve(__dirname, "src")}/`, "__": __dirname, - "@src": path.resolve(__dirname, 'src'), - schemas: path.resolve(__dirname, 'constants'), - config: path.join(__dirname, 'config'), - extensions: path.resolve(__dirname, 'src/extensions'), - pages: path.join(__dirname, 'src/pages'), - theme: path.join(__dirname, 'src/theme'), - components: path.join(__dirname, 'src/components'), - models: path.join(__dirname, 'src/models'), + "@src": path.resolve(__dirname, "src"), + schemas: path.resolve(__dirname, "constants"), + config: path.join(__dirname, "config"), + extensions: path.resolve(__dirname, "src/extensions"), + pages: path.join(__dirname, "src/pages"), + theme: path.join(__dirname, "src/theme"), + components: path.join(__dirname, "src/components"), + models: path.join(__dirname, "src/models"), + utils: path.join(__dirname, "src/utils"), } module.exports = (config = {}) => { @@ -22,12 +23,14 @@ module.exports = (config = {}) => { } config.resolve.alias = aliases - config.server.port = 8000 + config.server.port = process.env.listenPort ?? 8000 config.server.host = "0.0.0.0" config.server.fs = { allow: [".."] } + config.envDir = path.join(__dirname, "environments") + config.css = { preprocessorOptions: { less: { diff --git a/packages/app/capacitor.config.json b/packages/app/capacitor.config.json index 907634ec..35900907 100644 --- a/packages/app/capacitor.config.json +++ b/packages/app/capacitor.config.json @@ -3,10 +3,5 @@ "appName": "Comty", "bundledWebRuntime": true, "overrideUserAgent": "capacitor", - "webDir": "dist", - "server": { - "hostname": "192.168.0.5:8000", - "iosScheme": "http", - "androidScheme": "http" - } + "webDir": "dist" } \ No newline at end of file diff --git a/packages/app/package.json b/packages/app/package.json index 29a9d7a9..31c2c5ab 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -5,64 +5,79 @@ "scripts": { "dev": "vite", "dev:ssr": "vite-ssr", - "dev:evite": "evite dev", - "build": "cross-env NODE_ENV=production vite build", + "sync": "capacitor sync ios && capacitor sync android", + "build": "cross-env NODE_ENV=production vite build && yarn sync", + "build:dist": "cross-env NODE_ENV=production vite build", + "build:preview": "cross-env NODE_ENV=preview vite build && yarn sync", "build:ssr": "cross-env NODE_ENV=production vite-ssr build && ./scripts/move-dist.sh", "preview": "vite preview", "capacitor": "capacitor" }, + "peerDependencies": { + "react": "^16.8.6" + }, "dependencies": { - "@ant-design/icons": "^4.7.0", - "@corenode/utils": "^0.28.26", - "@react-pdf/renderer": "^1.6.17", - "antd": "^4.17.4", - "chart.js": "^3.5.1", - "classnames": "^2.3.1", - "dicebar_lib": "^1.0.0", - "enquire-js": "^0.2.1", - "evite-react-lib": "^0.9.0", - "faye": "^1.4.0", - "feather-reactjs": "^2.0.13", - "fuse.js": "^6.4.6", - "hls.js": "^1.0.12", - "howler": "^2.2.3", - "i18next": "^20.3.5", - "js-cookie": "^2.2.1", - "less": "^4.1.2", - "linebridge": "^0.8.4", - "moment": "^2.29.1", + "@ant-design/icons": "4.7.0", + "@capacitor/android": "^3.4.0", + "@capacitor/haptics": "^1.1.4", + "@capacitor/push-notifications": "^1.0.9", + "@capacitor/status-bar": "1.0.7", + "@capacitor/storage": "1.2.4", + "@corenode/utils": "0.28.26", + "@emotion/css": "11.0.0", + "@foxify/events": "2.0.1", + "@loadable/component": "5.15.2", + "antd": "4.18.6", + "antd-mobile": "^5.0.0-rc.17", + "chart.js": "3.7.0", + "classnames": "2.3.1", + "evite": "0.9.5", + "faye": "1.4.0", + "feather-reactjs": "2.0.13", + "fuse.js": "6.5.3", + "global": "4.4.0", + "history": "5.2.0", + "hls.js": "^1.1.5", + "howler": "2.2.3", + "i18next": "21.6.6", + "js-cookie": "3.0.1", + "jwt-decode": "3.1.2", + "less": "4.1.2", + "linebridge": "0.10.13", + "moment": "2.29.1", "mpegts.js": "^1.6.10", - "plyr": "^3.6.9", - "qrcode": "^1.4.4", - "@foxify/events": "^2.0.1", - "@loadable/component": "^5.15.0", - "history": "^5.0.1", - "jwt-decode": "^3.1.2", - "react": "^17.0.2", - "react-helmet": "^6.1.0", - "react-beautiful-dnd": "^13.1.0", - "react-chartjs-2": "^3.2.0", - "react-color": "^2.19.3", - "react-contexify": "^5.0.0", - "react-dom": "^17.0.2", - "react-draggable": "^4.4.3", - "react-helmet-async": "^1.0.9", - "react-i18next": "^11.11.4", - "react-icons": "^4.3.1", - "react-json-view": "^1.21.3", - "react-qr-reader": "^2.2.1", - "react-reveal": "^1.2.2", - "react-rnd": "^10.3.5", - "react-router": "^5.2.0", - "react-router-config": "^5.1.1", - "react-router-dom": "^5.2.0", - "socket.io-client": "^4.2.0", - "vite-ssr": "^0.14.3" + "nprogress": "^0.2.0", + "plyr": "^3.6.12", + "prop-types": "^15.8.1", + "qrcode": "1.5.0", + "react": "17.0.2", + "react-beautiful-dnd": "13.1.0", + "react-chartjs-2": "4.0.1", + "react-color": "2.19.3", + "react-contexify": "5.0.0", + "react-dom": "17.0.2", + "react-draggable": "4.4.4", + "react-helmet": "6.1.0", + "react-i18next": "11.15.3", + "react-icons": "4.3.1", + "react-intersection-observer": "8.33.1", + "react-json-view": "1.21.3", + "react-lazy-load-image-component": "^1.5.1", + "react-motion": "0.5.2", + "react-reveal": "1.2.2", + "react-rnd": "10.3.5", + "react-router": "6.2.1", + "react-router-config": "5.1.1", + "react-router-dom": "6.2.1", + "store": "^2.0.12", + "styled-components": "^5.3.3", + "vite-ssr": "0.15.0" }, "devDependencies": { - "@capacitor/cli": "^3.2.2", - "@capacitor/core": "^3.2.2", - "@capacitor/ios": "^3.0.2", + "@capacitor/cli": "3.2.2", + "@capacitor/core": "3.2.2", + "@capacitor/ios": "3.0.2", + "@capacitor/project": "1.0.28", "@types/jest": "^26.0.24", "@types/node": "^16.4.10", "@types/react": "^17.0.15", @@ -71,11 +86,11 @@ "@types/react-router-dom": "^5.1.8", "@typescript-eslint/eslint-plugin": "^4.29.0", "@vitejs/plugin-react-refresh": "^1.3.6", - "corenode": "^0.28.26", + "corenode": "0.28.26", "cross-env": "^7.0.3", - "evite": "^0.8.8", + "express": "^4.17.1", "typescript": "^4.3.5", - "vite": "^2.7.1", + "vite": "2.7.13", "vite-plugin-pages": "0.12.x" } } diff --git a/packages/app/src/App.jsx b/packages/app/src/App.jsx index 5fd1f183..a3c4bbbb 100644 --- a/packages/app/src/App.jsx +++ b/packages/app/src/App.jsx @@ -1,4 +1,13 @@ // Patch global prototypes +Array.prototype.findAndUpdateObject = function (discriminator, obj) { + let index = this.findIndex(item => item[discriminator] === obj[discriminator]) + if (index !== -1) { + this[index] = obj + } + + return index +} + Array.prototype.move = function (from, to) { this.splice(to, 0, this.splice(from, 1)[0]) return this @@ -10,19 +19,45 @@ String.prototype.toTitleCase = function () { }) } +Promise.tasked = function (promises) { + return new Promise(async (resolve, reject) => { + let rejected = false + + for await (let promise of promises) { + if (rejected) { + return + } + + try { + await promise() + } catch (error) { + rejected = true + return reject(error) + } + } + + if (!rejected) { + return resolve() + } + }) +} + import React from "react" -import { CreateEviteApp, BindPropsProvider } from "evite-react-lib" +import { CreateEviteApp, BindPropsProvider } from "evite" import { Helmet } from "react-helmet" import * as antd from "antd" +import { ActionSheet, Toast } from "antd-mobile" +import { StatusBar, Style } from "@capacitor/status-bar" +import { Translation } from "react-i18next" -import { Session, User, SidebarController, SettingsController } from "models" -import { API, Render, Splash, Theme, Sound } from "extensions" +import { Session, User } from "models" +import { API, SettingsController, Render, Splash, Theme, Sound, Notifications, i18n } from "extensions" import config from "config" -import { NotFound, RenderError, Settings } from "components" -import Layout from "./layout" +import { NotFound, RenderError, Crash, Settings, Navigation } from "components" import { Icons } from "components/Icons" +import Layout from "./layout" import "theme/index.less" const SplashExtension = Splash.extension({ @@ -39,118 +74,115 @@ const SplashExtension = Splash.extension({ }, }) -class ThrowCrash { - constructor(message, description) { - this.message = message - this.description = description - - antd.notification.error({ - message: "Fatal error", - description: message, - }) - - window.app.eventBus.emit("crash", this.message, this.description) - } -} - -const __renderTest = () => { - const [position, setPosition] = React.useState(0) - - // create a 300ms interval to move randomly inside window screen - React.useEffect(() => { - setInterval(() => { - const x = Math.random() * window.innerWidth - const y = Math.random() * window.innerHeight - - setPosition({ x, y }) - }, 50) - }, []) - - // clear interval when component unmount - React.useEffect(() => { - return () => { - clearInterval() - } - }, []) - - return
-} - class App { static initialize() { - this.configuration = { - settings: new SettingsController(), - sidebar: new SidebarController(), - } + window.app.version = config.package.version - this.eventBus = this.contexts.main.eventBus + this.mainSocket = this.contexts.app.WSInterface.sockets.main + this.loadingMessage = false + this.isAppCapacitor = () => navigator.userAgent === "capacitor" + } - this.eventBus.on("app_loading", async () => { - await this.setState({ initialized: false }) - this.eventBus.emit("splash_show") - }) - - this.eventBus.on("app_ready", async () => { - await this.setState({ initialized: true }) - this.eventBus.emit("splash_close") - }) - - this.eventBus.on("reinitializeSession", async () => { - await this.__SessionInit() - }) - this.eventBus.on("reinitializeUser", async () => { - await this.__UserInit() - }) - - this.eventBus.on("forceToLogin", () => { - if (window.location.pathname !== "/login") { - this.beforeLoginLocation = window.location.pathname - } - - window.app.setLocation("/login") - }) - - this.eventBus.on("new_session", async () => { + static eventsHandlers = { + "new_session": async function () { + await this.flushState() await this.initialization() if (window.location.pathname == "/login") { window.app.setLocation(this.beforeLoginLocation ?? "/main") this.beforeLoginLocation = null } - }) - this.eventBus.on("destroyed_session", async () => { + }, + "destroyed_session": async function () { await this.flushState() this.eventBus.emit("forceToLogin") - }) - - this.eventBus.on("invalid_session", (error) => { + }, + "forceToLogin": function () { if (window.location.pathname !== "/login") { - this.sessionController.forgetLocalSession() + this.beforeLoginLocation = window.location.pathname + } + + window.app.setLocation("/login") + }, + "invalid_session": async function (error) { + await this.sessionController.forgetLocalSession() + await this.flushState() + + if (window.location.pathname !== "/login") { + this.eventBus.emit("forceToLogin") antd.notification.open({ - message: "Invalid Session", - description: error, + message:{this.state.crash.error}-
{crash.error}
+