Skip to content

Instantly share code, notes, and snippets.

@joenoon
Created October 16, 2018 07:16
Show Gist options
  • Save joenoon/65426e5bfe729735fe553da7b20eae8f to your computer and use it in GitHub Desktop.
Save joenoon/65426e5bfe729735fe553da7b20eae8f to your computer and use it in GitHub Desktop.
Flash implementation inspired by Rails (ie. flash[:notice]) for frontend.
import { observable, computed, toJS } from 'mobx';
function defaultData() {
return {
text: null,
dataText: null,
type: null,
};
}
function toDataText(dataText) {
if (typeof dataText === 'string') return dataText;
if (dataText == null) return dataText;
try {
const propertyNames = Object.getOwnPropertyNames(dataText);
return JSON.stringify(dataText, propertyNames);
} catch (err) {
console.log('Flash - could not stringify', dataText);
}
}
const NOTICE = 'notice';
const ERROR = 'error';
/**
* Flash implementation inspired by Rails (ie. flash[:notice]) for frontend.
*/
export class Flash {
constructor({ storageKey, timeout }) {
this.storageKey = storageKey;
this.timeout = timeout;
let data: any = localStorage.getItem(storageKey);
localStorage.removeItem(storageKey);
if (data) {
data = {
...defaultData(),
...JSON.parse(data),
};
try {
data.text;
data.dataText;
data.type;
} catch (err) {
console.log('Flash failed to load', data);
data = defaultData();
}
this._data = data;
}
}
@observable
_data = defaultData();
_disposer: any;
storageKey: string;
timeout: number;
/**
* flash for 'notice' if set
*/
@computed
get notice() {
const { _data } = this;
if (_data.type === NOTICE) return toJS(_data);
}
/**
* flash for 'error' if set
*/
@computed
get error() {
const { _data } = this;
if (_data.type === ERROR) return toJS(_data);
}
/**
* set 'notice' for next page load (before a redirect)
*/
noticeNext = (text: string | null, dataText?: any) => {
this._recordNext(NOTICE, text, dataText);
};
/**
* set 'error' for next page load (before a redirect)
*/
errorNext = (text: string | null, dataText?: any) => {
this._recordNext(ERROR, text, dataText);
};
/**
* set 'notice' for immediate use
*/
noticeNow = (text: string | null, dataText?: any) => {
this._recordNow(NOTICE, text, dataText);
};
/**
* set 'error' for immediate use
*/
errorNow = (text: string | null, dataText?: any) => {
this._recordNow(ERROR, text, dataText);
};
/**
* clear all flash
*/
clear = () => {
const { _disposer } = this;
if (_disposer) _disposer();
this._data = defaultData();
};
/**
* call to explicitly dispose
*/
dispose = () => {
const { _disposer } = this;
if (_disposer) _disposer();
};
_recordNext = (type: string, text: string | null, dataText?: any) => {
if (text || dataText) {
localStorage.setItem(
this.storageKey,
JSON.stringify({
text,
dataText: toDataText(dataText),
type,
})
);
} else {
localStorage.removeItem(this.storageKey);
}
};
_recordNow = (type: string, text: string | null, dataText?: any) => {
this.clear();
if (!text && !dataText) return;
this._data = {
text,
dataText: toDataText(dataText),
type,
};
const { timeout } = this;
if (timeout === -1) return;
const timer = setTimeout(this.clear, timeout);
this._disposer = () => clearTimeout(timer);
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment