Skip to content

Instantly share code, notes, and snippets.

@HereComesJuju
Forked from mrcrowl/basket.ts
Created September 13, 2019 19:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save HereComesJuju/b7200a906b4bb0df3236bb005c46baf0 to your computer and use it in GitHub Desktop.
Save HereComesJuju/b7200a906b4bb0df3236bb005c46baf0 to your computer and use it in GitHub Desktop.
Example of using vuex-type to create strongly-typed vuex store access
// path: store/basket/basket.ts (module)
import { RootState } from "../../store"
import inventory, { Product } from "../inventory/inventory"
export interface Item { productId: string, quantity: number }
export interface DisplayItem { product: Product, quantity: number }
export interface BasketState { items: Item[], isLoading: boolean }
const initialBasketState: BasketState = { items: [], isLoading: false }
const b = getStoreBuilder<RootState>().module("basket", initialBasketState)
// getters
const numberOfItemsGetter = b.read(state => state.items.length, "numberOfItems")
const itemsGetter = b.read(state =>
{
const displayItems: DisplayItem[] = state.items.map(item =>
{
return {
product: inventory.getProductById(item.productId),
quantity: item.quantity
}
})
return displayItems
})
// mutations
function appendItem(state: BasketState, payload: { productId: string, quantity: number })
{
state.items.push({
productId: payload.productId,
quantity: payload.quantity
})
}
function setIsLoading(state: BasketState, payload: { isLoading: boolean })
{
state.isLoading = payload.isLoading
}
// action
async function restoreSavedBasket(context: BareActionContext<BasketState, RootState>)
{
const savedBasketId = localStorage["basketId"]
try
{
basket.commitSetIsLoading({ isLoading: true })
const { data: savedBasket } = await axios.get(`//chips-store.com/get-saved-basket/${savedBasketId}`, { responseType: "json" })
const items: Item[] = savedBasket.items
items.forEach(item => basket.commitAppendItem(item))
}
finally
{
basket.commitSetIsLoading({ isLoading: false })
}
}
// state
const stateGetter = b.state()
// exported "basket" module interface
const basket = {
// state
get state() { return stateGetter() },
// getters (wrapped as real getters)
get items() { return itemsGetter() },
get numberOfItems() { return numberOfItemsGetter() },
// mutations
commitAppendItem: b.commit(appendItem),
commitSetIsLoading: b.commit(setIsLoading),
// actions
dispatchRestoreSavedBasket: b.dispatch(restoreSavedBasket)
}
export default basket
// path: store/inventory/inventory.ts (module)
import { getStoreBuilder, BaseActionContext } from "vuex-typex"
import { Store } from "vuex"
import { RootState } from "../../store"
import axios from "axios"
export interface InventoryState { productsById: { [productId: string]: Product } }
export interface Product { id: string, name: string }
const initialInventoryState: InventoryState = {
productsById: {
"fritos": { id: "fritos", name: "Fritos Corn Chips, Chili Cheese" },
"doritos": { id: "doritos", name: "Doritos Nacho Cheese Flavored Tortilla Chips" },
"cheetos": { id: "cheetos", name: "Cheetos Crunchy Cheese Flavored Snacks" },
"tostitos": { id: "tostitos", name: "Tostitos Original Restaurant Style Tortilla Chips" }
}
}
const p = getStoreBuilder<RootState>().module("product", initialInventoryState)
const getProductByIdGetter = p.read(state => (id: string) => state.productsById[id], "getProductById")
// state
const stateGetter = p.state()
// exported "inventory" module interface
const inventory = {
// state
get state() { return stateGetter() },
// getter as method
getProductById(id: string)
{
return getProductByIdGetter()(id)
}
}
export default inventory
// path: store/store.ts (root store definition)
import Vue from 'vue'
import Vuex, { Store } from 'vuex'
import inventory from "./inventory/inventory"
import basket from "./basket/basket"
export interface RootState
{
basket: BasketState
inventory: InventoryState
}
Vue.use(Vuex)
const store: Store<RootState> = getStoreBuilder<RootState>().vuexStore()
export default store // <-- "store" to provide to root Vue
// path: app.ts (root Vue)
import Vue from 'vue'
import Vuex from 'vuex'
import store from './store/store'
import app_html from './app.html'
const app = new Vue({
el: '#app',
template: app_html,
store
})
export default app
// path: components/basket/basketDisplay.ts (component)
import basket from "../../store/basket/basket"
@Component({ template: basket_display_html })
export class BasketDisplay extends Vue
{
get isLoading() { return basket.state.isLoading }
get items() { return basket.items }
get numberOfItems() { return basket.numberOfItems }
restoreSavedBasket()
{
basket.dispatchRestoreSavedBasket()
}
addToBasket(productId: string, quantity: number = 1)
{
basket.commitAppendItem({ productId, quantity })
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment