Minimal summary and crate mode

Signed-off-by: Egor Savkin <es@m-labs.hk>
This commit is contained in:
Egor Savkin 2023-12-08 16:39:28 +08:00
parent e6df70b96a
commit 94f321ecf7
7 changed files with 124 additions and 107 deletions

View File

@ -10,8 +10,9 @@ import {crate_type_to_hp, hp_to_slots, resource_counters} from "./count_resource
* Component that displays a list of <ProductCartItem> * Component that displays a list of <ProductCartItem>
*/ */
export function Cart({isMobile, isTouch, data, onToggleOverlayRemove, onClickRemoveItem, onCardUpdate, onClickItem}) { export function Cart({isMobile, isTouch, data, onToggleOverlayRemove, onClickRemoveItem, onCardUpdate, onClickItem}) {
const nbrOccupied = resource_counters.hp(data.items); const nbrOccupied = hp_to_slots(resource_counters.hp(data.items, -1));
const nbrSlots = hp_to_slots(crate_type_to_hp(data.crate_type)); const nbrSlots = hp_to_slots(crate_type_to_hp(data.crate_type));
console.log(nbrOccupied, nbrSlots);
const products = data.items.map((item, index) => { const products = data.items.map((item, index) => {
let itemData; let itemData;
@ -62,7 +63,7 @@ export function Cart({isMobile, isTouch, data, onToggleOverlayRemove, onClickRem
)} )}
<FakePlaceholder <FakePlaceholder
nbrSlots={nbrSlots - nbrOccupied} nToDraw={nbrSlots - nbrOccupied}
isDraggingOver={snapshot.isDraggingOver}/> isDraggingOver={snapshot.isDraggingOver}/>
</div> </div>
)} )}

View File

@ -7,16 +7,26 @@ import {CrateWarnings} from "./CrateWarnings.jsx";
* Component that displays the main crate with reminder rules. * Component that displays the main crate with reminder rules.
* It includes <Cart> and rules * It includes <Cart> and rules
*/ */
export function Crate({data, handleToggleOverlayRemove, handleDeleteItem, handleShowOverlayRemove, handleCardsUpdated, isMobile, isTouch, onDelete}) { export function Crate({
data,
handleToggleOverlayRemove,
handleDeleteItem,
handleShowOverlayRemove,
handleCardsUpdated,
isMobile,
isTouch,
onDelete,
onModeChange
}) {
return ( return (
<div className="crate"> <div className="crate">
<CrateMode current={data.mode} onChange={null} /> <CrateMode current={data.mode} onChange={onModeChange}/>
<div> <div>
Delete crate Delete crate
<button style={{width: "32px"}} onClick={() => onDelete(data.id)}> <button style={{width: "32px"}} onClick={() => onDelete(data.id)}>
<img src="/images/shop/icon-remove.svg" alt="remove" /> <img src="/images/shop/icon-remove.svg" alt="remove"/>
</button> </button>
</div> </div>
@ -32,7 +42,7 @@ export function Crate({data, handleToggleOverlayRemove, handleDeleteItem, handle
onCardUpdate={handleCardsUpdated}> onCardUpdate={handleCardsUpdated}>
</Cart> </Cart>
{1||(rules && rules.length > 0) && ( {1 || (rules && rules.length > 0) && (
<CrateWarnings/> <CrateWarnings/>
)} )}
</div> </div>

View File

@ -2,7 +2,7 @@ import React from 'react'
import {Accordion} from "react-bootstrap"; import {Accordion} from "react-bootstrap";
import {Crate} from "./Crate.jsx"; import {Crate} from "./Crate.jsx";
export function CrateList({crates, isMobile, isTouch, onAddCrate, onDeleteCrate}) { export function CrateList({crates, isMobile, isTouch, onAddCrate, onDeleteCrate, onModeChange}) {
const onClickAdd = (_) => { const onClickAdd = (_) => {
onAddCrate("crate" + Object.entries(crates).length); onAddCrate("crate" + Object.entries(crates).length);
} }
@ -13,7 +13,13 @@ export function CrateList({crates, isMobile, isTouch, onAddCrate, onDeleteCrate}
<Accordion.Item eventKey={`${index}`} key={`crate${index}`}> <Accordion.Item eventKey={`${index}`} key={`crate${index}`}>
<Accordion.Header>Crate #{`${index}`}</Accordion.Header> <Accordion.Header>Crate #{`${index}`}</Accordion.Header>
<Accordion.Body> <Accordion.Body>
<Crate data={{id: crate_id, ...crate}} isTouch={isTouch} isMobile={isMobile} onDelete={onDeleteCrate}/> <Crate
data={{id: crate_id, ...crate}}
isTouch={isTouch}
isMobile={isMobile}
onDelete={onDeleteCrate}
onModeChange={(new_mode) => onModeChange(crate_id, new_mode)}
/>
</Accordion.Body> </Accordion.Body>
</Accordion.Item> </Accordion.Item>
)} )}

View File

@ -11,12 +11,10 @@ export function CrateMode({current, onChange}) {
<a <a
key={item} key={item}
className={current === item ? 'active' : ''} className={current === item ? 'active' : ''}
onClick={() => onChange(item)}
href="#" href="#"
role="button">{shared_data.crateModes[item].name}</a> role="button">{shared_data.crateModes[item].name}</a>
))} ))}
</div> </div>
); );
} }
//onClick={onChange(this, item)}

