Advertisement
Guest User

Untitled

a guest
Jul 10th, 2018
79
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. import "../common/sw-init"
  2. import { createStore, applyMiddleware, compose } from "redux"
  3. import { createRedutser } from "redutser"
  4. import thunkMw from "redux-thunk"
  5. import { ajaxRequest, url } from "../common/site"
  6. import { createEffects } from "@proerd/nextpress-client/built/connext"
  7. import { asyncThunkErrorMw } from "@proerd/nextpress-client/built/error"
  8. import { groupBy, toPairs } from "lodash"
  9. import { serviceWorker } from "../common/sw-init"
  10.  
  11. const initialState = {
  12.   newRule: undefined as undefined | Rule_Client,
  13.   ruleList: [] as Rule_Client[],
  14.   showUserDropdown: false,
  15.   error: undefined as string | undefined,
  16.   selectedTab: "rules" as "rules" | "realms" | "scan" | "options",
  17.   newRealm: undefined as undefined | NewRealm,
  18.   realmList: [] as NewRealm[],
  19.   scanTab: undefined as
  20.     | undefined
  21.     | {
  22.         results: [string, ScanResult[]][]
  23.       },
  24.   settings: undefined as
  25.     | undefined
  26.     | {
  27.         form: { optEmailNotifications: boolean; optBrowserNotifications: boolean }
  28.         isSaving?: 1 | 2
  29.       },
  30. }
  31.  
  32. type NewRealm = { name: string; slug: string; alliance: boolean; horde: boolean }
  33.  
  34. type Rule_Client = {
  35.   id?: number
  36.   itemId?: number
  37.   _itemName?: string
  38.   type?: string
  39.   value?: string
  40. }
  41.  
  42. export type ScanResult = {
  43.   type: string
  44.   slug: string
  45.   realmName: string
  46.   faction: 0 | 1
  47.   itemId: number
  48.   value: number
  49.   _itemName: string
  50.   stockFound?: number
  51.   minimumFound?: number
  52. }
  53.  
  54. type ScanApiResponse = {
  55.   results: ScanResult[]
  56. }
  57.  
  58. type SettingsApiResponse = {
  59.   settings: { optEmailNotifications: boolean; optBrowserNotifications: boolean }
  60. }
  61.  
  62. export const root = createRedutser(initialState, {
  63.   newRule_init: state => ({
  64.     ...state,
  65.     newRule: { itemId: undefined, rule: undefined },
  66.   }),
  67.   newRule_setField: (
  68.     state,
  69.     action: {
  70.       field: keyof NonNullable<typeof initialState["newRule"]>
  71.       val: string
  72.     },
  73.   ) => {
  74.     return {
  75.       ...state,
  76.       newRule: state.newRule && { ...state.newRule, [action.field]: action.val },
  77.     }
  78.   },
  79.   newRule_hide: state => ({
  80.     ...state,
  81.     newRule: undefined,
  82.   }),
  83.   toggleUserDropdown: state => ({
  84.     ...state,
  85.     showUserDropdown: !state.showUserDropdown,
  86.   }),
  87.   ruleList_replace: (state, act: { rules: Rule_Client[] }) => {
  88.     return {
  89.       ...state,
  90.       ruleList: act.rules || [],
  91.     }
  92.   },
  93.   removeRule: (state, act: { id: number }) => ({
  94.     ...state,
  95.     ruleList: state.ruleList.filter(r => r.id !== act.id),
  96.   }),
  97.   setTab: (state, tab: typeof initialState["selectedTab"]) => ({
  98.     ...state,
  99.     selectedTab: tab,
  100.   }),
  101.   error: (state, action: { error: any }) => {
  102.     console.log(action.error)
  103.     return {
  104.       ...state,
  105.       error: action.error,
  106.     }
  107.   },
  108.   newRealm_init: state => ({
  109.     ...state,
  110.     newRealm: {
  111.       name: "",
  112.       slug: "",
  113.       alliance: false,
  114.       horde: false,
  115.     },
  116.   }),
  117.   newRealm_set: (state, act: Partial<NewRealm>) => ({
  118.     ...state,
  119.     newRealm: state.newRealm && { ...state.newRealm, ...act },
  120.   }),
  121.   newRealm_hide: state => ({
  122.     ...state,
  123.     newRealm: undefined,
  124.   }),
  125.   realmList_replace: (state, act: { realms: NewRealm[] }) => ({
  126.     ...state,
  127.     realmList: act.realms || [],
  128.   }),
  129.   realmList_remove: (state, act: { slug: string }) => ({
  130.     ...state,
  131.     realmList: state.realmList.filter(r => r.slug !== act.slug),
  132.   }),
  133.   scanTab_empty: state => ({
  134.     ...state,
  135.     scanTab: undefined,
  136.   }),
  137.   scanTab_replace: (state, act: { results: Record<string, ScanResult[]> }) => ({
  138.     ...state,
  139.     scanTab: {
  140.       results: toPairs(act.results),
  141.     },
  142.   }),
  143.   settings_set: (state, act: { settings: SettingsApiResponse["settings"] }) => ({
  144.     ...state,
  145.     settings: {
  146.       form: act.settings,
  147.       isSaving: state.settings && state.settings.isSaving,
  148.     },
  149.   }),
  150.   settings_isSaving: (state, act: undefined | 1 | 2) => {
  151.     return {
  152.       ...state,
  153.       settings: state.settings && { ...state.settings, isSaving: act },
  154.     }
  155.   },
  156. })
  157.  
  158. export const effects = createEffects(root)({
  159.   // - rules -
  160.   reloadRules: () => async dispatch => {
  161.     let res = await ajaxRequest<{ rules: any }>({
  162.       url: url("/api/rule/list"),
  163.       method: "POST",
  164.       body: {},
  165.     })
  166.     let rules = res.rules || []
  167.     dispatch(root.creators.ruleList_replace({ rules }))
  168.   },
  169.   createRule: () => async (dispatch, getState) => {
  170.     let state = getState().newRule!
  171.     let rule = {
  172.       type: state.type,
  173.       itemId: state.itemId,
  174.       value: state.value,
  175.     }
  176.     await ajaxRequest({
  177.       url: url("/api/rule/create"),
  178.       method: "POST",
  179.       body: rule,
  180.     })
  181.     dispatch(root.creators.newRule_hide({}))
  182.     await effects.reloadRules()(dispatch)
  183.   },
  184.   removeRule: (id: number) => async dispatch => {
  185.     await ajaxRequest({
  186.       url: url("/api/rule/remove"),
  187.       method: "POST",
  188.       body: { id },
  189.     })
  190.     dispatch(root.creators.removeRule({ id }))
  191.   },
  192.   // - realms -
  193.   reloadRealms: () => async dispatch => {
  194.     let resp = await ajaxRequest<{ realms: NewRealm[] }>({
  195.       url: url("/api/realm/list"),
  196.       method: "POST",
  197.       body: {},
  198.     })
  199.     dispatch(root.creators.realmList_replace({ realms: resp.realms }))
  200.   },
  201.   addRealm: () => async (dispatch, getState) => {
  202.     let state = getState().newRealm!
  203.     await ajaxRequest({
  204.       url: url("/api/realm/create"),
  205.       method: "POST",
  206.       body: state,
  207.     })
  208.     dispatch(root.creators.newRealm_hide({}))
  209.     await effects.reloadRealms()(dispatch)
  210.   },
  211.   removeRealm: (slug: string) => async dispatch => {
  212.     await ajaxRequest({
  213.       url: url("/api/realm/remove"),
  214.       method: "POST",
  215.       body: { slug },
  216.     })
  217.     dispatch(root.creators.realmList_remove({ slug }))
  218.   },
  219.   loadTab: (tab: typeof initialState["selectedTab"]) => async (dispatch, getState) => {
  220.     dispatch(root.creators.setTab(tab))
  221.     if (tab === "scan") {
  222.       await effects.refreshScanTab()(dispatch)
  223.     }
  224.     if (typeof window !== "undefined") {
  225.       window.history.pushState({}, "", url("/dashboard", { tab }))
  226.     }
  227.   },
  228.   refreshScanTab: () => async dispatch => {
  229.     dispatch(root.creators.scanTab_empty({}))
  230.     let { results } = await ajaxRequest<ScanApiResponse>({
  231.       url: url("/api/scan"),
  232.       method: "POST",
  233.       body: {},
  234.     })
  235.     let grouped = groupBy(results, (item: ScanResult) => item.realmName + ":" + item.faction)
  236.     dispatch(root.creators.scanTab_replace({ results: grouped }))
  237.   },
  238.   loadUserSettings: () => async (dispatch, getState) => {
  239.     console.log("loadusersettings")
  240.     if (getState().settings) return
  241.     let { settings } = await ajaxRequest<SettingsApiResponse>({
  242.       url: url("/api/settings/view"),
  243.       method: "POST",
  244.       body: {},
  245.     })
  246.     dispatch(root.creators.settings_set({ settings }))
  247.     if (settings.optBrowserNotifications) {
  248.       let sw = await serviceWorker().init()
  249.       if (!sw) {
  250.         console.log("Unable to initialize service worker")
  251.         return
  252.       }
  253.       let subscription = await sw.getSubscription()
  254.       if (!subscription) {
  255.         console.log("unable to get subscription")
  256.         return
  257.       }
  258.       let _subscription = subscription.toJSON()
  259.       await ajaxRequest({
  260.         url: url("/api/insert-push-subscription"),
  261.         method: "POST",
  262.         body: {
  263.           endpoint: _subscription.endpoint,
  264.           auth: _subscription.keys.auth,
  265.           p256dh: _subscription.keys.p256dh,
  266.         },
  267.       })
  268.       console.log("updated push subscription for this session")
  269.     }
  270.   },
  271.   setUserSettings: (opts: SettingsApiResponse["settings"]) => async (dispatch, getState) => {
  272.     let prev = getState().settings!.form
  273.     if (!prev) {
  274.       await effects.loadUserSettings()(dispatch, getState)
  275.       prev = getState().settings!.form
  276.     }
  277.     dispatch(root.creators.settings_isSaving(1))
  278.     await Promise.all([
  279.       ajaxRequest({
  280.         url: url("/api/settings/update"),
  281.         method: "POST",
  282.         body: { settings: opts },
  283.       }),
  284.       new Promise(res => setTimeout(res, 1000)),
  285.     ])
  286.     dispatch(root.creators.settings_isSaving(2))
  287.     setTimeout(() => {
  288.       dispatch(root.creators.settings_isSaving(undefined))
  289.     }, 3000)
  290.     if (prev!.optBrowserNotifications && opts.optBrowserNotifications) {
  291.       if (typeof Notification !== "undefined" && (Notification as any).permission !== "granted") {
  292.         await Notification.requestPermission()
  293.       }
  294.     }
  295.     dispatch(root.creators.settings_set({ settings: opts }))
  296.   },
  297.   unsubscribePush: () => async () => {
  298.     let sw = await serviceWorker().init()
  299.     if (!sw) return
  300.     await sw.unsubscribe()
  301.   },
  302. })
  303.  
  304. const composeEnhancers =
  305.   (typeof window !== "undefined" && window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__) || compose
  306.  
  307. export const store = createStore(
  308.   root.reducer,
  309.   composeEnhancers(applyMiddleware(asyncThunkErrorMw(), thunkMw)),
  310. )
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement