@etsoo/materialui
Version:
TypeScript Material-UI Implementation
368 lines (367 loc) • 11.5 kB
JavaScript
"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;