forked from M-Labs/web2019
parent
ff7eac97dc
commit
3b1d9fcb56
|
@ -1,5 +1,4 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {v4 as uuidv4} from "uuid";
|
|
||||||
import {Droppable} from "@hello-pangea/dnd";
|
import {Droppable} from "@hello-pangea/dnd";
|
||||||
import {ProductItem} from "./ProductItem";
|
import {ProductItem} from "./ProductItem";
|
||||||
import {useShopStore} from "./shop_store";
|
import {useShopStore} from "./shop_store";
|
||||||
|
@ -42,7 +41,7 @@ export function Backlog() {
|
||||||
{group.items.map(item => {
|
{group.items.map(item => {
|
||||||
item_index++;
|
item_index++;
|
||||||
return (
|
return (
|
||||||
<ProductItem card_index={item_index}/>
|
<ProductItem card_index={item_index} key={item.id} />
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -4,7 +4,7 @@ import {cartStyle} from "./utils";
|
||||||
import {ProductCartItem} from "./ProductCartItem";
|
import {ProductCartItem} from "./ProductCartItem";
|
||||||
import {FakePlaceholder} from "./FakePlaceholder";
|
import {FakePlaceholder} from "./FakePlaceholder";
|
||||||
import {FillExtData} from "./options/utils";
|
import {FillExtData} from "./options/utils";
|
||||||
import {hp_to_slots, resource_counters} from "./count_resources";
|
import {hp_to_slots} from "./count_resources";
|
||||||
import {useShopStore} from "./shop_store";
|
import {useShopStore} from "./shop_store";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -3,7 +3,6 @@ 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 {TriggerCrateWarnings} from "./warnings";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component that displays the main crate with reminder rules.
|
* Component that displays the main crate with reminder rules.
|
||||||
|
|
|
@ -26,11 +26,9 @@ export function CrateList() {
|
||||||
</Accordion.Item>
|
</Accordion.Item>
|
||||||
)}
|
)}
|
||||||
<Accordion.Item eventKey="last">
|
<Accordion.Item eventKey="last">
|
||||||
<Accordion.Header>
|
<Accordion.Header onClick={onAddCrate}>
|
||||||
Add new crate
|
Add new crate
|
||||||
<button style={{width: "32px"}} onClick={onAddCrate}>
|
<img src="/images/shop/icon-add.svg" alt="add" width="32px"/>
|
||||||
<img src="/images/shop/icon-add.svg" alt="add" />
|
|
||||||
</button>
|
|
||||||
</Accordion.Header>
|
</Accordion.Header>
|
||||||
</Accordion.Item>
|
</Accordion.Item>
|
||||||
</Accordion>)
|
</Accordion>)
|
||||||
|
|
|
@ -44,7 +44,6 @@ export function ImportJSON() {
|
||||||
<div className="form-group w-100">
|
<div className="form-group w-100">
|
||||||
<textarea
|
<textarea
|
||||||
onChange={(event) => {
|
onChange={(event) => {
|
||||||
console.log(event)
|
|
||||||
updateImportDescription(event.target.value)
|
updateImportDescription(event.target.value)
|
||||||
}}
|
}}
|
||||||
value={data.value}
|
value={data.value}
|
||||||
|
|
|
@ -5,265 +5,14 @@ import {useShopStore} from "./shop_store";
|
||||||
* Component that provides a base layout (aside/main) for the page.
|
* Component that provides a base layout (aside/main) for the page.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
|
||||||
export function Layout({aside, main}) {
|
|
||||||
static get defaultProps() {
|
|
||||||
return {
|
|
||||||
mobileSideMenuShouldOpen: false,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
|
|
||||||
this.state = {
|
|
||||||
customconf: '',
|
|
||||||
error: null,
|
|
||||||
};
|
|
||||||
|
|
||||||
this.handleCustomConfig = this.handleCustomConfig.bind(this);
|
|
||||||
this.handleClickLoad = this.handleClickLoad.bind(this);
|
|
||||||
this.checkValidation = this.checkValidation.bind(this);
|
|
||||||
|
|
||||||
// retrieve list of available pn
|
|
||||||
const items_keys = Object.keys(props.items);
|
|
||||||
this.list_pn = items_keys.map(function (key) {
|
|
||||||
return props.items[key].name_number;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
handleCustomConfig(e) {
|
|
||||||
const value = e.target.value;
|
|
||||||
|
|
||||||
this.checkValidation(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
checkValidation(conf) {
|
|
||||||
let conf_obj;
|
|
||||||
|
|
||||||
try {
|
|
||||||
conf_obj = JSON.parse(conf);
|
|
||||||
} catch (e) {
|
|
||||||
return this.setState({
|
|
||||||
...this.state,
|
|
||||||
customconf: conf,
|
|
||||||
customconf_ready: null,
|
|
||||||
error: 'invalid format',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!conf_obj) {
|
|
||||||
return this.setState({
|
|
||||||
...this.state,
|
|
||||||
customconf: conf,
|
|
||||||
customconf_ready: null,
|
|
||||||
error: 'invalid format',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((!conf_obj.items || !conf_obj.type) &&
|
|
||||||
(Object.prototype.toString.call(conf_obj.items) !== '[object Array]' ||
|
|
||||||
Object.prototype.toString.call(conf_obj.type) !== '[object String]')) {
|
|
||||||
return this.setState({
|
|
||||||
...this.state,
|
|
||||||
customconf: conf,
|
|
||||||
customconf_ready: null,
|
|
||||||
error: 'invalid format',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (conf_obj.type !== "desktop" && conf_obj.type !== "rack") {
|
|
||||||
return this.setState({
|
|
||||||
...this.state,
|
|
||||||
customconf: conf,
|
|
||||||
customconf_ready: null,
|
|
||||||
error: 'invalid format',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
conf_obj.items.map(function (item) {
|
|
||||||
try {
|
|
||||||
return JSON.parse(item);
|
|
||||||
} catch (e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
conf_obj.items = conf_obj.items.filter(function (item) {
|
|
||||||
return item;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (conf_obj.items.filter(function (item) {
|
|
||||||
return Object.prototype.toString.call(item) !== '[object Object]' || !item.pn || Object.prototype.toString.call(item.pn) !== '[object String]';
|
|
||||||
}).length > 0) {
|
|
||||||
return this.setState({
|
|
||||||
...this.state,
|
|
||||||
customconf: conf,
|
|
||||||
customconf_ready: null,
|
|
||||||
error: 'invalid format',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
conf_obj.items = conf_obj.items.map(function (item) {
|
|
||||||
return {
|
|
||||||
pn: item.pn,
|
|
||||||
options: item.options ? item.options : null,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
const self = this;
|
|
||||||
const unknow_pn = conf_obj.items.filter(function (item_pn) {
|
|
||||||
return self.list_pn.includes(item_pn.pn) === false;
|
|
||||||
}).map(function (item_pn) {
|
|
||||||
return item_pn.pn;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (unknow_pn.length > 0) {
|
|
||||||
return this.setState({
|
|
||||||
...this.state,
|
|
||||||
customconf: conf,
|
|
||||||
customconf_ready: null,
|
|
||||||
error: `${unknow_pn.join(', ')} unknown${unknow_pn.length > 1 ? 's':''} pn number`,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setState({
|
|
||||||
...this.state,
|
|
||||||
customconf: conf,
|
|
||||||
error: null,
|
|
||||||
customconf_ready: conf_obj,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
handleClickLoad() {
|
|
||||||
this.checkValidation(this.state.customconf);
|
|
||||||
|
|
||||||
if (this.props.onClickLoadCustomConf) {
|
|
||||||
this.props.onClickLoadCustomConf(this.state.customconf_ready);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const {
|
|
||||||
aside,
|
|
||||||
main,
|
|
||||||
mobileSideMenuShouldOpen,
|
|
||||||
isMobile,
|
|
||||||
newCardJustAdded,
|
|
||||||
onClickToggleMobileSideMenu,
|
|
||||||
onClickCloseRFQFeedback,
|
|
||||||
showRFQFeedback,
|
|
||||||
RFQBodyType,
|
|
||||||
RFQBodyOrder,
|
|
||||||
} = this.props;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="layout">
|
|
||||||
|
|
||||||
<aside className={'aside ' + (mobileSideMenuShouldOpen ? 'menu-opened' : '')}>{aside}</aside>
|
|
||||||
|
|
||||||
{mobileSideMenuShouldOpen ? (
|
|
||||||
<section className="main" onClick={onClickToggleMobileSideMenu}>{main}</section>
|
|
||||||
) : (
|
|
||||||
<section className="main">{main}</section>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{isMobile && newCardJustAdded ? (
|
|
||||||
<div className="feedback-add-success">
|
|
||||||
✓ added
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
|
|
||||||
|
|
||||||
<div className={`modal fade ${ showRFQFeedback ? 'show': ''}`} style={{'display': showRFQFeedback ? 'block':'none'}} id="exampleModal" tabIndex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
|
|
||||||
<div className="modal-dialog" role="document">
|
|
||||||
<div className="modal-content">
|
|
||||||
<div className="modal-body rfqFeedback">
|
|
||||||
|
|
||||||
<div className="d-flex w-100">
|
|
||||||
|
|
||||||
{RFQBodyType === 'email' ? (
|
|
||||||
<div className="d-flex">
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<img width="30px" src="/images/shop/icon-done.svg" alt="close" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div style={{'padding': '0 .5em'}}>
|
|
||||||
We've received your request and will be in contact soon.
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
) : null }
|
|
||||||
|
|
||||||
{RFQBodyType === 'show' ? (
|
|
||||||
<p>
|
|
||||||
{RFQBodyOrder}
|
|
||||||
</p>
|
|
||||||
) : null}
|
|
||||||
|
|
||||||
{RFQBodyType === 'import' ? (
|
|
||||||
<div className="w-100">
|
|
||||||
|
|
||||||
<form className="w-100">
|
|
||||||
<div className="mb-3">
|
|
||||||
<p className="small">
|
|
||||||
Input the JSON description below. Should be something like:
|
|
||||||
<br />
|
|
||||||
{JSON.stringify({"items":[{"pn":"1124"},{"pn":"2118"},{"pn":"2118"},{"pn":"2128"}],"type":"desktop"})}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="mb-3 w-100">
|
|
||||||
<textarea
|
|
||||||
onChange={this.handleCustomConfig}
|
|
||||||
value={this.state.customconf}
|
|
||||||
className="form-control w-100"
|
|
||||||
rows="5"
|
|
||||||
placeholder="Input JSON description here." />
|
|
||||||
</div>
|
|
||||||
{this.state.error ? (
|
|
||||||
<div className="mb-3">
|
|
||||||
<p className="text-danger">{this.state.error}</p>
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<div className="d-flex flex-column flex-sm-row justify-content-end">
|
|
||||||
<a type="button" onClick={onClickCloseRFQFeedback} className="btn btn-sm btn-outline-primary m-0 mb-2 mb-sm-0 me-sm-2">Close</a>
|
|
||||||
<a type="button" onClick={this.handleClickLoad} className={`btn btn-sm btn-primary m-0 ms-sm-2 ${this.state.error ? 'disabled':''}`}>Load configuration</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<button onClick={onClickCloseRFQFeedback}>
|
|
||||||
<img src="/images/shop/icon-close.svg" alt="close" />
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div onClick={onClickCloseRFQFeedback} className={`modal-backdrop fade ${ showRFQFeedback ? 'show': ''}`} style={{'display': showRFQFeedback ? 'initial':'none'}}></div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
export function Layout({aside, main}) {
|
export function Layout({aside, main}) {
|
||||||
const mobileSideMenuShouldOpen = useShopStore((state) => state.sideMenuOpen);
|
const {mobileSideMenuShouldOpen, onClickToggleMobileSideMenu, showCardAddedFeedback} = useShopStore((state) => ({
|
||||||
const onClickToggleMobileSideMenu = useShopStore((state) => state.switchSideMenu);
|
mobileSideMenuShouldOpen: state.sideMenuIsOpen,
|
||||||
const newCardJustAdded = useShopStore((state) => state.newCardJustAdded);
|
onClickToggleMobileSideMenu: state.switchSideMenu,
|
||||||
const isMobile = useShopStore((state) => state.isMobile);
|
showCardAddedFeedback: state.showCardAddedFeedback,
|
||||||
|
isMobile: state.isMobile,
|
||||||
|
}));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="layout">
|
<div className="layout">
|
||||||
|
@ -276,7 +25,7 @@ export function Layout({aside, main}) {
|
||||||
<section className="main">{main}</section>
|
<section className="main">{main}</section>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{isMobile && newCardJustAdded ? (
|
{showCardAddedFeedback ? (
|
||||||
<div className="feedback-add-success">
|
<div className="feedback-add-success">
|
||||||
✓ added
|
✓ added
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import {validateEmail, Validation} from "./validate.js";
|
import {Validation} from "./validate.js";
|
||||||
import {useShopStore} from "./shop_store";
|
import {useShopStore} from "./shop_store";
|
||||||
import {ShowJSON} from "./ShowJSON";
|
import {ShowJSON} from "./ShowJSON";
|
||||||
|
|
||||||
|
@ -13,6 +13,7 @@ export function OrderForm() {
|
||||||
isProcessing,
|
isProcessing,
|
||||||
updateEmail,
|
updateEmail,
|
||||||
updateNote,
|
updateNote,
|
||||||
|
resetEmailValidation,
|
||||||
submitForm,
|
submitForm,
|
||||||
submitDisabled,
|
submitDisabled,
|
||||||
} = useShopStore(state => ({
|
} = useShopStore(state => ({
|
||||||
|
@ -22,7 +23,8 @@ export function OrderForm() {
|
||||||
updateEmail: state.updateEmail,
|
updateEmail: state.updateEmail,
|
||||||
updateNote: state.updateNote,
|
updateNote: state.updateNote,
|
||||||
submitForm: state.submitForm,
|
submitForm: state.submitForm,
|
||||||
submitDisabled: state.submitDisabled
|
submitDisabled: state.submitDisabled,
|
||||||
|
resetEmailValidation: state.resetEmailValidation
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
||||||
|
@ -35,6 +37,7 @@ export function OrderForm() {
|
||||||
className={`${email.error > 0 ? 'errorField' : ''}`}
|
className={`${email.error > 0 ? 'errorField' : ''}`}
|
||||||
type="email"
|
type="email"
|
||||||
placeholder="Email"
|
placeholder="Email"
|
||||||
|
onFocus={resetEmailValidation}
|
||||||
onChange={(event) => updateEmail(event.target.value)}
|
onChange={(event) => updateEmail(event.target.value)}
|
||||||
onBlur={(event) => updateEmail(event.target.value)}
|
onBlur={(event) => updateEmail(event.target.value)}
|
||||||
value={email.value}/>
|
value={email.value}/>
|
||||||
|
|
|
@ -13,7 +13,6 @@ import {RFQFeedback} from "./RFQFeedback";
|
||||||
export function OrderPanel({title, description}) {
|
export function OrderPanel({title, description}) {
|
||||||
const isMobile = useShopStore((state) => state.isMobile);
|
const isMobile = useShopStore((state) => state.isMobile);
|
||||||
const onClickToggleMobileSideMenu = useShopStore((state) => state.switchSideMenu);
|
const onClickToggleMobileSideMenu = useShopStore((state) => state.switchSideMenu);
|
||||||
const onClickOpenImport = useShopStore((state) => state.openImport);
|
|
||||||
|
|
||||||
return (<section className="panel">
|
return (<section className="panel">
|
||||||
|
|
||||||
|
|
|
@ -61,7 +61,7 @@ export function OrderSummary() {
|
||||||
<div>
|
<div>
|
||||||
{`${currency} ${formatMoney(crate_type.price)}`}
|
{`${currency} ${formatMoney(crate_type.price)}`}
|
||||||
|
|
||||||
<button style={{'opacity': '0', 'cursor': 'initial'}}>
|
<button onClick={() => clearCrate(crate.id)}>
|
||||||
<img src="/images/shop/icon-remove.svg"/>
|
<img src="/images/shop/icon-remove.svg"/>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -19,6 +19,10 @@ export function Shop() {
|
||||||
cardIndexById: state.cardIndexById
|
cardIndexById: state.cardIndexById
|
||||||
}));
|
}));
|
||||||
const handleOnDragEnd = (drop_result, _provided) => {
|
const handleOnDragEnd = (drop_result, _provided) => {
|
||||||
|
if (!drop_result.destination) {
|
||||||
|
console.warn("No drop destination");
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (drop_result.source.droppableId === "backlog")
|
if (drop_result.source.droppableId === "backlog")
|
||||||
addCardFromBacklog(drop_result.destination.droppableId, drop_result.source.index, drop_result.destination.index);
|
addCardFromBacklog(drop_result.destination.droppableId, drop_result.source.index, drop_result.destination.index);
|
||||||
else if(drop_result.destination.droppableId === "backlog")
|
else if(drop_result.destination.droppableId === "backlog")
|
||||||
|
@ -28,7 +32,7 @@ export function Shop() {
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
addCardFromBacklog(null, [cardIndexById("eem_pwr_mod"), cardIndexById("kasli")], -1);
|
addCardFromBacklog(null, [cardIndexById("eem_pwr_mod"), cardIndexById("kasli")], -1, true);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
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
|
||||||
|| item.options_data.ext_pwr === false
|
|| item.options_data.ext_pwr === false
|
||||||
|
@ -75,19 +73,4 @@ export function FillResources(data) {
|
||||||
|
|
||||||
export function hp_to_slots(hp) {
|
export function hp_to_slots(hp) {
|
||||||
return Math.trunc(hp / 4);
|
return Math.trunc(hp / 4);
|
||||||
}
|
|
||||||
|
|
||||||
export function crate_type_to_hp(crate_t) {
|
|
||||||
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;
|
|
||||||
}
|
}
|
|
@ -33,7 +33,7 @@ export function JSONToCrates(description) {
|
||||||
return Array.from(crates_raw.map((crate, c_i) => ({
|
return Array.from(crates_raw.map((crate, c_i) => ({
|
||||||
id: "crate" + c_i,
|
id: "crate" + c_i,
|
||||||
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),
|
||||||
id: uuidv4(),
|
id: uuidv4(),
|
||||||
options_data: card.options
|
options_data: card.options
|
||||||
|
|
|
@ -11,7 +11,7 @@ export function DialogPopup({options, data, target, id, big, first, last, option
|
||||||
);
|
);
|
||||||
|
|
||||||
let div_classes = `overlayVariant border rounded ${big ? "overlay-bigcard" : "overlay-smallcard"} ${(!big && first) ? "overlay-first" : ""} ${(!big && last) ? "overlay-last" : ""} ${options_class || ""}`;
|
let div_classes = `overlayVariant border rounded ${big ? "overlay-bigcard" : "overlay-smallcard"} ${(!big && first) ? "overlay-first" : ""} ${(!big && last) ? "overlay-last" : ""} ${options_class || ""}`;
|
||||||
const handleClick = (event) => {
|
const handleClick = (_event) => {
|
||||||
setShow(!show);
|
setShow(!show);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -53,7 +53,7 @@ export function SummaryPopup({id, options, data}) {
|
||||||
}
|
}
|
||||||
}, [show, size])
|
}, [show, size])
|
||||||
|
|
||||||
const handleClick = (event) => {
|
const handleClick = (_event) => {
|
||||||
setShow(!show);
|
setShow(!show);
|
||||||
if (!show) {
|
if (!show) {
|
||||||
document.addEventListener("scroll", handleScroll, true);
|
document.addEventListener("scroll", handleScroll, true);
|
||||||
|
|
|
@ -37,11 +37,22 @@ const useLayout = ((set, get) => ({
|
||||||
isTouch: window.isTouchEnabled(),
|
isTouch: window.isTouchEnabled(),
|
||||||
isMobile: window.deviceIsMobile(),
|
isMobile: window.deviceIsMobile(),
|
||||||
sideMenuIsOpen: false,
|
sideMenuIsOpen: false,
|
||||||
newCardJustAdded: false,
|
showCardAddedFeedback: false,
|
||||||
|
timerAdded: null,
|
||||||
|
|
||||||
switchSideMenu: () => set(state => ({
|
switchSideMenu: () => set(state => ({
|
||||||
sideMenuIsOpen: !state.sideMenuIsOpen
|
sideMenuIsOpen: !state.sideMenuIsOpen
|
||||||
})),
|
})),
|
||||||
|
cardAdded: () => set(state => ({
|
||||||
|
showCardAddedFeedback: true,
|
||||||
|
timerAdded: (!!state.timerAdded ? clearTimeout(state.timerAdded) : null) || (state.isMobile && setTimeout(() => {
|
||||||
|
get()._endCardAdded()
|
||||||
|
}, 2000))
|
||||||
|
})),
|
||||||
|
_endCardAdded: () => set(state => ({
|
||||||
|
showCardAddedFeedback: false,
|
||||||
|
timerAdded: !!state.timerAdded ? clearTimeout(state.timerAdded) : null
|
||||||
|
}))
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const useImportJSON = ((set, get) => ({
|
const useImportJSON = ((set, get) => ({
|
||||||
|
@ -70,7 +81,6 @@ const useImportJSON = ((set, get) => ({
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const useSubmitForm = ((set, get) => ({
|
const useSubmitForm = ((set, get) => ({
|
||||||
// TODO think about it
|
|
||||||
isProcessing: false,
|
isProcessing: false,
|
||||||
shouldShowRFQFeedback: false,
|
shouldShowRFQFeedback: false,
|
||||||
processingResult: {
|
processingResult: {
|
||||||
|
@ -102,6 +112,12 @@ const useSubmitForm = ((set, get) => ({
|
||||||
error: validateNote(new_notes)
|
error: validateNote(new_notes)
|
||||||
}
|
}
|
||||||
})),
|
})),
|
||||||
|
resetEmailValidation: () => set(state => ({
|
||||||
|
email: {
|
||||||
|
value: state.email.value,
|
||||||
|
error: Validation.OK
|
||||||
|
}
|
||||||
|
})),
|
||||||
|
|
||||||
_revalidateForm: () => set(state => ({
|
_revalidateForm: () => set(state => ({
|
||||||
email: {
|
email: {
|
||||||
|
@ -166,17 +182,22 @@ const useHighlighted = ((set, get) => ({
|
||||||
crate: "",
|
crate: "",
|
||||||
card: 0
|
card: 0
|
||||||
},
|
},
|
||||||
|
highlightedTimer: null,
|
||||||
highlightCard: (crate_id, index) => set(state => ({
|
highlightCard: (crate_id, index) => set(state => ({
|
||||||
highlighted: {
|
highlighted: {
|
||||||
crate: crate_id,
|
crate: crate_id,
|
||||||
card: index
|
card: index
|
||||||
}
|
},
|
||||||
|
highlightedTimer: (!!state.highlightedTimer ? clearTimeout(state.highlightedTimer) : null) || (state.isTouch && setTimeout(() => {
|
||||||
|
get().highlightReset()
|
||||||
|
}, 2000))
|
||||||
})),
|
})),
|
||||||
highlightReset: () => set(state => ({
|
highlightReset: () => set(state => ({
|
||||||
highlighted: {
|
highlighted: {
|
||||||
crate: "",
|
crate: "",
|
||||||
card: 0
|
card: 0
|
||||||
}
|
},
|
||||||
|
highlightedTimer: !!state.highlightedTimer ? clearTimeout(state.highlightedTimer) : null
|
||||||
})),
|
})),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
@ -185,15 +206,19 @@ const useCart = ((set, get) => ({
|
||||||
crates: shared_data.columns.crates,
|
crates: shared_data.columns.crates,
|
||||||
active_crate: "crate0",
|
active_crate: "crate0",
|
||||||
|
|
||||||
_newCrate: (crate_id) => set((state) => ({crates: state.crates.concat({
|
_newCrate: (crate_id) => set((state) => ({
|
||||||
|
crates: state.crates.concat({
|
||||||
id: crate_id || "crate" + state.crates.length,
|
id: crate_id || "crate" + state.crates.length,
|
||||||
crate_mode: "rack",
|
crate_mode: "rack",
|
||||||
items: [],
|
items: [],
|
||||||
warnings: [],
|
warnings: [],
|
||||||
occupiedHP: 0
|
occupiedHP: 0
|
||||||
})})),
|
}),
|
||||||
|
active_crate: crate_id || "crate" + state.crates.length
|
||||||
|
})),
|
||||||
delCrate: (id) => set(state => ({
|
delCrate: (id) => set(state => ({
|
||||||
crates: state.crates.filter((crate => crate.id !== id))
|
crates: state.crates.filter((crate => crate.id !== id)),
|
||||||
|
active_crate: state.active_crate === id ? null : state.active_crate,
|
||||||
})),
|
})),
|
||||||
_setCrateMode: (id, mode) => set(state => ({
|
_setCrateMode: (id, mode) => set(state => ({
|
||||||
crates: state.crates.map((crate, _i) => {
|
crates: state.crates.map((crate, _i) => {
|
||||||
|
@ -209,6 +234,7 @@ const useCart = ((set, get) => ({
|
||||||
_addCardFromBacklog: (crate_to, index_from, index_to) => set(state => {
|
_addCardFromBacklog: (crate_to, index_from, index_to) => set(state => {
|
||||||
const take_from = (true_type_of(index_from) === "array" ? index_from : [index_from]).map((item, _i) => (state.cards_list[item]));
|
const take_from = (true_type_of(index_from) === "array" ? index_from : [index_from]).map((item, _i) => (state.cards_list[item]));
|
||||||
const dest = crate_to || state.active_crate;
|
const dest = crate_to || state.active_crate;
|
||||||
|
if (!dest) return {};
|
||||||
return {
|
return {
|
||||||
crates: state.crates.map((crate, _i) => {
|
crates: state.crates.map((crate, _i) => {
|
||||||
if (dest === crate.id) {
|
if (dest === crate.id) {
|
||||||
|
@ -224,7 +250,6 @@ const useCart = ((set, get) => ({
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
_moveCard: (crate_from, index_from, crate_to, index_to) => set(state => {
|
_moveCard: (crate_from, index_from, crate_to, index_to) => set(state => {
|
||||||
console.log(crate_from, index_from, crate_to, index_to)
|
|
||||||
const the_card = state.crates.find((crate, _) => crate_from === crate.id ).items[index_from];
|
const the_card = state.crates.find((crate, _) => crate_from === crate.id ).items[index_from];
|
||||||
return {
|
return {
|
||||||
crates: state.crates.map((crate, _i) => {
|
crates: state.crates.map((crate, _i) => {
|
||||||
|
@ -293,6 +318,7 @@ const useCart = ((set, get) => ({
|
||||||
fillWarnings: (crate_id) => set(state => ({
|
fillWarnings: (crate_id) => set(state => ({
|
||||||
crates: state.crates.map((crate, _i) => {
|
crates: state.crates.map((crate, _i) => {
|
||||||
if (crate_id === crate.id) {
|
if (crate_id === crate.id) {
|
||||||
|
//console.log("--- CHECK ALERTS ---")
|
||||||
let itemsCopy = Array.from(crate.items);
|
let itemsCopy = Array.from(crate.items);
|
||||||
itemsCopy = FillResources(itemsCopy);
|
itemsCopy = FillResources(itemsCopy);
|
||||||
itemsCopy = TriggerWarnings(itemsCopy);
|
itemsCopy = TriggerWarnings(itemsCopy);
|
||||||
|
@ -332,10 +358,14 @@ const useCart = ((set, get) => ({
|
||||||
get().fillWarnings(id);
|
get().fillWarnings(id);
|
||||||
},
|
},
|
||||||
|
|
||||||
addCardFromBacklog: (crate_to, index_from, index_to) => {
|
addCardFromBacklog: (crate_to, index_from, index_to, just_mounted) => {
|
||||||
const dest = crate_to || get().active_crate;
|
const dest = crate_to || get().active_crate;
|
||||||
|
if (!dest) return {};
|
||||||
get()._addCardFromBacklog(dest, index_from, index_to)
|
get()._addCardFromBacklog(dest, index_from, index_to)
|
||||||
get().fillWarnings(dest);
|
get().fillWarnings(dest);
|
||||||
|
if (!just_mounted) {
|
||||||
|
get().cardAdded()
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
moveCard: (crate_from, index_from, crate_to, index_to) => {
|
moveCard: (crate_from, index_from, crate_to, index_to) => {
|
||||||
|
@ -346,6 +376,7 @@ const useCart = ((set, get) => ({
|
||||||
deleteCard: (crate_id, index) => {
|
deleteCard: (crate_id, index) => {
|
||||||
get()._deleteCard(crate_id, index);
|
get()._deleteCard(crate_id, index);
|
||||||
get().fillWarnings(crate_id);
|
get().fillWarnings(crate_id);
|
||||||
|
if (crate_id === get().highlighted.crate && index === get().highlighted.card) get().highlightReset()
|
||||||
},
|
},
|
||||||
clearCrate: (id) => {
|
clearCrate: (id) => {
|
||||||
get()._clearCrate(id);
|
get()._clearCrate(id);
|
||||||
|
|
|
@ -1,73 +1,8 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
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 = (
|
|
||||||
model,
|
|
||||||
source,
|
|
||||||
destination,
|
|
||||||
draggableSource,
|
|
||||||
droppableDestination
|
|
||||||
) => {
|
|
||||||
const destClone = Array.from(destination.items);
|
|
||||||
|
|
||||||
destClone.splice(droppableDestination.index, 0, ...draggableSource.map((dragged_item, _) => {
|
|
||||||
return {
|
|
||||||
...model[dragged_item],
|
|
||||||
id: uuidv4(),
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
return destClone;
|
|
||||||
};
|
|
||||||
*/
|
|
||||||
export const reorder = (list, startIndex, endIndex) => {
|
|
||||||
const result = Array.from(list);
|
|
||||||
const [removed] = result.splice(startIndex, 1);
|
|
||||||
result.splice(endIndex, 0, removed);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const remove = (list, startIndex) => {
|
|
||||||
const result = Array.from(list);
|
|
||||||
result.splice(startIndex, 1);
|
|
||||||
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,
|
||||||
|
@ -122,4 +57,4 @@ export function formatMoney(amount, decimalCount = 2, decimal = ".", thousands =
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return amount;
|
return amount;
|
||||||
}
|
}
|
||||||
};
|
}
|
|
@ -5,8 +5,7 @@
|
||||||
* Second - resources indicator should be separate component
|
* Second - resources indicator should be separate component
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {crate_type_to_hp, item_occupied_counters, resource_counters} from "./count_resources";
|
import {item_occupied_counters, resource_counters} from "./count_resources";
|
||||||
import {data as shared_data} from "./utils";
|
|
||||||
import {useShopStore} from "./shop_store";
|
import {useShopStore} from "./shop_store";
|
||||||
|
|
||||||
const Levels = {
|
const Levels = {
|
||||||
|
|
|
@ -1,43 +1,8 @@
|
||||||
const shop_data = {
|
const shop_data = {
|
||||||
|
|
||||||
API_RFQ: 'https://hooks.m-labs.hk/rfq',
|
API_RFQ: 'https://hooks.m-labs.hk/rfq',
|
||||||
|
|
||||||
mobileSideMenuShouldOpen: false,
|
|
||||||
currentItemHovered: null,
|
|
||||||
currentMode: 'rack',
|
|
||||||
currency: 'USD',
|
currency: 'USD',
|
||||||
|
|
||||||
crateModeSlots: {
|
|
||||||
rack: 21,
|
|
||||||
desktop: 10,
|
|
||||||
},
|
|
||||||
|
|
||||||
crateRules: {
|
|
||||||
maxSlot: {
|
|
||||||
type: 'crate',
|
|
||||||
icon: '/shop/icon-warning.svg',
|
|
||||||
color: '#c75e5e',
|
|
||||||
name: 'Crate',
|
|
||||||
message: 'You have reached the maximum number of slots allowed for this crate. Consider removing cards.',
|
|
||||||
},
|
|
||||||
compactSlot: {
|
|
||||||
type: 'crate',
|
|
||||||
icon: '/shop/icon-reminder.svg',
|
|
||||||
name: 'Crate',
|
|
||||||
message: 'The selected cards fit in a 42hp desktop crate, consider switching to it for a more compact system',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
crateModeItems: [{
|
|
||||||
id: 'rack',
|
|
||||||
name: 'Rack mountable crate',
|
|
||||||
price: 550,
|
|
||||||
}, {
|
|
||||||
id: 'desktop',
|
|
||||||
name: 'Desktop crate',
|
|
||||||
price: 500,
|
|
||||||
}],
|
|
||||||
|
|
||||||
crateModes: {
|
crateModes: {
|
||||||
rack: {
|
rack: {
|
||||||
id: 'rack',
|
id: 'rack',
|
||||||
|
@ -1194,9 +1159,6 @@ const shop_data = {
|
||||||
}]
|
}]
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
rules: {},
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue