huytrongnguyen / rosie

MIT License
0 stars 0 forks source link

DataModel enhancement #14

Open huytrongnguyen opened 6 months ago

huytrongnguyen commented 6 months ago
import { AjaxError, HttpParams } from '../types';
import { Subject } from '../observable';
import { ProxyConfig, ajaxRequest } from './proxy';

type CrudState = 'C' | 'R' | 'U' | 'D';

export class DataModel<T> extends Subject<T> {
  constructor(public config?: ProxyConfig<T>) { super(); }

  static create<T = any>(data: T, crudState: CrudState = 'R') {
    const record = new DataModel<T>();
    record.loadData(data);
    record.crudState = crudState;
    return record;
  }

  selected = false; setSelected(value: boolean) { this.selected = value; this.trigger('select'); }

  isModified(fieldName: string) { return this?.origin?.[fieldName] !== this?.value?.[fieldName]; }
  isPhantom() { return this.crudState === 'C'; }
  isDropped() { return this.crudState === 'D'; }

  get<T = any>(fieldName: string) { return this.value?.[fieldName] as T; }
  set(fieldName: string, newValue: any) {if (this.value[fieldName] !== newValue) { super.next({ ...this.value, [fieldName]: newValue }) } }
  drop() { this.prevState = this.crudState; this.crudState = 'D'; this.trigger('drop'); }
  putBack() { this.crudState = this.prevState; this.trigger('putBack'); }

  getData() { return this.value; }
  loadData(data: T) { super.next(data); this.origin = JSON.parse(JSON.stringify(data)); }

  load(params?: HttpParams, onError?: (_reason: AjaxError) => T, onComplete?: () => void) {
    this.fetch(params, onError, onComplete).then((value: T) => value && this.loadData(value));
  }

  fetch(params?: HttpParams, onError?: (_reason: AjaxError) => T, onComplete?: () => void) {
    return ajaxRequest<T>(this.config, params).catch(onError).finally(onComplete);
  }

  private origin: T;
  private crudState: CrudState = 'R';
  private prevState: CrudState = 'R';
  // "R" - The record is in a cleanly retrieved (unmodified) state.
  // "C" - The record is in a newly created (phantom) state.
  // "U" - The record is in an updated, modified (dirty) state.
  // "D" - The record is in a dropped state.

}
huytrongnguyen commented 6 months ago

How to pass header to ajax request?

import { Ajax, AjaxError, DataModel, DataStore, HttpParams, LocalCache, ProxyConfig, Rosie, StoreConfig } from 'rosie';

export const JWT_TOKEN = 'jwtToken';

const verifyUrl = '/api/auth/verify',
      loginUrl = `/sso/login?redirectUri=/callback`,
      AUTH_TOKEN_KEY = 'x-auth-token';

export function redirectToLogin() {
  LocalCache.remove(JWT_TOKEN);
  location.href = loginUrl;
}

export function verifyAuthToken<T = any>() {
  return Ajax.request<T>({ url: verifyUrl })
}

export function onAjaxError(reason: AjaxError) {
  // console.error(reason);
  if (reason?.response?.status == 401) redirectToLogin();
  const message = reason?.response?.data?.message;
  if (message) Rosie.alertError(message);
  return null;
}

export function onAjaxComplete() { Rosie.afterProcessing(); }

export class AuthDataModel<T> extends DataModel<T> {
  fetch(params: HttpParams = {}, onError?: (_reason: AjaxError) => T, onComplete?: () => void) {
    if (!params.headers) params.headers = {};
    params.headers[AUTH_TOKEN_KEY] = LocalCache.get(JWT_TOKEN);
    return super.fetch(params, onError ?? onAjaxError, onComplete ?? onAjaxComplete);
  }
}

export const Model = <T = any>(config?: ProxyConfig<T>) => new AuthDataModel<T>(config);

export class AuthDataStore<T> extends DataStore<T> {
  fetch(params: HttpParams = {}, onError?: (_reason: AjaxError) => T[], onComplete?: () => void) {
    if (!params.headers) params.headers = {};
    params.headers[AUTH_TOKEN_KEY] = LocalCache.get(JWT_TOKEN);
    return super.fetch(params, onError ?? onAjaxError, onComplete ?? onAjaxComplete);
  }
}

export const Store = <T = any>(config?: StoreConfig<T>) => new AuthDataStore<T>(config);