View File

@ -3,7 +3,8 @@ import PropTypes from "prop-types";
import {SummaryPopup} from "./options/SummaryPopup.jsx"; import {SummaryPopup} from "./options/SummaryPopup.jsx";
import {formatMoney} from "./utils"; import {formatMoney} from "./utils";
import {WarningIndicator} from "./CardWarnings.jsx"; import {WarningIndicator} from "./CardWarnings.jsx";
import {total_order_price} from "./count_resources";
import {data as shared_data} from "./utils";
/** /**
* Components that displays the list of card that are used in the crate. * Components that displays the list of card that are used in the crate.
@ -14,10 +15,7 @@ export class OrderSummary extends PureComponent {
static get propTypes() { static get propTypes() {
return { return {
currency: PropTypes.string, currency: PropTypes.string,
modes: PropTypes.array, crates: PropTypes.object,
currentMode: PropTypes.string,
summary: PropTypes.array,
itemsData: PropTypes.array,
onDeleteItem: PropTypes.func, onDeleteItem: PropTypes.func,
onDeleteAllItems: PropTypes.func, onDeleteAllItems: PropTypes.func,
onMouseEnterItem: PropTypes.func, onMouseEnterItem: PropTypes.func,
@ -75,13 +73,10 @@ export class OrderSummary extends PureComponent {
render() { render() {
const { const {
currency, currency,
modes, crates
currentMode,
summary,
itemsData,
} = this.props; } = this.props;
const mode = modes.find(elem => elem.id === currentMode); const total_price = total_order_price(crates);
return ( return (
<div className="summary-price"> <div className="summary-price">
@ -98,102 +93,82 @@ export class OrderSummary extends PureComponent {
</button> </button>
</td> </td>
</tr> </tr>
{mode && (
<tr>
<td className="item-card-name">{mode.name}</td>
<td className="price">
<div>
{`${currency} ${formatMoney(mode.price)}`}
<button style={{'opacity': '0', 'cursor': 'initial'}}>
<img src="/images/shop/icon-remove.svg" />
</button>
</div>
<span style={{
'display': 'inline-block',
'width': '30px',
}}>&nbsp;</span>
</td>
</tr>
)}
</thead> </thead>
<tbody> {Object.entries(crates).map(([crate_id, crate], _i) => {
{[].map((item, index) => { let crate_type = shared_data.crateModes[crate.crate_type];
let alert, warning, options, options_data;
if (itemsData[index] && itemsData[index].warnings) {
alert = itemsData[index];
const warningsKeys = Object.keys(alert.warnings);
if (warningsKeys && warningsKeys.length > 0) {
warning = alert.warnings[warningsKeys[0]];
}
}
options = itemsData[index] && itemsData[index].options;
options_data = itemsData[index] && itemsData[index].options_data;
const warnings = itemsData[index] && itemsData[index].show_warnings;
return ( return (
<tr key={item.id} <tbody key={"summary_crate_body"+crate_id}>
className={`hoverable ${item.selected ? 'selected' : ''}`} <tr key={"summary_crate_"+crate_id}>
onClick={this.handleOnClickSelectItem.bind(this, index)} <td className="item-card-name">{crate_type.name}</td>
onMouseEnter={this.handleOnMouseEnterItem.bind(this, item.id)}
onMouseLeave={this.handleOnMouseLeaveItem}>
<td className="item-card-name">
<div>{`${item.name_number} ${item.name} ${item.name_codename}`}</div>
</td>
<td className="price"> <td className="price">
<div className="d-inline-flex align-content-center"> <div>
{`${currency} ${formatMoney(item.price)}`} {`${currency} ${formatMoney(crate_type.price)}`}
<button onClick={this.handleOnDeleteItem.bind(this, index)}> <button style={{'opacity': '0', 'cursor': 'initial'}}>
<img src="/images/shop/icon-remove.svg" /> <img src="/images/shop/icon-remove.svg" />
</button> </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> </div>
<span style={{
'display': 'inline-block',
'width': '30px',
}}>&nbsp;</span>
</td> </td>
</tr> </tr>
); {crate.items.map((item, index) => {
})} let options = item && item.options;
</tbody> let options_data = item && item.options_data;
const warnings = item && item.show_warnings;
return (<tr key={"summary_crate_" + crate_id+item.id}
className={`hoverable ${item.selected ? 'selected' : ''}`}
onClick={this.handleOnClickSelectItem.bind(this, index)}
onMouseEnter={this.handleOnMouseEnterItem.bind(this, item.id)}
onMouseLeave={this.handleOnMouseLeaveItem}>
<td className="item-card-name">
<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={this.handleOnDeleteItem.bind(this, 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> <tfoot>
<tr> <tr>
<td className="item-card-name">Price estimate</td> <td className="item-card-name">Price estimate</td>
<td className="price"> <td className="price">
<div> <div>
{summary.length ? ( ${currency} ${formatMoney(total_price)}
`${currency} ${formatMoney(summary.reduce(
(prev, next) => {
return prev + next.price;
}, 0
) + mode.price)}`
) : (
`${currency} ${formatMoney(mode.price)}`
)}
<button style={{'opacity': '0', 'cursor': 'initial'}}> <button style={{'opacity': '0', 'cursor': 'initial'}}>
<img src="/images/shop/icon-remove.svg" alt="icon remove"/> <img src="/images/shop/icon-remove.svg" alt="icon remove"/>
</button> </button>

View File

@ -50,6 +50,7 @@ export class Shop extends PureComponent {
this.handleCardsUpdated = this.handleCardsUpdated.bind(this); this.handleCardsUpdated = this.handleCardsUpdated.bind(this);
this.onAddCrate = this.onAddCrate.bind(this); this.onAddCrate = this.onAddCrate.bind(this);
this.onDeleteCrate = this.onDeleteCrate.bind(this); this.onDeleteCrate = this.onDeleteCrate.bind(this);
this.onCrateModeChange = this.onCrateModeChange.bind(this);
this.timer = null; this.timer = null;
this.timer_remove = null; this.timer_remove = null;
@ -68,10 +69,10 @@ export class Shop extends PureComponent {
index: 0, index: 0,
}; };
/*this.handleOnDragEnd({ this.handleOnDragEnd({
source, source,
destination destination
});*/ });
} }
componentDidUpdate(prevProps, prevState) { componentDidUpdate(prevProps, prevState) {
@ -524,6 +525,22 @@ export class Shop extends PureComponent {
this.setState(new_state); this.setState(new_state);
} }
onCrateModeChange(crate_id, new_mode) {
let new_state = {
...this.state,
columns: {
...this.state.columns,
crates: {
...this.state.columns.crates,
[crate_id]: {
...this.state.columns.crates[crate_id],
crate_type: new_mode
}
}
}};
this.setState(new_state);
}
render() { render() {
const { const {
@ -586,14 +603,13 @@ export class Shop extends PureComponent {
isMobile={isMobile} isMobile={isMobile}
onAddCrate={this.onAddCrate} onAddCrate={this.onAddCrate}
onDeleteCrate={this.onDeleteCrate} onDeleteCrate={this.onDeleteCrate}
onModeChange={this.onCrateModeChange}
/> />
} }
summaryPrice={ summaryPrice={
<OrderSummary <OrderSummary
currency={currency} currency={currency}
currentMode={currentMode} crates={columns.crates}
modes={crateModeItems}
summary={columns.crates}
onMouseEnterItem={this.handleMouseEnterItem} onMouseEnterItem={this.handleMouseEnterItem}
onMouseLeaveItem={this.handleMouseLeaveItem} onMouseLeaveItem={this.handleMouseLeaveItem}
onDeleteItem={this.handleDeleteItem} onDeleteItem={this.handleDeleteItem}

View File

@ -79,4 +79,15 @@ export function hp_to_slots(hp) {
export function crate_type_to_hp(crate_t) { export function crate_type_to_hp(crate_t) {
return shared_data.crateModes[crate_t].hp; return shared_data.crateModes[crate_t].hp;
}
export function total_order_price(crates) {
let sum = 0;
Object.entries(crates).forEach( ([key, crate], _i) => {
sum += shared_data.crateModes[crate.crate_type].price;
crate.items.forEach((item, _) => {
sum += item.price;
});
});
return sum;
} }