UNPKG

@etsoo/materialui

Version:

TypeScript Material-UI Implementation

368 lines (367 loc) 11.5 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.ReactApp = exports.ReactAppContext = void 0; exports.useAppContext = useAppContext; exports.useRequiredAppContext = useRequiredAppContext; const appscript_1 = require("@etsoo/appscript"); const notificationbase_1 = require("@etsoo/notificationbase"); const shared_1 = require("@etsoo/shared"); const react_1 = __importDefault(require("react")); const NotifierMU_1 = require("../NotifierMU"); const ProgressCount_1 = require("../ProgressCount"); const Labels_1 = require("./Labels"); const react_2 = require("@etsoo/react"); /** * React application context */ exports.ReactAppContext = react_1.default.createContext(null); /** * Get React application context hook * @returns React application */ function useAppContext() { return react_1.default.useContext(exports.ReactAppContext); } /** * Get React application context hook * @returns React application */ function useRequiredAppContext() { return (0, react_2.useRequiredContext)(exports.ReactAppContext); } /** * React application */ class ReactApp extends appscript_1.CoreApp { static _notifierProvider; /** * Get notifier provider */ static get notifierProvider() { return this._notifierProvider; } static createNotifier(debug) { // Notifier ReactApp._notifierProvider = NotifierMU_1.NotifierMU.setup(undefined, debug); return NotifierMU_1.NotifierMU.instance; } /** * Culture state */ cultureState; /** * User state */ userState = new react_2.UserState(); /** * Is screen size down 'sm' */ smDown; /** * Is screen size up 'md' */ mdUp; /** * Navigate function */ navigateFunction; /** * User state dispatch */ userStateDispatch; /** * Constructor * @param settings Settings * @param name Application name * @param debug Debug mode */ constructor(settings, name, debug = false) { super(settings, null, ReactApp.createNotifier(debug), new shared_1.WindowStorage(), name, debug); if (appscript_1.BridgeUtils.host) { appscript_1.BridgeUtils.host.onUpdate((app, version) => { this.notifier.message(notificationbase_1.NotificationMessageType.Success, this.get("updateTip") + `(${[app, version].join(", ")})`, this.get("updateReady")); }); } this.cultureState = new react_2.CultureState(this.settings.currentCulture); } /** * Override alert action result * @param result Action result * @param callback Callback * @param forceToLocal Force to local labels */ alertResult(result, callback, forceToLocal) { const message = typeof result === "string" ? result : this.formatResult(result, forceToLocal); if (message.endsWith(")")) { const startPos = message.lastIndexOf("("); if (startPos > 0) { const main = message.substring(0, startPos).trim(); const tip = message.substring(startPos); const titleNode = react_1.default.createElement(react_1.default.Fragment, null, main, react_1.default.createElement("br"), react_1.default.createElement("span", { style: { fontSize: "9px" } }, tip)); this.notifier.alert(titleNode, callback); return; } } super.alertResult(message, callback); } /** * Change culture * @param culture New culture definition */ async changeCulture(culture) { // Super call to update cultrue const resources = await super.changeCulture(culture); // Update component labels Labels_1.Labels.setLabels(resources, { notificationMU: { alertTitle: "warning", alertOK: "ok", confirmTitle: "confirm", confirmYes: "ok", confirmNo: "cancel", promptTitle: "prompt", promptCancel: "cancel", promptOK: "ok" } }); // Document title // Default is servier name's label or appName label const title = this.get(this.name) ?? this.get("appName") ?? this.name; const host = appscript_1.BridgeUtils.host; if (host) { // Notify host host.changeCulture(culture.name); host.setTitle(title); } else { document.title = title; } return resources; } /** * Change culture extended * @param dispatch Dispatch method * @param culture New culture definition */ changeCultureEx(dispatch, culture) { // Same? if (culture.name === this.culture) return; // Super call this.changeCulture(culture).then(() => { // Dispatch action dispatch(culture); }); } /** * Get date format props * @returns Props */ getDateFormatProps() { return { culture: this.culture, timeZone: this.getTimeZone() }; } /** * Get money format props * @param currency Currency, if undefined, default currency applied * @returns Props */ getMoneyFormatProps(currency) { return { culture: this.culture, currency: currency ?? this.currency }; } /** * Fresh countdown UI * @param callback Callback */ freshCountdownUI(callback) { // Labels const labels = this.getLabels("cancel", "tokenExpiry"); // Progress const progress = react_1.default.createElement(ProgressCount_1.ProgressCount, { seconds: 30, valueUnit: "s", onComplete: () => { // Stop the progress return false; } }); // Popup this.notifier.alert(labels.tokenExpiry, async () => { if (callback) await callback(); else await this.tryLogin(); }, undefined, { okLabel: labels.cancel, primaryButtonProps: { fullWidth: true, autoFocus: false }, inputs: progress }); } /** * Try login * @param data Try login parameters * @returns Result */ async tryLogin(data) { // Destruct const { onFailure = (type) => { console.log(`Try login failed: ${type}.`); if (globalThis.navigator.onLine && !type.includes('"title":"Failed to fetch"')) { this.clearCacheToken(); } this.toLoginPage(rest); }, onSuccess, ...rest } = data ?? {}; // Check status const result = await super.tryLogin(data); if (!result) { onFailure("ReactAppSuperTryLoginFailed"); return false; } // Refresh token await this.refreshToken({ showLoading: data?.showLoading }, (result) => { if (result === true) { onSuccess?.(); } else if (result === false) { onFailure("ReactAppRefreshTokenFailed"); } else if (result != null && !this.tryLoginIgnoreResult(result)) { onFailure("ReactAppRefreshTokenFailed: " + JSON.stringify(result)); } else { // Ignore other results onFailure("ReactAppRefreshTokenIgnoredFailure: " + JSON.stringify(result)); return true; } }); return true; } /** * Check if the action result should be ignored during try login * @param result Action result * @returns Result */ tryLoginIgnoreResult(result) { // Ignore no token warning if (result.type === "noData" && result.field === "token") return true; else return false; } /** * Navigate to Url or delta * @param url Url or delta * @param options Options */ navigate(to, options) { if (this.navigateFunction == null) super.navigate(to, options); else if (typeof to === "number") this.navigateFunction(to); else this.navigateFunction(to, options); } /** * Show input dialog * @param props Props */ showInputDialog({ title, message, callback, ...rest }) { return this.notifier.prompt(message, callback, title, rest); } stateDetector(props) { // Destruct const { targetFields, update } = props; // Context const { state } = react_1.default.useContext(this.userState.context); // Ready react_1.default.useEffect(() => { // Match fields const changedFields = state.lastChangedFields; let matchedFields; if (targetFields == null || changedFields == null) { matchedFields = changedFields; } else { matchedFields = []; targetFields.forEach((targetField) => { if (changedFields.includes(targetField)) matchedFields?.push(targetField); }); } // Callback update(state.authorized, matchedFields); }, [state]); // return return react_1.default.createElement(react_1.default.Fragment); } /** * User login extended * @param user New user * @param refreshToken Refresh token * @param dispatch User state dispatch */ userLogin(user, refreshToken, dispatch) { // Super call, set token super.userLogin(user, refreshToken); // Dispatch action if (dispatch !== false) { this.doLoginDispatch(user); } } /** * User login callback * @param user New user */ onUserLogin(user) { return Promise.resolve(); } /** * User login dispatch * @param user New user */ doLoginDispatch(user) { this.onUserLogin(user).then(() => { if (this.userStateDispatch != null) this.userStateDispatch({ type: react_2.UserActionType.Login, user }); }); } /** * User logout * @param clearToken Clear refresh token or not * @param noTrigger No trigger for state change */ userLogout(clearToken = true, noTrigger = false) { // Super call super.userLogout(clearToken); // Dispatch action if (!noTrigger && this.userStateDispatch != null) this.userStateDispatch({ type: react_2.UserActionType.Logout }); } /** * User unauthorized */ userUnauthorized() { // Super call super.userUnauthorized(); if (this.userStateDispatch != null) { // There is delay during state update // Not a good idea to try login multiple times with API calls this.userStateDispatch({ type: react_2.UserActionType.Unauthorized }); } } } exports.ReactApp = ReactApp;