web2019/static/js/shop/OrderSummary.jsx
Egor Savkin 25c4ff970d Significantly reduce number of renders
Signed-off-by: Egor Savkin <es@m-labs.hk>
2024-01-09 10:14:53 +08:00

145 lines
6.9 KiB
JavaScript

import React from 'react';
import {SummaryPopup} from "./options/SummaryPopup";
import {formatMoney} from "./utils";
import {WarningIndicator} from "./CardWarnings";
import {useShopStore} from "./shop_store";
import {useRenderCount} from "@uidotdev/usehooks";
/**
* Components that displays the list of card that are used in the crate.
* It is a summary of purchase
*/
export function OrderSummary() {
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);
console.log("OrderSummary renders: ", renderCount)
return (
<div className="summary-price">
<table>
<thead>
<tr>
<td colSpan="2" className="summary-remove-all">
<span className="item-card-name">Remove all cards</span>
<button onClick={clearAll}>
<img src="/images/shop/icon-remove.svg"/>
</button>
</td>
</tr>
</thead>
{crates.map((crate, _i) => {
let crate_type = crateParams(crate.crate_mode);
return (
<tbody key={"summary_crate_body" + crate.id}>
<tr key={"summary_crate_" + crate.id}>
<td className="item-card-name">{crate_type.name}</td>
<td className="price">
<div className="d-inline-flex">
{`${currency} ${formatMoney(crate_type.price)}`}
<button onClick={() => clearCrate(crate.id)}>
<img src="/images/shop/icon-clear.svg" alt="empty crate"/>
</button>
<button onClick={() => delCrate(crate.id)}>
<img src="/images/shop/icon-remove.svg" alt="remove crate"/>
</button>
</div>
</td>
</tr>
{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 (<tr key={"summary_crate_" + crate.id + item.id}
className={`hoverable ${selected ? 'selected' : ''}`}
onClick={() => setHighlight(crate.id, index)}
onMouseEnter={() => setHighlight(crate.id, index)}
onMouseLeave={() => resetHighlight()}>
<td className="item-card-name">
<span style={{
'display': 'inline-block',
'width': '16px',
}}>&nbsp;</span>
<div>{`${item.name_number} ${item.name} ${item.name_codename}`}</div>
</td>
<td className="price">
<div className="d-inline-flex align-content-center">
{`${currency} ${formatMoney(item.price)}`}
<button onClick={() => deleteCard(crate.id, index)}>
<img src="/images/shop/icon-remove.svg"/>
</button>
<div style={{'width': '45px', 'height': '20px'}}
className="d-inline-flex align-content-center align-self-center justify-content-evenly">
{(warnings && warnings.length > 0 ? (
<WarningIndicator warnings={warnings}/>
) : (
<span style={{
'display': 'inline-block',
'width': '20px',
}}>&nbsp;</span>
))}
{((options && options_data) ? (
<SummaryPopup id={item.id + "options"} options={options}
data={options_data}/>
) : (
<span style={{
'display': 'inline-block',
'width': '20px',
}}>&nbsp;</span>
))}
</div>
</div>
</td>
</tr>);
})}
</tbody>
)
})}
<tfoot>
<tr>
<td className="item-card-name">Price estimate</td>
<td className="price">
<div>
{currency} {formatMoney(total_price)}
<button style={{'opacity': '0', 'cursor': 'initial'}}>
<img src="/images/shop/icon-remove.svg" alt="icon remove"/>
</button>
</div>
<span style={{
'display': 'inline-block',
'width': '30px',
}}>&nbsp;</span>
</td>
</tr>
</tfoot>
</table>
</div>
);
}