From 2bfc16e3c09bf7717a09b88ff9632d37e1babbe0 Mon Sep 17 00:00:00 2001 From: Egor Savkin Date: Thu, 14 Dec 2023 17:45:54 +0800 Subject: [PATCH] Split Summary so that it rerenders only partially Signed-off-by: Egor Savkin --- static/js/shop/Cart.jsx | 4 +- static/js/shop/OrderSummary.jsx | 99 ++------------------------- static/js/shop/ProductCartItem.jsx | 5 +- static/js/shop/SummaryCrate.jsx | 30 ++++++++ static/js/shop/SummaryCrateCard.jsx | 78 +++++++++++++++++++++ static/js/shop/SummaryCrateHeader.jsx | 43 ++++++++++++ static/js/shop/SummaryCrates.jsx | 25 +++++++ static/js/shop/SummaryTotalPrice.jsx | 17 +++++ static/js/shop/shop_store.js | 11 ++- static/js/shop/utils.js | 7 +- 10 files changed, 220 insertions(+), 99 deletions(-) create mode 100644 static/js/shop/SummaryCrate.jsx create mode 100644 static/js/shop/SummaryCrateCard.jsx create mode 100644 static/js/shop/SummaryCrateHeader.jsx create mode 100644 static/js/shop/SummaryCrates.jsx create mode 100644 static/js/shop/SummaryTotalPrice.jsx diff --git a/static/js/shop/Cart.jsx b/static/js/shop/Cart.jsx index 12c3790..21028ea 100644 --- a/static/js/shop/Cart.jsx +++ b/static/js/shop/Cart.jsx @@ -17,8 +17,10 @@ export function Cart({crate_index}) { // #!render_count const renderCount = useRenderCount(); - const crate = useShopStore(useShallow((state) => state.crates[crate_index]), (a, b) => { + const crate = useShopStore((state) => state.crates[crate_index], (a, b) => { + //console.log(a, b) return a.items.length === b.items.length && a.occupiedHP === b.occupiedHP && a.crate_mode === b.crate_mode + //return a === b }); const crateParams = useShopStore((state) => state.crateParams); diff --git a/static/js/shop/OrderSummary.jsx b/static/js/shop/OrderSummary.jsx index fb6c849..564ba64 100644 --- a/static/js/shop/OrderSummary.jsx +++ b/static/js/shop/OrderSummary.jsx @@ -1,12 +1,12 @@ import React from 'react'; -import {SummaryPopup} from "./options/SummaryPopup"; -import {formatMoney} from "./utils"; -import {WarningIndicator} from "./CardWarnings"; import {useShopStore} from "./shop_store"; +import {SummaryCrates} from "./SummaryCrates"; +import {SummaryTotalPrice} from "./SummaryTotalPrice"; // #!render_count import {useRenderCount} from "@uidotdev/usehooks"; + /** * Components that displays the list of card that are used in the crate. * It is a summary of purchase @@ -14,18 +14,7 @@ import {useRenderCount} from "@uidotdev/usehooks"; export function OrderSummary() { // #!render_count const renderCount = useRenderCount(); - - const currency = useShopStore((state) => state.currency); - const crates = useShopStore((state) => state.crates); - const total_price = useShopStore((state) => state.totalOrderPrice()); - const crateParams = useShopStore((state) => state.crateParams); - const deleteCard = useShopStore((state) => state.deleteCard); - const setHighlight = useShopStore((state) => state.highlightCard); - const resetHighlight = useShopStore((state) => state.highlightReset); - const highlighted = useShopStore((state) => state.highlighted); const clearAll = useShopStore((state) => state.clearAll); - const clearCrate = useShopStore((state) => state.clearCrate); - const delCrate = useShopStore((state) => state.delCrate); // #!render_count console.log("OrderSummary renders: ", renderCount) @@ -47,91 +36,13 @@ export function OrderSummary() { - {crates.map((crate, _i) => { - let crate_type = crateParams(crate.crate_mode); - return ( - - - {crate_type.name} - -
- {`${currency} ${formatMoney(crate_type.price)}`} - - - - -
- - - {crate.items.map((item, index) => { - const options = item && item.options; - const options_data = item && item.options_data; - const warnings = item && item.show_warnings; - const selected = crate.id === highlighted.crate && index === highlighted.card; - - return ( setHighlight(crate.id, index)} - onMouseEnter={() => setHighlight(crate.id, index)} - onMouseLeave={() => resetHighlight()}> - -   -
{`${item.name_number} ${item.name} ${item.name_codename}`}
- - - -
- {`${currency} ${formatMoney(item.price)}`} - - - -
- {(warnings && warnings.length > 0 ? ( - - ) : ( -   - ))} - {((options && options_data) ? ( - - ) : ( -   - ))} -
-
- - ); - })} - - ) - })} + Price estimate -
- {currency} {formatMoney(total_price)} - -
+ state.crates[crate_index].items[card_index], - (a, b) => a.id === b.id && a.show_warnings === b.show_warnings && a.counted_resources === b.counted_resources ); + (a, b) => { + //console.log(a.options_data, b.options_data, a.options_data === b.options_data) + return a.id === b.id && a.show_warnings === b.show_warnings && a.counted_resources === b.counted_resources && a.options_data === b.options_data + } ); const highlighted = useShopStore((state) => state.crates[crate_index].id === state.highlighted.crate && card_index === state.highlighted.card); const crate_id = useShopStore((state) => state.crates[crate_index].id); const setHighlight = useShopStore((state) => state.highlightCard); diff --git a/static/js/shop/SummaryCrate.jsx b/static/js/shop/SummaryCrate.jsx new file mode 100644 index 0000000..5bb4c75 --- /dev/null +++ b/static/js/shop/SummaryCrate.jsx @@ -0,0 +1,30 @@ +import {range} from "./utils"; +import React from "react"; +import {useShopStore} from "./shop_store"; +import {SummaryCrateHeader} from "./SummaryCrateHeader"; +import {SummaryCrateCard} from "./SummaryCrateCard"; + +// #!render_count +import {useRenderCount} from "@uidotdev/usehooks"; + +export function SummaryCrate({crate_index}) { + // #!render_count + const renderCount = useRenderCount(); + + const crate_id = useShopStore((state) => state.crates[crate_index].id); + const crate_len = useShopStore((state) => state.crates[crate_index].items.length); + + // #!render_count + console.log("SummaryCrate renders: ", renderCount) + + return ( + + + + + {range(0, crate_len).map((index, _i) => + + )} + + ) +} \ No newline at end of file diff --git a/static/js/shop/SummaryCrateCard.jsx b/static/js/shop/SummaryCrateCard.jsx new file mode 100644 index 0000000..9aed323 --- /dev/null +++ b/static/js/shop/SummaryCrateCard.jsx @@ -0,0 +1,78 @@ +import {formatMoney} from "./utils"; +import {WarningIndicator} from "./CardWarnings"; +import {SummaryPopup} from "./options/SummaryPopup"; +import React from "react"; +import {useShopStore} from "./shop_store"; + +// #!render_count +import {useRenderCount} from "@uidotdev/usehooks"; + +export function SummaryCrateCard({crate_index, card_index}) { + // #!render_count + const renderCount = useRenderCount(); + + const currency = useShopStore((state) => state.currency); + const deleteCard = useShopStore((state) => state.deleteCard); + const setHighlight = useShopStore((state) => state.highlightCard); + const resetHighlight = useShopStore((state) => state.highlightReset); + + const highlighted = useShopStore((state) => state.crates[crate_index].id === state.highlighted.crate && card_index === state.highlighted.card); + const crate_id = useShopStore((state) => state.crates[crate_index].id); + const card = useShopStore((state) => state.crates[crate_index].items[card_index], + (a, b) => a.id === b.id && a.options_data === b.options_data && a.show_warnings === b.show_warnings); + + // #!render_count + console.log("SummaryCrateCard renders: ", renderCount) + + + const options = card && card.options; + const options_data = card && card.options_data; + const warnings = card && card.show_warnings; + + return ( + setHighlight(crate_id, card_index)} + onMouseEnter={() => setHighlight(crate_id, card_index)} + onMouseLeave={() => resetHighlight()}> + +   +
{`${card.name_number} ${card.name} ${card.name_codename}`}
+ + + +
+ {`${currency} ${formatMoney(card.price)}`} + + + +
+ {(warnings && warnings.length > 0 ? ( + + ) : ( +   + ))} + {((options && options_data) ? ( + + ) : ( +   + ))} +
+
+ + ); +} \ No newline at end of file diff --git a/static/js/shop/SummaryCrateHeader.jsx b/static/js/shop/SummaryCrateHeader.jsx new file mode 100644 index 0000000..232921b --- /dev/null +++ b/static/js/shop/SummaryCrateHeader.jsx @@ -0,0 +1,43 @@ +import {formatMoney} from "./utils"; +import React from "react"; +import {useShopStore} from "./shop_store"; + +// #!render_count +import {useRenderCount} from "@uidotdev/usehooks"; + +export function SummaryCrateHeader({crate_index}) { + // #!render_count + const renderCount = useRenderCount(); + + const currency = useShopStore((state) => state.currency); + const crateParams = useShopStore((state) => state.crateParams); + const clearCrate = useShopStore((state) => state.clearCrate); + const delCrate = useShopStore((state) => state.delCrate); + + const crate_mode = useShopStore((state) => state.crates[crate_index].crate_mode); + const crate_id = useShopStore((state) => state.crates[crate_index].id); + + // #!render_count + console.log("SummaryCrateHeader renders: ", renderCount) + + let crate_type = crateParams(crate_mode); + + return ( + + {crate_type.name} + +
+ {`${currency} ${formatMoney(crate_type.price)}`} + + + + +
+ + + ) +} \ No newline at end of file diff --git a/static/js/shop/SummaryCrates.jsx b/static/js/shop/SummaryCrates.jsx new file mode 100644 index 0000000..3ce724c --- /dev/null +++ b/static/js/shop/SummaryCrates.jsx @@ -0,0 +1,25 @@ +import {range} from "./utils"; +import React from "react"; +import {useShopStore} from "./shop_store"; +import {SummaryCrate} from "./SummaryCrate"; + +// #!render_count +import {useRenderCount} from "@uidotdev/usehooks"; + +export function SummaryCrates() { + // #!render_count + const renderCount = useRenderCount(); + + const crates_l = useShopStore((state) => state.crates.length); + + // #!render_count + console.log("SummaryCrates renders: ", renderCount) + + return ( + <> + {range(0, crates_l).map((index, _i) => { + return + })} + + ) +} \ No newline at end of file diff --git a/static/js/shop/SummaryTotalPrice.jsx b/static/js/shop/SummaryTotalPrice.jsx new file mode 100644 index 0000000..9bd15b3 --- /dev/null +++ b/static/js/shop/SummaryTotalPrice.jsx @@ -0,0 +1,17 @@ +import {useShopStore} from "./shop_store"; +import {formatMoney} from "./utils"; +import React from "react"; + +export function SummaryTotalPrice() { + const currency = useShopStore((state) => state.currency); + const total_price = useShopStore((state) => state.totalOrderPrice()); + + return ( +
+ {currency} {formatMoney(total_price)} + +
+ ) +} \ No newline at end of file diff --git a/static/js/shop/shop_store.js b/static/js/shop/shop_store.js index e686395..8beb131 100644 --- a/static/js/shop/shop_store.js +++ b/static/js/shop/shop_store.js @@ -254,12 +254,14 @@ const useCart = ((set, get) => ({ return { crates: state.crates.map((crate, _i) => { if (crate_to === crate_from && crate_to === crate.id) { + // TODO fix //const the_card = {...crate[index_from]}; let items_copy = Array.from(crate.items); delete items_copy[index_from]; + console.log(crate_from, index_from, crate_to, index_to, items_copy.toSpliced(index_to+1, 0, the_card).filter((item, _) => !!item)) return { ...crate, - items: items_copy.toSpliced(index_to+1, 0, the_card).filter((item, _) => !!item) + items: items_copy.toSpliced(index_to+1, 0, {...the_card}).filter((item, _) => !!item) } } else if (crate_to === crate.id) { return { @@ -305,7 +307,12 @@ const useCart = ((set, get) => ({ crates: state.crates.map((crate, _i) => { if (crate_id === crate.id) { let itemsCopy = Array.from(crate.items); - itemsCopy[index].options_data = {...itemsCopy[index].options_data, ...new_options}; + itemsCopy[index] = { + ...itemsCopy[index], + options_data: { + ...itemsCopy[index].options_data, + ...new_options + }}; return { ...crate, items: itemsCopy diff --git a/static/js/shop/utils.js b/static/js/shop/utils.js index 49e472b..85d9823 100644 --- a/static/js/shop/utils.js +++ b/static/js/shop/utils.js @@ -57,4 +57,9 @@ export function formatMoney(amount, decimalCount = 2, decimal = ".", thousands = } catch (e) { return amount; } -} \ No newline at end of file +} + +export const range = (start, end) => { + const length = end - start; + return Array.from({ length }, (_, i) => start + i); +}