forked from M-Labs/web2019
Add order options
Signed-off-by: Egor Savkin <es@m-labs.hk>
This commit is contained in:
parent
15d9124025
commit
bcc8db6819
@ -384,6 +384,17 @@ button {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.order-bar {
|
||||||
|
width: 100%;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
padding: 0.75rem 1.25rem;
|
||||||
|
input[type="text"] {
|
||||||
|
padding: 0;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
line-height: 1.1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.crate {
|
.crate {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
|
61763
static/js/shop.bundle.js
61763
static/js/shop.bundle.js
File diff suppressed because one or more lines are too long
@ -1,7 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import {useShopStore} from "./shop_store";
|
import {useShopStore} from "./shop_store";
|
||||||
import {ProcessOptions, ProcessOptionsToData} from "./options/Options";
|
import {ProcessOptions} from "./options/Options";
|
||||||
|
|
||||||
export function CrateOptions({crate_index}) {
|
export function CrateOptions({crate_index}) {
|
||||||
const crate_id = useShopStore((state) => state.crates[crate_index].id);
|
const crate_id = useShopStore((state) => state.crates[crate_index].id);
|
||||||
|
38
static/js/shop/OrderOptions.jsx
Normal file
38
static/js/shop/OrderOptions.jsx
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
import {useShopStore} from "./shop_store";
|
||||||
|
import {ProcessOptions} from "./options/Options";
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
export function OrderOptions() {
|
||||||
|
const optionsLogic = useShopStore((state) => state.order_options);
|
||||||
|
const updateOptions = useShopStore((state) => state.updateOrderOptions);
|
||||||
|
const options_data = useShopStore((state) => state.order_options_data || {});
|
||||||
|
|
||||||
|
const options = ProcessOptions({
|
||||||
|
options: optionsLogic,
|
||||||
|
data: options_data,
|
||||||
|
id: "order_options",
|
||||||
|
target: {
|
||||||
|
construct: ((outvar, value) => {
|
||||||
|
// #!options_log
|
||||||
|
console.log("construct", outvar, value, options_data);
|
||||||
|
|
||||||
|
options_data[outvar] = value;
|
||||||
|
updateOptions({[outvar]: value});
|
||||||
|
}),
|
||||||
|
update: ((outvar, value) => {
|
||||||
|
// #!options_log
|
||||||
|
console.log("update", outvar, value, options_data);
|
||||||
|
|
||||||
|
if (outvar in options_data) options_data[outvar] = value;
|
||||||
|
|
||||||
|
updateOptions({[outvar]: value});
|
||||||
|
})
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="order-bar border rounded">
|
||||||
|
{options}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import {OrderSummary} from "./OrderSummary";
|
import {SummaryOrder} from "./SummaryOrder";
|
||||||
import {OrderForm} from "./OrderForm";
|
import {OrderForm} from "./OrderForm";
|
||||||
import {CrateList} from "./CrateList";
|
import {CrateList} from "./CrateList";
|
||||||
import {useShopStore} from "./shop_store";
|
import {useShopStore} from "./shop_store";
|
||||||
@ -8,6 +8,7 @@ import {RFQFeedback} from "./RFQFeedback";
|
|||||||
|
|
||||||
// #!render_count
|
// #!render_count
|
||||||
import {useRenderCount} from "@uidotdev/usehooks";
|
import {useRenderCount} from "@uidotdev/usehooks";
|
||||||
|
import {OrderOptions} from "./OrderOptions";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component that renders all things for order.
|
* Component that renders all things for order.
|
||||||
@ -46,8 +47,10 @@ export function OrderPanel({title, description}) {
|
|||||||
|
|
||||||
<CrateList/>
|
<CrateList/>
|
||||||
|
|
||||||
|
<OrderOptions/>
|
||||||
|
|
||||||
<section className="summary">
|
<section className="summary">
|
||||||
<OrderSummary/>
|
<SummaryOrder/>
|
||||||
|
|
||||||
<OrderForm/>
|
<OrderForm/>
|
||||||
</section>
|
</section>
|
||||||
|
@ -4,7 +4,6 @@ import {useShopStore} from "./shop_store";
|
|||||||
|
|
||||||
// #!render_count
|
// #!render_count
|
||||||
import {useRenderCount} from "@uidotdev/usehooks";
|
import {useRenderCount} from "@uidotdev/usehooks";
|
||||||
import {CrateMode} from "./CrateMode";
|
|
||||||
|
|
||||||
export function SummaryCrateHeader({crate_index}) {
|
export function SummaryCrateHeader({crate_index}) {
|
||||||
// #!render_count
|
// #!render_count
|
||||||
|
@ -21,7 +21,7 @@ export function SummaryCratePricedOptions({crate_index}) {
|
|||||||
// #!render_count
|
// #!render_count
|
||||||
console.log("SummaryCratePricedOptions renders: ", renderCount)
|
console.log("SummaryCratePricedOptions renders: ", renderCount)
|
||||||
|
|
||||||
return options.map((option, i) => (
|
return options.map((option, _i) => (
|
||||||
<tr key={"summary_crate_" + crate_id +"option_" + option.id}>
|
<tr key={"summary_crate_" + crate_id +"option_" + option.id}>
|
||||||
<td className="item-card-name">
|
<td className="item-card-name">
|
||||||
<span style={{
|
<span style={{
|
||||||
|
@ -5,6 +5,7 @@ import {SummaryCrate} from "./SummaryCrate";
|
|||||||
|
|
||||||
// #!render_count
|
// #!render_count
|
||||||
import {useRenderCount} from "@uidotdev/usehooks";
|
import {useRenderCount} from "@uidotdev/usehooks";
|
||||||
|
import {SummaryOrderPricedOptions} from "./SummaryOrderPricedOptions";
|
||||||
|
|
||||||
export function SummaryCrates() {
|
export function SummaryCrates() {
|
||||||
// #!render_count
|
// #!render_count
|
||||||
@ -20,6 +21,7 @@ export function SummaryCrates() {
|
|||||||
{range(0, crates_l).map((index, _i) => {
|
{range(0, crates_l).map((index, _i) => {
|
||||||
return <SummaryCrate crate_index={index} key={"summary_crate_body_" + index} />
|
return <SummaryCrate crate_index={index} key={"summary_crate_body_" + index} />
|
||||||
})}
|
})}
|
||||||
|
<SummaryOrderPricedOptions/>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
@ -1,5 +1,4 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {useShopStore} from "./shop_store";
|
|
||||||
import {SummaryCrates} from "./SummaryCrates";
|
import {SummaryCrates} from "./SummaryCrates";
|
||||||
import {SummaryTotalPrice} from "./SummaryTotalPrice";
|
import {SummaryTotalPrice} from "./SummaryTotalPrice";
|
||||||
|
|
||||||
@ -11,12 +10,12 @@ import {useRenderCount} from "@uidotdev/usehooks";
|
|||||||
* 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.
|
||||||
* It is a summary of purchase
|
* It is a summary of purchase
|
||||||
*/
|
*/
|
||||||
export function OrderSummary() {
|
export function SummaryOrder() {
|
||||||
// #!render_count
|
// #!render_count
|
||||||
const renderCount = useRenderCount();
|
const renderCount = useRenderCount();
|
||||||
|
|
||||||
// #!render_count
|
// #!render_count
|
||||||
console.log("OrderSummary renders: ", renderCount)
|
console.log("SummaryOrder renders: ", renderCount)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="summary-price">
|
<div className="summary-price">
|
43
static/js/shop/SummaryOrderPricedOptions.jsx
Normal file
43
static/js/shop/SummaryOrderPricedOptions.jsx
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
import {formatMoney} from "./utils";
|
||||||
|
import React from "react";
|
||||||
|
import {useShopStore} from "./shop_store";
|
||||||
|
import {ProcessOptionsToData} from "./options/Options";
|
||||||
|
|
||||||
|
// #!render_count
|
||||||
|
import {useRenderCount} from "@uidotdev/usehooks";
|
||||||
|
|
||||||
|
export function SummaryOrderPricedOptions() {
|
||||||
|
// #!render_count
|
||||||
|
const renderCount = useRenderCount();
|
||||||
|
|
||||||
|
const currency = useShopStore((state) => state.currency);
|
||||||
|
const optionsPrices = useShopStore((state) => state.order_prices);
|
||||||
|
const updateOptions = useShopStore((state) => state.updateOrderOptions);
|
||||||
|
const options_data = useShopStore((state) => state.order_options_data);
|
||||||
|
|
||||||
|
const options = ProcessOptionsToData({options: optionsPrices, data: options_data});
|
||||||
|
|
||||||
|
// #!render_count
|
||||||
|
console.log("SummaryOrderPricedOptions renders: ", renderCount)
|
||||||
|
|
||||||
|
return <tbody key={"summary_order_body"}>
|
||||||
|
{options.map((option, _i) => (
|
||||||
|
<tr key={"summary_order" + "option_" + option.id}>
|
||||||
|
<td className="item-card-name">
|
||||||
|
<div>{option.title}</div>
|
||||||
|
</td>
|
||||||
|
<td className="price">
|
||||||
|
<div className="d-inline-flex align-content-center">
|
||||||
|
{`${currency} ${formatMoney(option.price)}`}
|
||||||
|
|
||||||
|
<button onClick={() => updateOptions(option.disable_patch)}>
|
||||||
|
<img src="/images/shop/icon-remove.svg" className="d-block"/>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<div style={{'width': '45px', 'height': '20px'}} className="d-inline"></div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
</tbody>;
|
||||||
|
}
|
@ -5,20 +5,23 @@ import {v4 as uuidv4} from "uuid";
|
|||||||
|
|
||||||
export function validateJSON(description) {
|
export function validateJSON(description) {
|
||||||
let crates_raw;
|
let crates_raw;
|
||||||
|
let order_options;
|
||||||
try {
|
try {
|
||||||
const parsed = JSON.parse(description);
|
const parsed = JSON.parse(description);
|
||||||
// here we can check additional fields
|
// here we can check additional fields
|
||||||
crates_raw = parsed.crates;
|
crates_raw = parsed.crates;
|
||||||
|
order_options = parsed.options;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (!order_options) return false;
|
||||||
const crate_modes = useShopStore.getState().crate_modes;
|
const crate_modes = useShopStore.getState().crate_modes;
|
||||||
const modes_order = useShopStore.getState().modes_order;
|
const modes_order = useShopStore.getState().modes_order;
|
||||||
const pn_to_card = useShopStore.getState().pn_to_cards;
|
const pn_to_card = useShopStore.getState().pn_to_cards;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
for (const crate of crates_raw) {
|
for (const crate of crates_raw) {
|
||||||
if (!crate.type || !crate.items || !(crate.type in crate_modes)) return false;
|
if (!crate.type || !crate.items || !crate.options || !(crate.type in crate_modes)) return false;
|
||||||
for (const card of crate.items) {
|
for (const card of crate.items) {
|
||||||
if (!(card.pn in pn_to_card) || card.options === undefined) return false;
|
if (!(card.pn in pn_to_card) || card.options === undefined) return false;
|
||||||
}
|
}
|
||||||
@ -53,12 +56,15 @@ export function JSONToCrates(description) {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
// some additional fields go here
|
// some additional fields go here
|
||||||
|
order_options_data: parsed.options,
|
||||||
crates: crates
|
crates: crates
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function CratesToJSON(crates) {
|
export function CratesToJSON(crates) {
|
||||||
const crateOptions = useShopStore.getState().crate_options;
|
const crateOptions = useShopStore.getState().crate_options;
|
||||||
|
const orderOptions = useShopStore.getState().order_options;
|
||||||
|
const orderOptionsData = useShopStore.getState().order_options_data;
|
||||||
return JSON.stringify({
|
return JSON.stringify({
|
||||||
// additional fields can go here
|
// additional fields can go here
|
||||||
crates: Array.from(crates.map((crate, _i) => ({
|
crates: Array.from(crates.map((crate, _i) => ({
|
||||||
@ -68,6 +74,7 @@ export function CratesToJSON(crates) {
|
|||||||
}))),
|
}))),
|
||||||
type: crate.crate_mode,
|
type: crate.crate_mode,
|
||||||
options: FilterOptions(crateOptions, crate.options_data)
|
options: FilterOptions(crateOptions, crate.options_data)
|
||||||
})))
|
}))),
|
||||||
|
options: FilterOptions(orderOptions, orderOptionsData)
|
||||||
}, null, 2)
|
}, null, 2)
|
||||||
}
|
}
|
@ -45,11 +45,11 @@ export function ProcessOptionsToData({options, data}) {
|
|||||||
let options_t = true_type_of(options);
|
let options_t = true_type_of(options);
|
||||||
if (options_t === "array") {
|
if (options_t === "array") {
|
||||||
return Array.from(
|
return Array.from(
|
||||||
options.map((option_item, i) => ProcessOptionsToData({
|
options.map((option_item, _i) => ProcessOptionsToData({
|
||||||
options: option_item,
|
options: option_item,
|
||||||
data: data,
|
data: data,
|
||||||
}))
|
}))
|
||||||
).filter((item, i) => !!item).flat();
|
).filter((item, _i) => !!item).flat();
|
||||||
} else if (options_t === "object") {
|
} else if (options_t === "object") {
|
||||||
if (true_type_of(options.title) === "string") {
|
if (true_type_of(options.title) === "string") {
|
||||||
return options;
|
return options;
|
||||||
|
@ -21,6 +21,15 @@ class Line extends Component {
|
|||||||
this.props.target.update(this.props.outvar, text);
|
this.props.target.update(this.props.outvar, text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static getDerivedStateFromProps(props, current_state) {
|
||||||
|
if (current_state.text !== props.data[props.outvar]) {
|
||||||
|
return {
|
||||||
|
text: props.data[props.outvar]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let key = this.props.id + this.props.outvar;
|
let key = this.props.id + this.props.outvar;
|
||||||
return (
|
return (
|
||||||
|
@ -23,6 +23,15 @@ class Radio extends Component {
|
|||||||
this.props.target.update(this.props.outvar, variant);
|
this.props.target.update(this.props.outvar, variant);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static getDerivedStateFromProps(props, current_state) {
|
||||||
|
if (current_state.variant !== props.data[props.outvar]) {
|
||||||
|
return {
|
||||||
|
variant: props.data[props.outvar]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let key = this.props.id + this.props.outvar;
|
let key = this.props.id + this.props.outvar;
|
||||||
return (
|
return (
|
||||||
|
@ -34,6 +34,16 @@ class SwitchLine extends Component {
|
|||||||
this.props.target.update(this.props.outvar, new_state);
|
this.props.target.update(this.props.outvar, new_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static getDerivedStateFromProps(props, current_state) {
|
||||||
|
if (current_state.checked !== props.data[props.outvar].checked || current_state.text !== props.data[props.outvar].text) {
|
||||||
|
return {
|
||||||
|
checked: props.data[props.outvar].checked,
|
||||||
|
text: props.data[props.outvar].text,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let key = this.props.id + this.props.outvar;
|
let key = this.props.id + this.props.outvar;
|
||||||
return (
|
return (
|
||||||
|
@ -18,6 +18,12 @@ export function FillExtCrateData(crate) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function FillExtOrderData(crates, modes_order) {
|
||||||
|
return {
|
||||||
|
has_crate: crates.filter((crate) => modes_order.includes(crate.crate_mode)).length >= 1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function FilterOptions(options, data) {
|
export function FilterOptions(options, data) {
|
||||||
let options_t = true_type_of(options);
|
let options_t = true_type_of(options);
|
||||||
let target = {};
|
let target = {};
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import {createWithEqualityFn} from "zustand/traditional";
|
import {createWithEqualityFn} from "zustand/traditional";
|
||||||
import {data as shared_data, itemsUnfoldedList} from "./utils";
|
import {data as shared_data, itemsUnfoldedList} from "./utils";
|
||||||
import {FillExtCrateData, true_type_of} from "./options/utils";
|
import {FillExtCrateData, FillExtOrderData, true_type_of} from "./options/utils";
|
||||||
import {v4 as uuidv4} from "uuid";
|
import {v4 as uuidv4} from "uuid";
|
||||||
import {FillResources} from "./count_resources";
|
import {FillResources} from "./count_resources";
|
||||||
import {FillExtCardData} from "./options/utils";
|
import {FillExtCardData} from "./options/utils";
|
||||||
@ -10,7 +10,6 @@ import {TriggerCrateWarnings, TriggerWarnings} from "./warnings";
|
|||||||
import {Validation, validateEmail, validateNote, validateJSONInput} from "./validate";
|
import {Validation, validateEmail, validateNote, validateJSONInput} from "./validate";
|
||||||
import {CratesToJSON, JSONToCrates} from "./json_porter";
|
import {CratesToJSON, JSONToCrates} from "./json_porter";
|
||||||
import {ProcessOptionsToData} from "./options/Options";
|
import {ProcessOptionsToData} from "./options/Options";
|
||||||
import {forEach} from "react-bootstrap/ElementChildren";
|
|
||||||
|
|
||||||
|
|
||||||
const cards_to_pn_map = (cards) => {
|
const cards_to_pn_map = (cards) => {
|
||||||
@ -74,18 +73,23 @@ const useCrateOptions = ((set, get) => ({
|
|||||||
|
|
||||||
updateCrateOptions: (crate_id, new_options) => {
|
updateCrateOptions: (crate_id, new_options) => {
|
||||||
get().fillExtCrateData(crate_id);
|
get().fillExtCrateData(crate_id);
|
||||||
|
get().fillOrderExtData();
|
||||||
get()._updateCrateOption(crate_id, new_options);
|
get()._updateCrateOption(crate_id, new_options);
|
||||||
get()._updateTotalOrderPrice();
|
get()._updateTotalOrderPrice();
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const useOrderOptions = ((set, get) => ({
|
const useOrderOptions = ((set, get) => ({
|
||||||
orderOptions: shared_data.crateOptions.options,
|
order_options: shared_data.orderOptions.options,
|
||||||
orderPrices: shared_data.crateOptions.prices,
|
order_prices: shared_data.orderOptions.prices,
|
||||||
order_options_data: {},
|
order_options_data: {},
|
||||||
|
|
||||||
// in case of future needs
|
fillOrderExtData: () => set(state => ({
|
||||||
fillOrderExtData: _ => {},
|
order_options_data: {
|
||||||
|
...state.order_options_data,
|
||||||
|
ext_data: FillExtOrderData(state.crates, state.modes_order)
|
||||||
|
}
|
||||||
|
})),
|
||||||
|
|
||||||
_updateOrderOptions: (new_options) => set(state => ({
|
_updateOrderOptions: (new_options) => set(state => ({
|
||||||
order_options_data: {
|
order_options_data: {
|
||||||
@ -95,9 +99,9 @@ const useOrderOptions = ((set, get) => ({
|
|||||||
})),
|
})),
|
||||||
|
|
||||||
updateOrderOptions: (new_options) => {
|
updateOrderOptions: (new_options) => {
|
||||||
get().fillOrderExtData();
|
|
||||||
get()._updateOrderOptions(new_options);
|
get()._updateOrderOptions(new_options);
|
||||||
get()._updateTotalOrderPrice();
|
get()._updateTotalOrderPrice();
|
||||||
|
get().fillOrderExtData();
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@ -150,10 +154,12 @@ const useImportJSON = ((set, get) => ({
|
|||||||
return {
|
return {
|
||||||
importShouldOpen: false,
|
importShouldOpen: false,
|
||||||
// additional fields go here
|
// additional fields go here
|
||||||
crates: parsed.crates
|
crates: parsed.crates,
|
||||||
|
order_options_data: parsed.order_options_data
|
||||||
}}),
|
}}),
|
||||||
loadDescription: () => {
|
loadDescription: () => {
|
||||||
get()._loadDescription()
|
get()._loadDescription()
|
||||||
|
get().fillOrderExtData();
|
||||||
get().crates.forEach((crate, _i) => {
|
get().crates.forEach((crate, _i) => {
|
||||||
get().fillExtData(crate.id);
|
get().fillExtData(crate.id);
|
||||||
get().fillWarnings(crate.id);
|
get().fillWarnings(crate.id);
|
||||||
@ -317,7 +323,7 @@ const useCart = ((set, get) => ({
|
|||||||
}),
|
}),
|
||||||
active_crate: crate_id || "crate" + state.crates.length
|
active_crate: crate_id || "crate" + state.crates.length
|
||||||
})),
|
})),
|
||||||
delCrate: (id) => set(state => ({
|
_delCrate: (id) => set(state => ({
|
||||||
crates: state.crates.filter((crate => crate.id !== id || !state.modes_order.includes(crate.crate_mode))),
|
crates: state.crates.filter((crate => crate.id !== id || !state.modes_order.includes(crate.crate_mode))),
|
||||||
active_crate: state.active_crate === id ? null : state.active_crate,
|
active_crate: state.active_crate === id ? null : state.active_crate,
|
||||||
})),
|
})),
|
||||||
@ -471,6 +477,8 @@ const useCart = ((set, get) => ({
|
|||||||
sum += item.price;
|
sum += item.price;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
const order_options = ProcessOptionsToData({options: get().order_prices, data: get().order_options_data || {}});
|
||||||
|
sum += order_options ? order_options.reduce((accumulator, currentValue) => accumulator+currentValue.price, 0) : 0;
|
||||||
return {total_order_price: sum};
|
return {total_order_price: sum};
|
||||||
}),
|
}),
|
||||||
|
|
||||||
@ -481,6 +489,7 @@ const useCart = ((set, get) => ({
|
|||||||
get()._newCrate(crate_id)
|
get()._newCrate(crate_id)
|
||||||
get().fillExtData(crate_id);
|
get().fillExtData(crate_id);
|
||||||
get().fillExtCrateData(crate_id);
|
get().fillExtCrateData(crate_id);
|
||||||
|
get().fillOrderExtData();
|
||||||
get().fillWarnings(crate_id);
|
get().fillWarnings(crate_id);
|
||||||
get()._updateTotalOrderPrice();
|
get()._updateTotalOrderPrice();
|
||||||
},
|
},
|
||||||
@ -489,11 +498,17 @@ const useCart = ((set, get) => ({
|
|||||||
get()._setCrateMode(id, mode)
|
get()._setCrateMode(id, mode)
|
||||||
get().fillExtData(id);
|
get().fillExtData(id);
|
||||||
get().fillExtCrateData(id);
|
get().fillExtCrateData(id);
|
||||||
|
get().fillOrderExtData();
|
||||||
get().fillWarnings(id);
|
get().fillWarnings(id);
|
||||||
get().setActiveCrate(id);
|
get().setActiveCrate(id);
|
||||||
get()._updateTotalOrderPrice();
|
get()._updateTotalOrderPrice();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
delCrate: (id) => {
|
||||||
|
get()._delCrate(id);
|
||||||
|
get().fillOrderExtData();
|
||||||
|
},
|
||||||
|
|
||||||
addCardFromBacklog: (crate_to, index_from, index_to, just_mounted) => {
|
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) {
|
if (!dest) {
|
||||||
|
@ -53,7 +53,7 @@ export function formatMoney(amount, decimalCount = 2, decimal = ".", thousands =
|
|||||||
let i = parseInt(amount = Math.abs(Number(amount) || 0).toFixed(decimalCount)).toString();
|
let i = parseInt(amount = Math.abs(Number(amount) || 0).toFixed(decimalCount)).toString();
|
||||||
let j = (i.length > 3) ? i.length % 3 : 0;
|
let j = (i.length > 3) ? i.length % 3 : 0;
|
||||||
|
|
||||||
return negativeSign + (j ? i.substr(0, j) + thousands : '') + i.substr(j).replace(/(\d{3})(?=\d)/g, "$1" + thousands) + (decimalCount ? decimal + Math.abs(amount - i).toFixed(decimalCount).slice(2) : "");
|
return negativeSign + (j ? i.substring(0, j) + thousands : '') + i.substring(j).replace(/(\d{3})(?=\d)/g, "$1" + thousands) + (decimalCount ? decimal + Math.abs(amount - i).toFixed(decimalCount).slice(2) : "");
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return amount;
|
return amount;
|
||||||
}
|
}
|
||||||
|
@ -66,20 +66,28 @@ const shop_data = {
|
|||||||
title: "Desktop Environment",
|
title: "Desktop Environment",
|
||||||
outvar: "nuc_desktop",
|
outvar: "nuc_desktop",
|
||||||
variants: ["Gnome", "KDE"],
|
variants: ["Gnome", "KDE"],
|
||||||
tip: "Gnome vs KDE",
|
tip: "Gnome has clean and minimalist design. KDE has more feature-rich and classic interface.",
|
||||||
fallback: 0
|
fallback: 0
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{type: "Line", args: {title: "Additional software to be pre-installed", outvar: "software", fallback: "",
|
{type: "Line", args: {title: "Additional software to be pre-installed", outvar: "software", fallback: "",
|
||||||
tip: "Pre-install additional software, if needed"}},
|
tip: "Pre-install additional software, if needed."}},
|
||||||
],
|
],
|
||||||
|
{"if": [
|
||||||
|
{"var": "ext_data.has_crate"},
|
||||||
|
{type: "Switch", args: {
|
||||||
|
title: "Opt-out from promotional USB stick",
|
||||||
|
outvar: "usb_stick_opt_out",
|
||||||
|
tip: "Choose if you don't need a USB stick and wish to receive configuration files via other electronic means (e.g. email or cloud).",
|
||||||
|
fallback: false,
|
||||||
|
}}
|
||||||
|
]},
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|
||||||
prices: [{
|
prices: [{
|
||||||
"if": [{"var": "nuc"}, {title: "Include optional pre-installed Intel® NUC mini-computer", price: 1300}, 0],
|
"if": [{"var": "nuc"}, {title: "Include optional pre-installed Intel® NUC mini-computer", price: 1300, disable_patch: {"nuc": false}, id: "nuc"}],
|
||||||
|
|
||||||
}]
|
}]
|
||||||
},
|
},
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user