forked from M-Labs/web2019
Minimal working multiple crates
Signed-off-by: Egor Savkin <es@m-labs.hk>
This commit is contained in:
parent
63d83b5e10
commit
691e5bbd86
|
@ -1,101 +1,72 @@
|
||||||
import React, {PureComponent} from 'react'
|
import React from 'react'
|
||||||
import PropTypes from "prop-types";
|
|
||||||
import {Droppable} from "@hello-pangea/dnd";
|
import {Droppable} from "@hello-pangea/dnd";
|
||||||
import {cartStyle, nbrOccupiedSlotsInCrate} from "./utils";
|
import {cartStyle, nbrOccupiedSlotsInCrate} from "./utils";
|
||||||
import {ProductCartItem} from "./ProductCartItem.jsx";
|
import {ProductCartItem} from "./ProductCartItem.jsx";
|
||||||
import {FakePlaceholder} from "./FakePlaceholder.jsx";
|
import {FakePlaceholder} from "./FakePlaceholder.jsx";
|
||||||
import {FillExtData} from "./options/utils";
|
import {FillExtData} from "./options/utils";
|
||||||
|
import {crate_type_to_hp, hp_to_slots, resource_counters} from "./count_resources";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component that displays a list of <ProductCartItem>
|
* Component that displays a list of <ProductCartItem>
|
||||||
*/
|
*/
|
||||||
export class Cart extends PureComponent {
|
export function Cart({isMobile, isTouch, data, onToggleOverlayRemove, onClickRemoveItem, onCardUpdate, onClickItem}) {
|
||||||
|
const nbrOccupied = resource_counters.hp(data.items);
|
||||||
static get propTypes() {
|
const nbrSlots = hp_to_slots(crate_type_to_hp(data.crate_type));
|
||||||
return {
|
|
||||||
isMobile: PropTypes.bool,
|
|
||||||
isTouch: PropTypes.bool,
|
|
||||||
nbrSlots: PropTypes.number,
|
|
||||||
itemHovered: PropTypes.string,
|
|
||||||
data: PropTypes.object.isRequired,
|
|
||||||
onToggleOverlayRemove: PropTypes.func,
|
|
||||||
onClickRemoveItem: PropTypes.func,
|
|
||||||
onCardUpdate: PropTypes.func,
|
|
||||||
onClickItem: PropTypes.func,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const {
|
|
||||||
isMobile,
|
|
||||||
isTouch,
|
|
||||||
nbrSlots,
|
|
||||||
itemHovered,
|
|
||||||
data,
|
|
||||||
onToggleOverlayRemove,
|
|
||||||
onClickRemoveItem,
|
|
||||||
onClickItem,
|
|
||||||
onCardUpdate,
|
|
||||||
} = this.props;
|
|
||||||
|
|
||||||
const nbrOccupied = nbrOccupiedSlotsInCrate(data.items);
|
|
||||||
|
|
||||||
const products = data.items.map((item, index) => {
|
|
||||||
let itemData;
|
|
||||||
let ext_data = FillExtData(data.itemsData, index);
|
|
||||||
if (data.itemsData && index in data.itemsData) {
|
|
||||||
itemData = data.itemsData[index];
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<ProductCartItem
|
|
||||||
isMobile={isMobile}
|
|
||||||
isTouch={isTouch}
|
|
||||||
hovered={item.id === itemHovered}
|
|
||||||
key={item.id}
|
|
||||||
id={item.id}
|
|
||||||
index={index}
|
|
||||||
first={index === 0}
|
|
||||||
last={index === data.items.length - 1 && nbrOccupied >= nbrSlots}
|
|
||||||
data={itemData}
|
|
||||||
ext_data={ext_data}
|
|
||||||
onToggleOverlayRemove={onToggleOverlayRemove}
|
|
||||||
onClickRemoveItem={onClickRemoveItem}
|
|
||||||
onCardUpdate={onCardUpdate}
|
|
||||||
onClickItem={onClickItem}
|
|
||||||
model={item}>
|
|
||||||
</ProductCartItem>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
const products = data.items.map((item, index) => {
|
||||||
|
let itemData;
|
||||||
|
let ext_data = FillExtData(data.items, index);
|
||||||
|
if (data.items && index in data.items) {
|
||||||
|
itemData = data.items[index];
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<Droppable droppableId={data.id} direction="horizontal">
|
<ProductCartItem
|
||||||
|
isMobile={isMobile}
|
||||||
{(provided, snapshot) => (
|
isTouch={isTouch}
|
||||||
<div
|
hovered={item.hovered}
|
||||||
ref={provided.innerRef}
|
key={item.id}
|
||||||
{...provided.droppableProps}
|
id={item.id}
|
||||||
style={cartStyle(
|
index={index}
|
||||||
provided.droppableProps.style,
|
first={index === 0}
|
||||||
snapshot,
|
last={index === data.items.length - 1 && nbrOccupied >= nbrSlots}
|
||||||
)}
|
data={itemData}
|
||||||
className="items-cart-list">
|
ext_data={ext_data}
|
||||||
|
onToggleOverlayRemove={onToggleOverlayRemove}
|
||||||
{products}
|
onClickRemoveItem={onClickRemoveItem}
|
||||||
|
onCardUpdate={onCardUpdate}
|
||||||
{provided.placeholder && (
|
onClickItem={onClickItem}
|
||||||
<div style={{ display: 'none' }}>
|
model={item}>
|
||||||
{provided.placeholder}
|
</ProductCartItem>
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<FakePlaceholder
|
|
||||||
nbrSlots={nbrSlots}
|
|
||||||
items={data.items}
|
|
||||||
isDraggingOver={snapshot.isDraggingOver} />
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
</Droppable>
|
|
||||||
);
|
);
|
||||||
}
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Droppable droppableId={data.id} direction="horizontal">
|
||||||
|
|
||||||
|
{(provided, snapshot) => (
|
||||||
|
<div
|
||||||
|
ref={provided.innerRef}
|
||||||
|
{...provided.droppableProps}
|
||||||
|
style={cartStyle(
|
||||||
|
provided.droppableProps.style,
|
||||||
|
snapshot,
|
||||||
|
)}
|
||||||
|
className="items-cart-list">
|
||||||
|
|
||||||
|
{products}
|
||||||
|
|
||||||
|
{provided.placeholder && (
|
||||||
|
<div style={{display: 'none'}}>
|
||||||
|
{provided.placeholder}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<FakePlaceholder
|
||||||
|
nbrSlots={nbrSlots - nbrOccupied}
|
||||||
|
isDraggingOver={snapshot.isDraggingOver}/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
</Droppable>
|
||||||
|
);
|
||||||
}
|
}
|
|
@ -1,44 +1,36 @@
|
||||||
import React, {PureComponent} from 'react';
|
import React from 'react';
|
||||||
import PropTypes from "prop-types";
|
import {Cart} from "./Cart.jsx";
|
||||||
|
import {CrateMode} from "./CrateMode.jsx";
|
||||||
|
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 class Crate extends PureComponent {
|
export function Crate({data, handleToggleOverlayRemove, handleDeleteItem, handleShowOverlayRemove, handleCardsUpdated, isMobile, isTouch}) {
|
||||||
|
return (
|
||||||
|
<div className="crate">
|
||||||
|
|
||||||
static get propTypes() {
|
<CrateMode current={data.mode} onChange={null} />
|
||||||
return {
|
|
||||||
rules: PropTypes.array,
|
|
||||||
cart: PropTypes.element,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
<div className="crate-products">
|
||||||
const {
|
|
||||||
rules,
|
|
||||||
cart,
|
|
||||||
} = this.props;
|
|
||||||
|
|
||||||
return (
|
<Cart
|
||||||
<div className="crate">
|
data={data}
|
||||||
|
isMobile={isMobile}
|
||||||
<div className="crate-products">
|
isTouch={isTouch}
|
||||||
|
onToggleOverlayRemove={handleToggleOverlayRemove}
|
||||||
{cart}
|
onClickRemoveItem={handleDeleteItem}
|
||||||
|
onClickItem={handleShowOverlayRemove}
|
||||||
{rules && rules.length > 0 && (
|
onCardUpdate={handleCardsUpdated}>
|
||||||
<div className="crate-info">
|
</Cart>
|
||||||
{rules.map((rule, index) => (
|
|
||||||
<p key={index} className="rule" style={{'color': rule.color ? rule.color : 'inherit'}}>
|
|
||||||
<img src={`/images${rule.icon}`} /> <i><strong>{rule.name}:</strong> {rule.message}</i>
|
|
||||||
</p>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
{1||(rules && rules.length > 0) && (
|
||||||
|
<CrateWarnings/>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
|
||||||
}
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
}
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
import React from 'react'
|
||||||
|
import {Accordion} from "react-bootstrap";
|
||||||
|
import {Crate} from "./Crate.jsx";
|
||||||
|
|
||||||
|
export function CrateList({crates, isMobile, isTouch}) {
|
||||||
|
return (
|
||||||
|
<Accordion defaultActiveKey="0">
|
||||||
|
{Object.entries(crates).map(([crate_id, crate], index) =>
|
||||||
|
<Accordion.Item eventKey={`${index}`} key={`crate${index}`}>
|
||||||
|
<Accordion.Header>Crate #{`${index}`}</Accordion.Header>
|
||||||
|
<Accordion.Body>
|
||||||
|
<Crate data={{id: crate_id, ...crate}} isTouch={isTouch} isMobile={isMobile}/>
|
||||||
|
</Accordion.Body>
|
||||||
|
</Accordion.Item>
|
||||||
|
)}
|
||||||
|
</Accordion>)
|
||||||
|
}
|
|
@ -1,48 +1,22 @@
|
||||||
import React, {PureComponent} from 'react';
|
import React from 'react';
|
||||||
import PropTypes from "prop-types";
|
import {data as shared_data} from "./utils";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component that displays crate modes
|
* Component that displays crate modes
|
||||||
*/
|
*/
|
||||||
export class CrateMode extends PureComponent {
|
export function CrateMode({current, onChange}) {
|
||||||
|
return (
|
||||||
|
<div className="crate-mode">
|
||||||
|
{shared_data.crateModeOrder.map(item => (
|
||||||
|
<a
|
||||||
|
key={item}
|
||||||
|
className={current === item ? 'active' : ''}
|
||||||
|
|
||||||
static get propTypes() {
|
href="#"
|
||||||
return {
|
role="button">{shared_data.crateModes[item].name}</a>
|
||||||
items: PropTypes.array.isRequired,
|
))}
|
||||||
mode: PropTypes.string.isRequired,
|
</div>
|
||||||
onClickMode: PropTypes.func,
|
);
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
this.handleOnClickMode = this.handleOnClickMode.bind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
handleOnClickMode(mode, e) {
|
|
||||||
if (this.props.onClickMode) {
|
|
||||||
this.props.onClickMode(mode);
|
|
||||||
}
|
|
||||||
e.preventDefault();
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const {
|
|
||||||
mode,
|
|
||||||
items,
|
|
||||||
} = this.props;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="crate-mode">
|
|
||||||
{items.map(item => (
|
|
||||||
<a
|
|
||||||
key={item.id}
|
|
||||||
className={mode == item.id ? 'active' : ''}
|
|
||||||
onClick={this.handleOnClickMode.bind(this, item.id)}
|
|
||||||
href="#"
|
|
||||||
role="button">{item.name}</a>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//onClick={onChange(this, item)}
|
|
@ -0,0 +1,13 @@
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
export function CrateWarnings() {
|
||||||
|
return (
|
||||||
|
<div className="crate-info">
|
||||||
|
{rules.map((rule, index) => (
|
||||||
|
<p key={index} className="rule" style={{'color': rule.color ? rule.color : 'inherit'}}>
|
||||||
|
<img src={`/images${rule.icon}`} /> <i><strong>{rule.name}:</strong> {rule.message}</i>
|
||||||
|
</p>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
|
@ -1,47 +1,27 @@
|
||||||
import React, {PureComponent} from 'react'
|
import React from 'react';
|
||||||
import PropTypes from "prop-types";
|
|
||||||
import {nbrOccupiedSlotsInCrate} from "./utils";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component that displays a placeholder inside crate.
|
* Component that displays a placeholder inside crate.
|
||||||
* Allows to display how it remains space for the current crate.
|
* Allows to display how it remains space for the current crate.
|
||||||
*/
|
*/
|
||||||
export class FakePlaceholder extends PureComponent {
|
export function FakePlaceholder({isDraggingOver, nToDraw}) {
|
||||||
|
const fakePlaceholder = [];
|
||||||
|
|
||||||
static get propTypes() {
|
for (let i = nToDraw; i > 0; i--) {
|
||||||
return {
|
fakePlaceholder.push(
|
||||||
isDraggingOver: PropTypes.bool,
|
<div key={i} style={{
|
||||||
nbrSlots: PropTypes.number.isRequired,
|
display: isDraggingOver ? 'none' : 'block',
|
||||||
items: PropTypes.array.isRequired,
|
border: '1px dashed #ccc',
|
||||||
};
|
width: '45px',
|
||||||
}
|
marginBottom: '5px',
|
||||||
|
}}></div>
|
||||||
render() {
|
|
||||||
const {
|
|
||||||
isDraggingOver,
|
|
||||||
nbrSlots,
|
|
||||||
items,
|
|
||||||
} = this.props;
|
|
||||||
|
|
||||||
const fakePlaceholder = [];
|
|
||||||
const nbrOccupied = nbrOccupiedSlotsInCrate(items);
|
|
||||||
|
|
||||||
for (var i = (nbrSlots - nbrOccupied); i > 0; i--) {
|
|
||||||
fakePlaceholder.push(
|
|
||||||
<div key={i} style={{
|
|
||||||
display: isDraggingOver ? 'none' : 'block',
|
|
||||||
border: '1px dashed #ccc',
|
|
||||||
width: '45px',
|
|
||||||
marginBottom: '5px',
|
|
||||||
}}></div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<React.Fragment>
|
|
||||||
{fakePlaceholder}
|
|
||||||
</React.Fragment>
|
|
||||||
);
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<React.Fragment>
|
||||||
|
{fakePlaceholder}
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
export function ImportJSON() {
|
||||||
|
return (
|
||||||
|
<div> Import JSON BAOBAO</div>
|
||||||
|
)
|
||||||
|
}
|
|
@ -11,8 +11,7 @@ export class OrderPanel extends PureComponent {
|
||||||
return {
|
return {
|
||||||
title: PropTypes.string,
|
title: PropTypes.string,
|
||||||
description: PropTypes.element,
|
description: PropTypes.element,
|
||||||
crateMode: PropTypes.element,
|
cratesList: PropTypes.element,
|
||||||
crate: PropTypes.element,
|
|
||||||
summaryPrice: PropTypes.element,
|
summaryPrice: PropTypes.element,
|
||||||
form: PropTypes.element,
|
form: PropTypes.element,
|
||||||
isMobile: PropTypes.bool,
|
isMobile: PropTypes.bool,
|
||||||
|
@ -25,8 +24,7 @@ export class OrderPanel extends PureComponent {
|
||||||
const {
|
const {
|
||||||
title,
|
title,
|
||||||
description,
|
description,
|
||||||
crateMode,
|
cratesList,
|
||||||
crate,
|
|
||||||
summaryPrice,
|
summaryPrice,
|
||||||
form,
|
form,
|
||||||
isMobile,
|
isMobile,
|
||||||
|
@ -41,8 +39,6 @@ export class OrderPanel extends PureComponent {
|
||||||
|
|
||||||
<div className="control">
|
<div className="control">
|
||||||
{description}
|
{description}
|
||||||
|
|
||||||
{crateMode}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
|
@ -61,7 +57,7 @@ export class OrderPanel extends PureComponent {
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
{crate}
|
{cratesList}
|
||||||
|
|
||||||
<section className="summary">
|
<section className="summary">
|
||||||
{summaryPrice}
|
{summaryPrice}
|
||||||
|
|
|
@ -121,7 +121,7 @@ export class OrderSummary extends PureComponent {
|
||||||
</thead>
|
</thead>
|
||||||
|
|
||||||
<tbody>
|
<tbody>
|
||||||
{summary.map((item, index) => {
|
{[].map((item, index) => {
|
||||||
let alert, warning, options, options_data;
|
let alert, warning, options, options_data;
|
||||||
|
|
||||||
if (itemsData[index] && itemsData[index].warnings) {
|
if (itemsData[index] && itemsData[index].warnings) {
|
||||||
|
|
|
@ -4,18 +4,16 @@ import {FilterOptions} from "./options/utils";
|
||||||
import {v4 as uuidv4} from "uuid";
|
import {v4 as uuidv4} from "uuid";
|
||||||
import {DragDropContext} from "@hello-pangea/dnd";
|
import {DragDropContext} from "@hello-pangea/dnd";
|
||||||
|
|
||||||
import {copy, itemsUnfoldedList, nbrOccupiedSlotsInCrate, remove, reorder} from "./utils";
|
import {copyFromBacklog, itemsUnfoldedList, nbrOccupiedSlotsInCrate, remove, reorder} from "./utils";
|
||||||
|
|
||||||
import {Layout} from "./Layout.jsx";
|
import {Layout} from "./Layout.jsx";
|
||||||
import {Backlog} from "./Backlog.jsx";
|
import {Backlog} from "./Backlog.jsx";
|
||||||
import {OrderPanel} from "./OrderPanel.jsx";
|
import {OrderPanel} from "./OrderPanel.jsx";
|
||||||
import {CrateMode} from "./CrateMode.jsx";
|
|
||||||
import {Crate} from "./Crate.jsx";
|
|
||||||
import {Cart} from "./Cart.jsx";
|
|
||||||
import {OrderSummary} from "./OrderSummary.jsx";
|
import {OrderSummary} from "./OrderSummary.jsx";
|
||||||
import {OrderForm} from "./OrderForm.jsx";
|
import {OrderForm} from "./OrderForm.jsx";
|
||||||
import {TriggerWarnings} from "./warnings";
|
import {TriggerWarnings} from "./warnings";
|
||||||
import {FillResources} from "./count_resources";
|
import {FillResources} from "./count_resources";
|
||||||
|
import {CrateList} from "./CrateList.jsx";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component that render the entire shop
|
* Component that render the entire shop
|
||||||
|
@ -64,14 +62,14 @@ export class Shop extends PureComponent {
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
const destination = {
|
const destination = {
|
||||||
droppableId: 'cart',
|
droppableId: 'crate0',
|
||||||
index: 0,
|
index: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
this.handleOnDragEnd({
|
/*this.handleOnDragEnd({
|
||||||
source,
|
source,
|
||||||
destination
|
destination
|
||||||
});
|
});*/
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate(prevProps, prevState) {
|
componentDidUpdate(prevProps, prevState) {
|
||||||
|
@ -83,13 +81,15 @@ export class Shop extends PureComponent {
|
||||||
* trigger again this function (componentDidUpdate) and thus,
|
* trigger again this function (componentDidUpdate) and thus,
|
||||||
* making an infinite loop.
|
* making an infinite loop.
|
||||||
*/
|
*/
|
||||||
|
return;
|
||||||
if (
|
if (
|
||||||
(prevState.columns.cart.items !== this.state.columns.cart.items) ||
|
(prevState.columns.crates !== this.state.columns.crates.items) ||
|
||||||
(prevState.currentMode !== this.state.currentMode)
|
(prevState.currentMode !== this.state.currentMode)
|
||||||
) {
|
) {
|
||||||
this.checkAlerts(this.state.columns.cart.items);
|
this.checkAlerts(this.state.columns.cart.items);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (this.state.newCardJustAdded) {
|
if (this.state.newCardJustAdded) {
|
||||||
this.timer = setTimeout(() => {
|
this.timer = setTimeout(() => {
|
||||||
this.setState({
|
this.setState({
|
||||||
|
@ -353,11 +353,20 @@ export class Shop extends PureComponent {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
handleOnDragEnd(result, newAdded) {
|
handleOnDragEnd(result) {
|
||||||
|
/**
|
||||||
|
* 4 cases:
|
||||||
|
* - from backlog to one of the crate - add to the correct crate in correct order
|
||||||
|
* - from one crate to another - delete from one crate and put to another in correct order
|
||||||
|
* - within one crate - reorder
|
||||||
|
* - from crate to backlog - delete
|
||||||
|
* */
|
||||||
|
|
||||||
const {
|
const {
|
||||||
source,
|
source,
|
||||||
destination,
|
destination,
|
||||||
} = result;
|
} = result;
|
||||||
|
/* better move to another function
|
||||||
let dragged_items = [];
|
let dragged_items = [];
|
||||||
if (source.indexes) {
|
if (source.indexes) {
|
||||||
source.indexes.forEach((card_index, _) => {
|
source.indexes.forEach((card_index, _) => {
|
||||||
|
@ -365,82 +374,61 @@ export class Shop extends PureComponent {
|
||||||
})
|
})
|
||||||
} else if (source.index >= 0) {
|
} else if (source.index >= 0) {
|
||||||
dragged_items.push(itemsUnfoldedList[source.index]);
|
dragged_items.push(itemsUnfoldedList[source.index]);
|
||||||
}
|
}*/
|
||||||
|
|
||||||
|
console.log('==> result', result);
|
||||||
|
|
||||||
|
// dropped outside the list
|
||||||
if (!destination) {
|
if (!destination) {
|
||||||
if (source.droppableId === 'cart') {
|
|
||||||
this.setState({
|
|
||||||
...this.state,
|
|
||||||
newCardJustAdded: false,
|
|
||||||
columns: {
|
|
||||||
...this.state.columns,
|
|
||||||
[source.droppableId]: {
|
|
||||||
...this.state.columns[source.droppableId],
|
|
||||||
items: remove(
|
|
||||||
this.state.columns[source.droppableId].items,
|
|
||||||
source.index,
|
|
||||||
),
|
|
||||||
itemsData: remove(
|
|
||||||
this.state.columns[source.droppableId].itemsData,
|
|
||||||
source.index,
|
|
||||||
)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(source.droppableId) {
|
switch (source.droppableId) {
|
||||||
|
// TODO add delete functionality
|
||||||
case 'backlog':
|
|
||||||
if (source.droppableId !== destination.droppableId) {
|
|
||||||
this.setState({
|
|
||||||
...this.state,
|
|
||||||
newCardJustAdded: newAdded ? true : false,
|
|
||||||
columns: {
|
|
||||||
...this.state.columns,
|
|
||||||
[destination.droppableId]: {
|
|
||||||
...this.state.columns[destination.droppableId],
|
|
||||||
items: copy(
|
|
||||||
this.state.items,
|
|
||||||
this.state.columns[source.droppableId],
|
|
||||||
this.state.columns[destination.droppableId],
|
|
||||||
dragged_items,
|
|
||||||
destination,
|
|
||||||
),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case destination.droppableId:
|
case destination.droppableId:
|
||||||
this.setState({
|
this.setState({
|
||||||
...this.state,
|
...this.state,
|
||||||
newCardJustAdded: false,
|
|
||||||
columns: {
|
columns: {
|
||||||
...this.state.columns,
|
...this.state.columns,
|
||||||
[destination.droppableId]: {
|
crates: {
|
||||||
...this.state.columns[destination.droppableId],
|
...this.state.columns.crates,
|
||||||
items: reorder(
|
[destination.droppableId]: {
|
||||||
this.state.columns[destination.droppableId].items,
|
...this.state.columns.crates[destination.droppableId],
|
||||||
source.index,
|
items: reorder(
|
||||||
destination.index,
|
this.state.columns.crates[source.droppableId].items,
|
||||||
),
|
source.index,
|
||||||
itemsData: reorder(
|
destination.index
|
||||||
this.state.columns[destination.droppableId].itemsData,
|
)}}
|
||||||
source.index,
|
}
|
||||||
destination.index,
|
});
|
||||||
),
|
break;
|
||||||
},
|
case 'backlog':
|
||||||
},
|
this.setState({
|
||||||
|
...this.state,
|
||||||
|
columns: {
|
||||||
|
...this.state.columns,
|
||||||
|
crates: {
|
||||||
|
...this.state.columns.crates,
|
||||||
|
[destination.droppableId]: {
|
||||||
|
...this.state.columns.crates[destination.droppableId],
|
||||||
|
items: copyFromBacklog(
|
||||||
|
this.state.items,
|
||||||
|
this.state.columns.crates[destination.droppableId],
|
||||||
|
source,
|
||||||
|
destination
|
||||||
|
)}}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
this.setState({
|
||||||
|
columns: move(
|
||||||
|
this.state.columns[source.droppableId],
|
||||||
|
this.state.columns[destination.droppableId],
|
||||||
|
source,
|
||||||
|
destination
|
||||||
|
)
|
||||||
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -460,6 +448,7 @@ export class Shop extends PureComponent {
|
||||||
|
|
||||||
checkAlerts(newItems) {
|
checkAlerts(newItems) {
|
||||||
console.log('--- START CHECKING CRATE WARNING ---');
|
console.log('--- START CHECKING CRATE WARNING ---');
|
||||||
|
return;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
currentMode,
|
currentMode,
|
||||||
|
@ -546,7 +535,7 @@ export class Shop extends PureComponent {
|
||||||
<Backlog
|
<Backlog
|
||||||
currency={currency}
|
currency={currency}
|
||||||
items={items}
|
items={items}
|
||||||
data={columns['backlog']}
|
data={columns.backlog}
|
||||||
onClickAddItem={this.handleClickAddItem}
|
onClickAddItem={this.handleClickAddItem}
|
||||||
onClickToggleMobileSideMenu={this.handleClickToggleMobileSideMenu}
|
onClickToggleMobileSideMenu={this.handleClickToggleMobileSideMenu}
|
||||||
isMobile={isMobile}>
|
isMobile={isMobile}>
|
||||||
|
@ -559,37 +548,17 @@ export class Shop extends PureComponent {
|
||||||
isMobile={isMobile}
|
isMobile={isMobile}
|
||||||
title="Order hardware"
|
title="Order hardware"
|
||||||
description={(<p className="description">Drag and drop the cards you want into the crate below to see how the combination would look like. Setup card's configuration by tapping at the top of the card, most of the options can be modified after shipment. If you have any issues with this ordering system, or if you need other configurations, email us directly anytime at <a href="mailto:sales@m-labs.hk">sales@m-labs.hk</a>. The price is estimated and must be confirmed by a quote.</p>)}
|
description={(<p className="description">Drag and drop the cards you want into the crate below to see how the combination would look like. Setup card's configuration by tapping at the top of the card, most of the options can be modified after shipment. If you have any issues with this ordering system, or if you need other configurations, email us directly anytime at <a href="mailto:sales@m-labs.hk">sales@m-labs.hk</a>. The price is estimated and must be confirmed by a quote.</p>)}
|
||||||
crateMode={
|
cratesList={
|
||||||
<CrateMode
|
<CrateList
|
||||||
items={crateModeItems}
|
crates={columns.crates}
|
||||||
mode={currentMode}
|
/>
|
||||||
onClickMode={this.handleCrateModeChange}>
|
|
||||||
</CrateMode>}
|
|
||||||
crate={
|
|
||||||
<Crate
|
|
||||||
cart={
|
|
||||||
<Cart
|
|
||||||
nbrSlots={crateModeSlots[currentMode]}
|
|
||||||
data={columns['cart']}
|
|
||||||
isMobile={isMobile}
|
|
||||||
isTouch={isTouch}
|
|
||||||
itemHovered={currentItemHovered}
|
|
||||||
onToggleOverlayRemove={this.handleToggleOverlayRemove}
|
|
||||||
onClickRemoveItem={this.handleDeleteItem}
|
|
||||||
onClickItem={this.handleShowOverlayRemove}
|
|
||||||
onCardUpdate={this.handleCardsUpdated}>
|
|
||||||
</Cart>
|
|
||||||
}
|
|
||||||
rules={Object.values(rules).filter(rule => rule)}>
|
|
||||||
</Crate>
|
|
||||||
}
|
}
|
||||||
summaryPrice={
|
summaryPrice={
|
||||||
<OrderSummary
|
<OrderSummary
|
||||||
currency={currency}
|
currency={currency}
|
||||||
currentMode={currentMode}
|
currentMode={currentMode}
|
||||||
modes={crateModeItems}
|
modes={crateModeItems}
|
||||||
summary={columns['cart'].items}
|
summary={columns.crates}
|
||||||
itemsData={columns.cart.itemsData}
|
|
||||||
onMouseEnterItem={this.handleMouseEnterItem}
|
onMouseEnterItem={this.handleMouseEnterItem}
|
||||||
onMouseLeaveItem={this.handleMouseLeaveItem}
|
onMouseLeaveItem={this.handleMouseLeaveItem}
|
||||||
onDeleteItem={this.handleDeleteItem}
|
onDeleteItem={this.handleDeleteItem}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import {data as shared_data} from "./utils";
|
||||||
|
|
||||||
const count_item_occupied_eem = (item) => {
|
const count_item_occupied_eem = (item) => {
|
||||||
if (!item.options_data
|
if (!item.options_data
|
||||||
|
@ -45,7 +46,7 @@ function CounterFactory(name) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const resource_counters = {
|
export const resource_counters = {
|
||||||
"eem": CounterFactory("eem"),
|
"eem": CounterFactory("eem"),
|
||||||
"clk": CounterFactory("clk"),
|
"clk": CounterFactory("clk"),
|
||||||
"idc": CounterFactory("idc"),
|
"idc": CounterFactory("idc"),
|
||||||
|
@ -71,3 +72,11 @@ export function FillResources(data) {
|
||||||
return element;
|
return element;
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function hp_to_slots(hp) {
|
||||||
|
return Math.trunc(hp / 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function crate_type_to_hp(crate_t) {
|
||||||
|
return shared_data.crateModes[crate_t].hp;
|
||||||
|
}
|
|
@ -5,7 +5,7 @@ import {v4 as uuidv4} from "uuid";
|
||||||
export const data = window.shop_data;
|
export const data = window.shop_data;
|
||||||
export const itemsUnfoldedList = Array.from(data.columns.backlog.categories.map(groupId => groupId.itemIds).flat());
|
export const itemsUnfoldedList = Array.from(data.columns.backlog.categories.map(groupId => groupId.itemIds).flat());
|
||||||
|
|
||||||
export const copy = (
|
/*export const copy = (
|
||||||
model,
|
model,
|
||||||
source,
|
source,
|
||||||
destination,
|
destination,
|
||||||
|
@ -23,7 +23,7 @@ export const copy = (
|
||||||
|
|
||||||
return destClone;
|
return destClone;
|
||||||
};
|
};
|
||||||
|
*/
|
||||||
export const reorder = (list, startIndex, endIndex) => {
|
export const reorder = (list, startIndex, endIndex) => {
|
||||||
const result = Array.from(list);
|
const result = Array.from(list);
|
||||||
const [removed] = result.splice(startIndex, 1);
|
const [removed] = result.splice(startIndex, 1);
|
||||||
|
@ -38,6 +38,36 @@ export const remove = (list, startIndex) => {
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export const copyFromBacklog = (source, destination, droppableSource, droppableDestination) => {
|
||||||
|
console.log('==> dest', destination);
|
||||||
|
|
||||||
|
const destClone = Array.from(destination.items);
|
||||||
|
const items = droppableSource.indexes
|
||||||
|
? droppableSource.indexes .map((item, _) => itemsUnfoldedList[item])
|
||||||
|
: [itemsUnfoldedList[droppableSource.index]];
|
||||||
|
|
||||||
|
destClone.splice(droppableDestination.index, 0, ...items.map((item, _) => {
|
||||||
|
return {...source[item], id: uuidv4()}
|
||||||
|
}));
|
||||||
|
return destClone;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const move = (source, destination, droppableSource, droppableDestination) => {
|
||||||
|
console.log('==> move', source, destination);
|
||||||
|
const sourceClone = Array.from(source);
|
||||||
|
const destClone = Array.from(destination);
|
||||||
|
const [removed] = sourceClone.splice(droppableSource.index, 1);
|
||||||
|
|
||||||
|
destClone.splice(droppableDestination.index, 0, removed);
|
||||||
|
|
||||||
|
const result = {columns: {}};
|
||||||
|
result.columns[droppableSource.droppableId] = sourceClone;
|
||||||
|
result.columns[droppableDestination.droppableId] = destClone;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
export const productStyle = (style, snapshot, removeAnim, hovered, selected, cart=false) => {
|
export const productStyle = (style, snapshot, removeAnim, hovered, selected, cart=false) => {
|
||||||
const custom = {
|
const custom = {
|
||||||
opacity: snapshot.isDragging ? .7 : 1,
|
opacity: snapshot.isDragging ? .7 : 1,
|
||||||
|
@ -76,13 +106,6 @@ export const cartStyle = (style, snapshot) => {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export const nbrOccupiedSlotsInCrate = (items) => {
|
|
||||||
return items.reduce((prev, next) => {
|
|
||||||
return prev + (next.hp === 8 ? 2 : 1);
|
|
||||||
}, 0);
|
|
||||||
};
|
|
||||||
|
|
||||||
export function formatMoney(amount, decimalCount = 2, decimal = ".", thousands = ",") {
|
export function formatMoney(amount, decimalCount = 2, decimal = ".", thousands = ",") {
|
||||||
// https://stackoverflow.com/questions/149055/how-can-i-format-numbers-as-currency-string-in-javascript
|
// https://stackoverflow.com/questions/149055/how-can-i-format-numbers-as-currency-string-in-javascript
|
||||||
// changes: return amount if error in order to avoid empty value
|
// changes: return amount if error in order to avoid empty value
|
||||||
|
|
|
@ -38,6 +38,30 @@ const shop_data = {
|
||||||
price: 500,
|
price: 500,
|
||||||
}],
|
}],
|
||||||
|
|
||||||
|
crateModes: {
|
||||||
|
rack: {
|
||||||
|
id: 'rack',
|
||||||
|
name: 'Rack mountable crate',
|
||||||
|
price: 550,
|
||||||
|
hp: 84
|
||||||
|
},
|
||||||
|
desktop: {
|
||||||
|
id: 'desktop',
|
||||||
|
name: 'Desktop crate',
|
||||||
|
price: 500,
|
||||||
|
hp: 42
|
||||||
|
},
|
||||||
|
no_crate: {
|
||||||
|
id: 'no_crate',
|
||||||
|
name: 'Standalone cards',
|
||||||
|
price: 0,
|
||||||
|
hp: -1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
crateModeOrder: [
|
||||||
|
"rack", "desktop", "no_crate"
|
||||||
|
],
|
||||||
|
|
||||||
items: {
|
items: {
|
||||||
/* keys are also ids, avoid changing them */
|
/* keys are also ids, avoid changing them */
|
||||||
'kasli': {
|
'kasli': {
|
||||||
|
@ -1161,12 +1185,12 @@ const shop_data = {
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
||||||
'cart': {
|
"crates": {
|
||||||
id: 'cart',
|
"crate0": {
|
||||||
title: 'Cart',
|
crate_type: "rack",
|
||||||
items: [],
|
items: []
|
||||||
itemsData: [],
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue