Add css classes to the radio component, add shipping summary and other content fixes
Signed-off-by: Egor Savkin <es@m-labs.hk>
This commit is contained in:
parent
0b5797b1ba
commit
759f7cffcc
912
package-lock.json
generated
912
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
19
package.json
19
package.json
@ -13,24 +13,23 @@
|
|||||||
"url": "https://git.m-labs.hk/M-Labs/web2019.git"
|
"url": "https://git.m-labs.hk/M-Labs/web2019.git"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/cli": "^7.23.0",
|
"@babel/cli": "^7.23.9",
|
||||||
"@babel/core": "^7.23.2",
|
"@babel/core": "^7.23.9",
|
||||||
"@babel/preset-env": "^7.23.2",
|
"@babel/preset-env": "^7.23.9",
|
||||||
"@babel/preset-react": "^7.22.15",
|
"@babel/preset-react": "^7.23.3",
|
||||||
"babel-loader": "^9.1.3",
|
"babel-loader": "^9.1.3",
|
||||||
"babel-preset-minify": "^0.5.2",
|
"babel-preset-minify": "^0.5.2",
|
||||||
"bootstrap": "^5.3.0",
|
"bootstrap": "^5.3.2",
|
||||||
"jquery": "^3.7.0",
|
"jquery": "^3.7.1",
|
||||||
"prop-types": "^15.8.1",
|
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-bootstrap": "^2.9.1",
|
"react-bootstrap": "^2.10.0",
|
||||||
"@hello-pangea/dnd": "^16.5.0",
|
"@hello-pangea/dnd": "^16.5.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
"uuid": "^9.0.1",
|
"uuid": "^9.0.1",
|
||||||
"webpack": "^5.89.0",
|
"webpack": "^5.90.1",
|
||||||
"webpack-cli": "^5.1.4",
|
"webpack-cli": "^5.1.4",
|
||||||
"json-logic-js": "^2.0.2",
|
"json-logic-js": "^2.0.2",
|
||||||
"zustand": "^4.4.7",
|
"zustand": "^4.5.0",
|
||||||
"@uidotdev/usehooks":"^2.4.1",
|
"@uidotdev/usehooks":"^2.4.1",
|
||||||
"webpack-preprocessor-loader": "^1.3.0"
|
"webpack-preprocessor-loader": "^1.3.0"
|
||||||
},
|
},
|
||||||
|
File diff suppressed because one or more lines are too long
@ -6,6 +6,7 @@ import {SummaryCrate} from "./SummaryCrate";
|
|||||||
// #!render_count
|
// #!render_count
|
||||||
import {useRenderCount} from "@uidotdev/usehooks";
|
import {useRenderCount} from "@uidotdev/usehooks";
|
||||||
import {SummaryOrderPricedOptions} from "./SummaryOrderPricedOptions";
|
import {SummaryOrderPricedOptions} from "./SummaryOrderPricedOptions";
|
||||||
|
import {SummaryOrderShipping} from "./SummaryOrderShipping";
|
||||||
|
|
||||||
export function SummaryCrates() {
|
export function SummaryCrates() {
|
||||||
// #!render_count
|
// #!render_count
|
||||||
@ -22,6 +23,7 @@ export function SummaryCrates() {
|
|||||||
return <SummaryCrate crate_index={index} key={"summary_crate_body_" + index} />
|
return <SummaryCrate crate_index={index} key={"summary_crate_body_" + index} />
|
||||||
})}
|
})}
|
||||||
<SummaryOrderPricedOptions/>
|
<SummaryOrderPricedOptions/>
|
||||||
|
<SummaryOrderShipping/>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
35
static/js/shop/SummaryOrderShipping.jsx
Normal file
35
static/js/shop/SummaryOrderShipping.jsx
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import {formatMoney} from "./utils";
|
||||||
|
import React from "react";
|
||||||
|
import {useShopStore} from "./shop_store";
|
||||||
|
import {ProcessOptions, ProcessOptionsToData} from "./options/Options";
|
||||||
|
|
||||||
|
// #!render_count
|
||||||
|
import {useRenderCount} from "@uidotdev/usehooks";
|
||||||
|
|
||||||
|
export function SummaryOrderShipping() {
|
||||||
|
// #!render_count
|
||||||
|
const renderCount = useRenderCount();
|
||||||
|
|
||||||
|
const shipping_summary = useShopStore((state) => state.shipping_summary);
|
||||||
|
const options_data = useShopStore((state) => state.order_options_data);
|
||||||
|
|
||||||
|
// #!render_count
|
||||||
|
console.log("SummaryOrderShipping renders: ", renderCount)
|
||||||
|
|
||||||
|
const options = ProcessOptions({
|
||||||
|
options: shipping_summary,
|
||||||
|
data: options_data,
|
||||||
|
id: "shipping_options",
|
||||||
|
target: null,
|
||||||
|
});
|
||||||
|
|
||||||
|
return <tbody key="summary_shipping_order_body">
|
||||||
|
{options.map((option, i) => (
|
||||||
|
<tr key={"summary_shipping_order_option_" + i} id={"summary_shipping_order_option_" + i}>
|
||||||
|
<td className="item-card-name" key={"summary_shipping_order_key_option_" + i} id={"summary_shipping_order_key_option_" + i}>
|
||||||
|
{option}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
</tbody>;
|
||||||
|
}
|
17
static/js/shop/options/components/Label.jsx
Normal file
17
static/js/shop/options/components/Label.jsx
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import React from "react";
|
||||||
|
import {apply as json_logic_apply, add_operation as json_add_operation} from "json-logic-js";
|
||||||
|
|
||||||
|
|
||||||
|
json_add_operation("lower", (some_str) => some_str.toLowerCase(some_str));
|
||||||
|
json_add_operation("upper", (some_str) => some_str.toUpperCase(some_str));
|
||||||
|
json_add_operation("capitalize", (some_str) => some_str.capitalizeFirstLetter(some_str));
|
||||||
|
|
||||||
|
export function Label(target, id, data, {content}) {
|
||||||
|
const resulting_string = json_logic_apply(content, data).flat().join("");
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div id={id+"label"} key={id+"label"} className="options-label">
|
||||||
|
{resulting_string}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
@ -46,7 +46,7 @@ class Line extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function LineWrapper(target, id, data, {title, fallback, outvar, icon, tip}) {
|
export function LineWrapper(target, id, data, {title, fallback, outvar, icon, tip, classes}) {
|
||||||
return <Line target={target} title={title} fallback={fallback} outvar={outvar} icon={icon} tip={tip} key={id}
|
return <Line target={target} title={title} fallback={fallback} outvar={outvar} icon={icon} tip={tip} key={id}
|
||||||
id={id} data={data}/>;
|
id={id} data={data} classes={classes}/>;
|
||||||
}
|
}
|
@ -42,7 +42,7 @@ class Radio extends Component {
|
|||||||
</div>
|
</div>
|
||||||
{this.props.tip && <Tip id={this.props.id + "tooltip"} tip={this.props.tip}/>}
|
{this.props.tip && <Tip id={this.props.id + "tooltip"} tip={this.props.tip}/>}
|
||||||
{this.props.variants.map((variant, _) => (
|
{this.props.variants.map((variant, _) => (
|
||||||
<div className="form-check shop-radio-variant" key={key + variant}>
|
<div className={`form-check shop-radio-variant ${this.props.classes}`} key={key + variant}>
|
||||||
<input
|
<input
|
||||||
className="form-check-input"
|
className="form-check-input"
|
||||||
type="radio"
|
type="radio"
|
||||||
@ -62,8 +62,8 @@ class Radio extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function RadioWrapper(target, id, data, {title, variants, outvar, fallback, icon, tip}) {
|
export function RadioWrapper(target, id, data, {title, variants, outvar, fallback, icon, tip, classes}) {
|
||||||
return <Radio target={target} title={title} variants={variants} outvar={outvar} icon={icon} tip={tip} key={id}
|
return <Radio target={target} title={title} variants={variants} outvar={outvar} icon={icon} tip={tip} key={id}
|
||||||
fallback={fallback}
|
fallback={fallback} classes={classes}
|
||||||
id={id} data={data}/>;
|
id={id} data={data}/>;
|
||||||
}
|
}
|
@ -57,7 +57,7 @@ class Switch extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function SwitchWrapper(target, id, data, {title, fallback, outvar, icon, tip}) {
|
export function SwitchWrapper(target, id, data, {title, fallback, outvar, icon, tip, classes}) {
|
||||||
return <Switch target={target} title={title} fallback={fallback} outvar={outvar} icon={icon} tip={tip} key={id}
|
return <Switch target={target} title={title} fallback={fallback} outvar={outvar} icon={icon} tip={tip} key={id}
|
||||||
id={id} data={data}/>;
|
id={id} data={data} classes={classes}/>;
|
||||||
}
|
}
|
@ -71,7 +71,7 @@ class SwitchLine extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function SwitchLineWrapper(target, id, data, {title, fallback, outvar, icon, tip}) {
|
export function SwitchLineWrapper(target, id, data, {title, fallback, outvar, icon, tip, classes}) {
|
||||||
return <SwitchLine target={target} title={title} fallback={fallback} outvar={outvar} icon={icon} tip={tip} key={id}
|
return <SwitchLine target={target} title={title} fallback={fallback} outvar={outvar} icon={icon} tip={tip} key={id}
|
||||||
id={id} data={data}/>;
|
id={id} data={data} classes={classes}/>;
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ import {RadioWrapper} from "./Radio";
|
|||||||
import {SwitchWrapper} from "./Switch";
|
import {SwitchWrapper} from "./Switch";
|
||||||
import {SwitchLineWrapper} from "./SwitchLine";
|
import {SwitchLineWrapper} from "./SwitchLine";
|
||||||
import {UnimplementedComponent} from "./UnimplementedComponent";
|
import {UnimplementedComponent} from "./UnimplementedComponent";
|
||||||
|
import {Label} from "./Label";
|
||||||
|
|
||||||
|
|
||||||
// Class components are used because we cannot use hooks for updating the state
|
// Class components are used because we cannot use hooks for updating the state
|
||||||
@ -13,5 +14,6 @@ export const componentsList = {
|
|||||||
"Switch": SwitchWrapper,
|
"Switch": SwitchWrapper,
|
||||||
"Line": LineWrapper,
|
"Line": LineWrapper,
|
||||||
"SwitchLine": SwitchLineWrapper,
|
"SwitchLine": SwitchLineWrapper,
|
||||||
|
"Label": Label,
|
||||||
"Default": UnimplementedComponent,
|
"Default": UnimplementedComponent,
|
||||||
};
|
};
|
@ -82,6 +82,7 @@ const useCrateOptions = ((set, get) => ({
|
|||||||
const useOrderOptions = ((set, get) => ({
|
const useOrderOptions = ((set, get) => ({
|
||||||
order_options: shared_data.orderOptions.options,
|
order_options: shared_data.orderOptions.options,
|
||||||
order_prices: shared_data.orderOptions.prices,
|
order_prices: shared_data.orderOptions.prices,
|
||||||
|
shipping_summary: shared_data.orderOptions.shippingSummary,
|
||||||
order_options_data: {},
|
order_options_data: {},
|
||||||
|
|
||||||
fillOrderExtData: () => set(state => ({
|
fillOrderExtData: () => set(state => ({
|
||||||
|
@ -50,7 +50,7 @@ const shop_data = {
|
|||||||
options: [
|
options: [
|
||||||
{"type": "Group", items:[
|
{"type": "Group", items:[
|
||||||
{type: "Switch", args: {
|
{type: "Switch", args: {
|
||||||
title: "Include optional pre-installed Intel® NUC mini-computer",
|
title: "Include optional Intel® NUC mini-computer with pre-installed ARTIQ software",
|
||||||
outvar: "nuc",
|
outvar: "nuc",
|
||||||
tip: "OS: latest stable NixOS with Gnome or KDE with pre-installed ARTIQ software. " +
|
tip: "OS: latest stable NixOS with Gnome or KDE with pre-installed ARTIQ software. " +
|
||||||
"Hardware (other choices available): Intel® NUC 13 Pro Kit NUC13ANKi7, i7-1360P CPU, " +
|
"Hardware (other choices available): Intel® NUC 13 Pro Kit NUC13ANKi7, i7-1360P CPU, " +
|
||||||
@ -68,20 +68,30 @@ const shop_data = {
|
|||||||
outvar: "nuc_desktop",
|
outvar: "nuc_desktop",
|
||||||
variants: ["Gnome", "KDE"],
|
variants: ["Gnome", "KDE"],
|
||||||
tip: "Gnome has clean and minimalist design. KDE has more feature-rich and classic interface.",
|
tip: "Gnome has clean and minimalist design. KDE has more feature-rich and classic interface.",
|
||||||
fallback: 0
|
fallback: 0,
|
||||||
|
classes: "form-check-inline ms-4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{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": [
|
||||||
{"if": [
|
|
||||||
{"var": "ext_data.has_crate"},
|
{"var": "ext_data.has_crate"},
|
||||||
{type: "Switch", args: {
|
{type: "Switch", args: {
|
||||||
title: "Opt-out from promotional USB stick",
|
title: "Include promotional USB stick",
|
||||||
outvar: "usb_stick_opt_out",
|
outvar: "include_usb_stick_nuc",
|
||||||
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).",
|
tip: "Choose if you need a USB stick and wish to receive configuration files via other electronic means (e.g. email or cloud).",
|
||||||
fallback: false,
|
fallback: false,
|
||||||
}}
|
}}
|
||||||
|
]},
|
||||||
|
],
|
||||||
|
{"if": [
|
||||||
|
{"var": "ext_data.has_crate"},
|
||||||
|
{type: "Switch", args: {
|
||||||
|
title: "Include promotional USB stick",
|
||||||
|
outvar: "include_usb_stick",
|
||||||
|
tip: "Choose if you need a USB stick and wish to receive configuration files via other electronic means (e.g. email or cloud).",
|
||||||
|
fallback: true,
|
||||||
|
}}
|
||||||
]},
|
]},
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@ -127,7 +137,32 @@ const shop_data = {
|
|||||||
|
|
||||||
prices: [{
|
prices: [{
|
||||||
"if": [{"var": "nuc"}, {title: "Include optional pre-installed Intel® NUC mini-computer", price: 1300, disable_patch: {"nuc": false}, id: "nuc"}],
|
"if": [{"var": "nuc"}, {title: "Include optional pre-installed Intel® NUC mini-computer", price: 1300, disable_patch: {"nuc": false}, id: "nuc"}],
|
||||||
}]
|
}],
|
||||||
|
shippingSummary: [
|
||||||
|
{type: "Label", args: {
|
||||||
|
content: ["Shipping method: ", {"var": "shipping"}]
|
||||||
|
}},
|
||||||
|
{"if": [
|
||||||
|
{"var": "shipping_instructions"},
|
||||||
|
{type: "Label", args: {
|
||||||
|
content: [
|
||||||
|
{"if": [
|
||||||
|
{"==": [{"var": "shipping"}, "Incoterms 2020 FCA"]},
|
||||||
|
"carrier account information and/or other shipping instructions: ",
|
||||||
|
"delivery address: "
|
||||||
|
]},
|
||||||
|
{"var": "shipping_instructions"}
|
||||||
|
]
|
||||||
|
}}]},
|
||||||
|
{type: "Label", args: {
|
||||||
|
content: [
|
||||||
|
{"if": [
|
||||||
|
{"==": [{"var": "shipping"}, "Prepay and add shipping (only available to credit customers)"]},
|
||||||
|
["In case of additional customs fees: ", {"lower": {"var": "prepay_fees_handling"}}],
|
||||||
|
]}
|
||||||
|
]
|
||||||
|
}},
|
||||||
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
items: {
|
items: {
|
||||||
|
Loading…
Reference in New Issue
Block a user