forked from M-Labs/web2019
Cache total price calculation
Signed-off-by: Egor Savkin <es@m-labs.hk>
This commit is contained in:
parent
4527189994
commit
15d9124025
61763
static/js/shop.bundle.js
61763
static/js/shop.bundle.js
File diff suppressed because one or more lines are too long
|
@ -3,11 +3,10 @@ import {Cart} from "./Cart";
|
||||||
import {CrateMode} from "./CrateMode";
|
import {CrateMode} from "./CrateMode";
|
||||||
import {CrateWarnings} from "./CrateWarnings";
|
import {CrateWarnings} from "./CrateWarnings";
|
||||||
import {useShopStore} from "./shop_store";
|
import {useShopStore} from "./shop_store";
|
||||||
|
import {CrateOptions} from "./CrateOptions";
|
||||||
|
|
||||||
// #!render_count
|
// #!render_count
|
||||||
import {useRenderCount} from "@uidotdev/usehooks";
|
import {useRenderCount} from "@uidotdev/usehooks";
|
||||||
import {CrateFanTray} from "./CrateFanTray";
|
|
||||||
import {CrateOptions} from "./CrateOptions";
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,37 +0,0 @@
|
||||||
import React from 'react';
|
|
||||||
|
|
||||||
import {useShopStore} from "./shop_store";
|
|
||||||
import {Tip} from "./options/components/Tip";
|
|
||||||
import {formatMoney} from "./utils";
|
|
||||||
|
|
||||||
export function CrateFanTray({crate_index}) {
|
|
||||||
const currency = useShopStore((state) => state.currency);
|
|
||||||
const fanTray = useShopStore((state) => state.fanTray);
|
|
||||||
const crate_id = useShopStore((state) => state.crates[crate_index].id);
|
|
||||||
const fanTrayAvailable = useShopStore((state) => state.fanTrayAvailableByIndex(crate_index));
|
|
||||||
const fanTrayEnabled = useShopStore((state) => state.crates[crate_index].fan_tray);
|
|
||||||
const updateFanTray = useShopStore((state) => state.updateFanTrayOption);
|
|
||||||
|
|
||||||
const base_id = crate_id + "fan_tray";
|
|
||||||
return fanTrayAvailable ? (
|
|
||||||
<div className="crate-bar">
|
|
||||||
<div className="shop-switch">
|
|
||||||
<div className="form-check form-switch">
|
|
||||||
<input
|
|
||||||
className="form-check-input"
|
|
||||||
type="checkbox"
|
|
||||||
role="switch"
|
|
||||||
id={base_id}
|
|
||||||
checked={fanTrayEnabled}
|
|
||||||
onClick={() => updateFanTray(crate_id, !fanTrayEnabled)}
|
|
||||||
onChange={() => updateFanTray(crate_id, !fanTrayEnabled)}
|
|
||||||
/>
|
|
||||||
<label className="form-check-label" htmlFor={base_id} style={{"display": "inline", marginRight: "0.125rem"}}>
|
|
||||||
{fanTray.optionTitle} (+{`${currency} ${formatMoney(fanTray.price)}`})
|
|
||||||
</label>
|
|
||||||
{fanTray.tip && <Tip id={base_id + "tooltip"} tip={fanTray.tip}/>}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
) : null
|
|
||||||
}
|
|
|
@ -9,8 +9,6 @@ export function CrateOptions({crate_index}) {
|
||||||
const updateOptions = useShopStore((state) => state.updateCrateOptions);
|
const updateOptions = useShopStore((state) => state.updateCrateOptions);
|
||||||
const options_data = useShopStore((state) => state.crates[crate_index].options_data || {});
|
const options_data = useShopStore((state) => state.crates[crate_index].options_data || {});
|
||||||
|
|
||||||
console.log(options_data)
|
|
||||||
|
|
||||||
const options = ProcessOptions({
|
const options = ProcessOptions({
|
||||||
options: optionsLogic,
|
options: optionsLogic,
|
||||||
data: options_data,
|
data: options_data,
|
||||||
|
@ -33,8 +31,6 @@ export function CrateOptions({crate_index}) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log(options)
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="crate-bar">
|
<div className="crate-bar">
|
||||||
{options}
|
{options}
|
||||||
|
|
|
@ -1,45 +0,0 @@
|
||||||
import {formatMoney} from "./utils";
|
|
||||||
import React from "react";
|
|
||||||
import {useShopStore} from "./shop_store";
|
|
||||||
|
|
||||||
// #!render_count
|
|
||||||
import {useRenderCount} from "@uidotdev/usehooks";
|
|
||||||
|
|
||||||
|
|
||||||
export function SummaryCrateFanTray({crate_index}) {
|
|
||||||
// #!render_count
|
|
||||||
const renderCount = useRenderCount();
|
|
||||||
|
|
||||||
const currency = useShopStore((state) => state.currency);
|
|
||||||
const fanTray = useShopStore((state) => state.fanTray);
|
|
||||||
const crate_id = useShopStore((state) => state.crates[crate_index].id);
|
|
||||||
const fanTrayAvailable = useShopStore((state) => state.fanTrayAvailableByIndex(crate_index));
|
|
||||||
const fanTrayEnabled = useShopStore((state) => state.crates[crate_index].fan_tray);
|
|
||||||
const updateFanTray = useShopStore((state) => state.updateFanTrayOption);
|
|
||||||
|
|
||||||
|
|
||||||
// #!render_count
|
|
||||||
console.log("SummaryCrateCard renders: ", renderCount)
|
|
||||||
|
|
||||||
return (fanTrayAvailable && fanTrayEnabled) ? (<tr
|
|
||||||
key={"summary_crate_" + crate_id + "_fan_tray"}>
|
|
||||||
<td className="item-card-name">
|
|
||||||
<span style={{
|
|
||||||
'display': 'inline-block', 'width': '16px',
|
|
||||||
}}> </span>
|
|
||||||
<div>{fanTray.optionTitle}</div>
|
|
||||||
</td>
|
|
||||||
|
|
||||||
<td className="price">
|
|
||||||
<div className="d-inline-flex align-content-center">
|
|
||||||
{`${currency} ${formatMoney(fanTray.price)}`}
|
|
||||||
|
|
||||||
<button onClick={() => updateFanTray(crate_id, false)}>
|
|
||||||
<img src="/images/shop/icon-remove.svg" className="d-block"/>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<div style={{'width': '45px', 'height': '20px'}} className="d-inline"></div>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>) : null;
|
|
||||||
}
|
|
|
@ -18,8 +18,6 @@ export function SummaryCratePricedOptions({crate_index}) {
|
||||||
|
|
||||||
const options = ProcessOptionsToData({options: optionsPrices, data: options_data});
|
const options = ProcessOptionsToData({options: optionsPrices, data: options_data});
|
||||||
|
|
||||||
console.log(options, options_data, optionsPrices)
|
|
||||||
|
|
||||||
// #!render_count
|
// #!render_count
|
||||||
console.log("SummaryCratePricedOptions renders: ", renderCount)
|
console.log("SummaryCratePricedOptions renders: ", renderCount)
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ import React from "react";
|
||||||
|
|
||||||
export function SummaryTotalPrice() {
|
export function SummaryTotalPrice() {
|
||||||
const currency = useShopStore((state) => state.currency);
|
const currency = useShopStore((state) => state.currency);
|
||||||
const total_price = useShopStore((state) => state.totalOrderPrice());
|
const total_price = useShopStore((state) => state.total_order_price);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
|
|
|
@ -36,12 +36,11 @@ export function JSONToCrates(description) {
|
||||||
const parsed = JSON.parse(description);
|
const parsed = JSON.parse(description);
|
||||||
const crates_raw = parsed.crates;
|
const crates_raw = parsed.crates;
|
||||||
const pn_to_card = useShopStore.getState().getCardDescriptionByPn;
|
const pn_to_card = useShopStore.getState().getCardDescriptionByPn;
|
||||||
const fanTrayAvailable = useShopStore.getState().fanTrayAvailableForMode;
|
|
||||||
|
|
||||||
const crates = Array.from(crates_raw.map((crate, c_i) => ({
|
const crates = Array.from(crates_raw.map((crate, c_i) => ({
|
||||||
id: crate.type === "no_crate" ? "spare" : "crate" + c_i,
|
id: crate.type === "no_crate" ? "spare" : "crate" + c_i,
|
||||||
name: crate.type === "no_crate" ? "Spare cards" : undefined,
|
name: crate.type === "no_crate" ? "Spare cards" : undefined,
|
||||||
fan_tray: fanTrayAvailable(crate.type) && crate.fan_tray === true,
|
options_data: crate.options,
|
||||||
crate_mode: crate.type,
|
crate_mode: crate.type,
|
||||||
items: Array.from(crate.items.map((card, _i) => ({
|
items: Array.from(crate.items.map((card, _i) => ({
|
||||||
...pn_to_card(card.pn),
|
...pn_to_card(card.pn),
|
||||||
|
@ -59,7 +58,7 @@ export function JSONToCrates(description) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function CratesToJSON(crates) {
|
export function CratesToJSON(crates) {
|
||||||
const fanTrayAvailable = useShopStore.getState().fanTrayAvailableForMode;
|
const crateOptions = useShopStore.getState().crate_options;
|
||||||
return JSON.stringify({
|
return JSON.stringify({
|
||||||
// additional fields can go here
|
// additional fields can go here
|
||||||
crates: Array.from(crates.map((crate, _i) => ({
|
crates: Array.from(crates.map((crate, _i) => ({
|
||||||
|
@ -68,7 +67,7 @@ export function CratesToJSON(crates) {
|
||||||
options: (card.options_data && card.options) ? FilterOptions(card.options, card.options_data) : null
|
options: (card.options_data && card.options) ? FilterOptions(card.options, card.options_data) : null
|
||||||
}))),
|
}))),
|
||||||
type: crate.crate_mode,
|
type: crate.crate_mode,
|
||||||
fan_tray: (!fanTrayAvailable(crate.crate_mode) ? undefined : true) && crate.fan_tray
|
options: FilterOptions(crateOptions, crate.options_data)
|
||||||
})))
|
})))
|
||||||
}, null, 2)
|
}, null, 2)
|
||||||
}
|
}
|
|
@ -9,6 +9,8 @@ import {FillExtCardData} from "./options/utils";
|
||||||
import {TriggerCrateWarnings, TriggerWarnings} from "./warnings";
|
import {TriggerCrateWarnings, TriggerWarnings} from "./warnings";
|
||||||
import {Validation, validateEmail, validateNote, validateJSONInput} from "./validate";
|
import {Validation, validateEmail, validateNote, validateJSONInput} from "./validate";
|
||||||
import {CratesToJSON, JSONToCrates} from "./json_porter";
|
import {CratesToJSON, JSONToCrates} from "./json_porter";
|
||||||
|
import {ProcessOptionsToData} from "./options/Options";
|
||||||
|
import {forEach} from "react-bootstrap/ElementChildren";
|
||||||
|
|
||||||
|
|
||||||
const cards_to_pn_map = (cards) => {
|
const cards_to_pn_map = (cards) => {
|
||||||
|
@ -58,13 +60,6 @@ const useCrateOptions = ((set, get) => ({
|
||||||
crates: state.crates.map((crate, _i) => {
|
crates: state.crates.map((crate, _i) => {
|
||||||
if (crate_id === crate.id) {
|
if (crate_id === crate.id) {
|
||||||
const previous_options = crate.options_data || {};
|
const previous_options = crate.options_data || {};
|
||||||
console.log(crate_id, new_options, {
|
|
||||||
...crate,
|
|
||||||
options_data: {
|
|
||||||
...previous_options,
|
|
||||||
...new_options
|
|
||||||
}
|
|
||||||
})
|
|
||||||
return {
|
return {
|
||||||
...crate,
|
...crate,
|
||||||
options_data: {
|
options_data: {
|
||||||
|
@ -80,6 +75,7 @@ const useCrateOptions = ((set, get) => ({
|
||||||
updateCrateOptions: (crate_id, new_options) => {
|
updateCrateOptions: (crate_id, new_options) => {
|
||||||
get().fillExtCrateData(crate_id);
|
get().fillExtCrateData(crate_id);
|
||||||
get()._updateCrateOption(crate_id, new_options);
|
get()._updateCrateOption(crate_id, new_options);
|
||||||
|
get()._updateTotalOrderPrice();
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
@ -101,6 +97,7 @@ const useOrderOptions = ((set, get) => ({
|
||||||
updateOrderOptions: (new_options) => {
|
updateOrderOptions: (new_options) => {
|
||||||
get().fillOrderExtData();
|
get().fillOrderExtData();
|
||||||
get()._updateOrderOptions(new_options);
|
get()._updateOrderOptions(new_options);
|
||||||
|
get()._updateTotalOrderPrice();
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
@ -158,9 +155,11 @@ const useImportJSON = ((set, get) => ({
|
||||||
loadDescription: () => {
|
loadDescription: () => {
|
||||||
get()._loadDescription()
|
get()._loadDescription()
|
||||||
get().crates.forEach((crate, _i) => {
|
get().crates.forEach((crate, _i) => {
|
||||||
get().fillExtData(crate.id)
|
get().fillExtData(crate.id);
|
||||||
get().fillWarnings(crate.id)
|
get().fillWarnings(crate.id);
|
||||||
})
|
get().fillExtCrateData(crate.id);
|
||||||
|
});
|
||||||
|
get()._updateTotalOrderPrice();
|
||||||
},
|
},
|
||||||
updateImportDescription: (new_description) => set(state => ({
|
updateImportDescription: (new_description) => set(state => ({
|
||||||
importValue: {
|
importValue: {
|
||||||
|
@ -309,6 +308,7 @@ const useCart = ((set, get) => ({
|
||||||
crates: shared_data.columns.crates,
|
crates: shared_data.columns.crates,
|
||||||
active_crate: "crate0",
|
active_crate: "crate0",
|
||||||
_defaultCrates: Array.from(shared_data.columns.crates),
|
_defaultCrates: Array.from(shared_data.columns.crates),
|
||||||
|
total_order_price: 0,
|
||||||
|
|
||||||
_newCrate: (crate_id) => set((state) => ({
|
_newCrate: (crate_id) => set((state) => ({
|
||||||
crates: state.crates.toSpliced(-1, 0, {
|
crates: state.crates.toSpliced(-1, 0, {
|
||||||
|
@ -461,17 +461,18 @@ const useCart = ((set, get) => ({
|
||||||
})
|
})
|
||||||
})),
|
})),
|
||||||
|
|
||||||
totalOrderPrice: () => {
|
_updateTotalOrderPrice: () => set(state => {
|
||||||
let sum = 0;
|
let sum = 0;
|
||||||
get().crates.forEach( (crate, i) => {
|
get().crates.forEach( (crate, i) => {
|
||||||
sum += get().crate_modes[crate.crate_mode].price;
|
sum += get().crate_modes[crate.crate_mode].price;
|
||||||
sum += (crate.fan_tray && get().fanTrayAvailableByIndex(i)) ? get().fanTray.price : 0;
|
const crate_options = ProcessOptionsToData({options: get().crate_prices, data: crate.options_data || {}});
|
||||||
|
sum += crate_options ? crate_options.reduce((accumulator, currentValue) => accumulator+currentValue.price, 0) : 0;
|
||||||
crate.items.forEach((item, _) => {
|
crate.items.forEach((item, _) => {
|
||||||
sum += item.price;
|
sum += item.price;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
return sum;
|
return {total_order_price: sum};
|
||||||
},
|
}),
|
||||||
|
|
||||||
// Composite actions that require warnings recalculation:
|
// Composite actions that require warnings recalculation:
|
||||||
|
|
||||||
|
@ -481,6 +482,7 @@ const useCart = ((set, get) => ({
|
||||||
get().fillExtData(crate_id);
|
get().fillExtData(crate_id);
|
||||||
get().fillExtCrateData(crate_id);
|
get().fillExtCrateData(crate_id);
|
||||||
get().fillWarnings(crate_id);
|
get().fillWarnings(crate_id);
|
||||||
|
get()._updateTotalOrderPrice();
|
||||||
},
|
},
|
||||||
|
|
||||||
setCrateMode: (id, mode) => {
|
setCrateMode: (id, mode) => {
|
||||||
|
@ -489,6 +491,7 @@ const useCart = ((set, get) => ({
|
||||||
get().fillExtCrateData(id);
|
get().fillExtCrateData(id);
|
||||||
get().fillWarnings(id);
|
get().fillWarnings(id);
|
||||||
get().setActiveCrate(id);
|
get().setActiveCrate(id);
|
||||||
|
get()._updateTotalOrderPrice();
|
||||||
},
|
},
|
||||||
|
|
||||||
addCardFromBacklog: (crate_to, index_from, index_to, just_mounted) => {
|
addCardFromBacklog: (crate_to, index_from, index_to, just_mounted) => {
|
||||||
|
@ -502,6 +505,7 @@ const useCart = ((set, get) => ({
|
||||||
get().fillExtData(dest);
|
get().fillExtData(dest);
|
||||||
get().fillWarnings(dest);
|
get().fillWarnings(dest);
|
||||||
get().setActiveCrate(dest);
|
get().setActiveCrate(dest);
|
||||||
|
get()._updateTotalOrderPrice();
|
||||||
if (!just_mounted) {
|
if (!just_mounted) {
|
||||||
get().cardAdded()
|
get().cardAdded()
|
||||||
}
|
}
|
||||||
|
@ -512,6 +516,7 @@ const useCart = ((set, get) => ({
|
||||||
get().fillExtData(crate_to);
|
get().fillExtData(crate_to);
|
||||||
get().fillWarnings(crate_to);
|
get().fillWarnings(crate_to);
|
||||||
get().setActiveCrate(crate_to);
|
get().setActiveCrate(crate_to);
|
||||||
|
get()._updateTotalOrderPrice();
|
||||||
if (crate_from !== crate_to) {
|
if (crate_from !== crate_to) {
|
||||||
get().fillExtData(crate_from);
|
get().fillExtData(crate_from);
|
||||||
get().fillWarnings(crate_from);
|
get().fillWarnings(crate_from);
|
||||||
|
@ -521,6 +526,7 @@ const useCart = ((set, get) => ({
|
||||||
get()._deleteCard(crate_id, index);
|
get()._deleteCard(crate_id, index);
|
||||||
get().fillExtData(crate_id);
|
get().fillExtData(crate_id);
|
||||||
get().fillWarnings(crate_id);
|
get().fillWarnings(crate_id);
|
||||||
|
get()._updateTotalOrderPrice();
|
||||||
if (crate_id === get().highlighted.crate && index === get().highlighted.card) get().highlightReset()
|
if (crate_id === get().highlighted.crate && index === get().highlighted.card) get().highlightReset()
|
||||||
},
|
},
|
||||||
clearCrate: (id) => {
|
clearCrate: (id) => {
|
||||||
|
@ -534,28 +540,13 @@ const useCart = ((set, get) => ({
|
||||||
get().fillWarnings(crate_id);
|
get().fillWarnings(crate_id);
|
||||||
},
|
},
|
||||||
|
|
||||||
updateFanTrayOption: (crate_id, add_fan_tray) => set(state => ({
|
|
||||||
crates: state.crates.map((crate, _i) => {
|
|
||||||
if (crate_id === crate.id) {
|
|
||||||
return {
|
|
||||||
...crate,
|
|
||||||
fan_tray: add_fan_tray
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else return crate;
|
|
||||||
})
|
|
||||||
})),
|
|
||||||
|
|
||||||
fanTrayAvailableByIndex: (crate_index) => {
|
|
||||||
return get().fanTrayAvailableForMode(get().crates[crate_index].crate_mode);
|
|
||||||
},
|
|
||||||
|
|
||||||
initExtData: () => {
|
initExtData: () => {
|
||||||
get().fillOrderExtData();
|
get().fillOrderExtData();
|
||||||
get().crates.forEach((crate, _i) => {
|
get().crates.forEach((crate, _i) => {
|
||||||
get().fillExtData(crate.id);
|
get().fillExtData(crate.id);
|
||||||
get().fillExtCrateData(crate.id);
|
get().fillExtCrateData(crate.id);
|
||||||
})
|
})
|
||||||
|
get()._updateTotalOrderPrice();
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue