Add basic demo example

Kinda works, but buggy

Signed-off-by: Egor Savkin <es@m-labs.hk>
Egor Savkin 2023-08-17 14:42:47 +08:00
parent 212a7743eb
commit b8a293f34a
5 changed files with 174 additions and 18 deletions

View File

@ -16,18 +16,19 @@
"@babel/core": "^7.22.8", "@babel/core": "^7.22.8",
"@babel/preset-env": "^7.22.7", "@babel/preset-env": "^7.22.7",
"@babel/preset-react": "^7.22.5", "@babel/preset-react": "^7.22.5",
"babel-preset-minify": "^0.5.2", "axios": "^1.4.0",
"babel-loader": "^9.1.3", "babel-loader": "^9.1.3",
"babel-preset-minify": "^0.5.2",
"bootstrap": "^5.3.0",
"jquery": "^3.7.0",
"prop-types": "^15.8.1",
"react": "^18.2.0",
"react-beautiful-dnd": "^13.1.1",
"react-dom": "^18.2.0",
"uuid": "^9.0.0",
"webpack": "^5.88.1", "webpack": "^5.88.1",
"webpack-cli": "^5.1.4", "webpack-cli": "^5.1.4",
"bootstrap": "^5.3.0", "json-logic-js": "^2.0.2"
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-beautiful-dnd": "^13.1.1",
"axios": "^1.4.0",
"prop-types": "^15.8.1",
"jquery": "^3.7.0",
"uuid": "^9.0.0"
}, },
"babel": { "babel": {
"presets": [ "presets": [

View File

@ -255,7 +255,7 @@ button {
.item-card-name, .item-card-name,
.price { .price {
> .alert-warning { > .alert-warning, > .alert-info {
background-color: inherit; background-color: inherit;
height: inherit; height: inherit;
width: 20px; width: 20px;
@ -382,7 +382,7 @@ button {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
/*max-width: 96px;*/ /*max-width: 96px;*/
max-width: 130px; max-width: 132px;
justify-content: flex-start; justify-content: flex-start;
align-content: center; align-content: center;
align-items: center; align-items: center;
@ -432,7 +432,7 @@ button {
height: 24px; height: 24px;
} }
> .alert-warning { > .alert-warning, > .alert-info {
background-color: inherit; background-color: inherit;
height: inherit; height: inherit;
width: 20px; width: 20px;
@ -508,6 +508,25 @@ button {
} }
} }
.overlayVariant {
top: 0;
width: 100%;
min-height: 70px;
position: absolute;
display: flex;
align-items: center;
justify-content: center;
background-color: white;
color: black;
flex-direction: column;
cursor: pointer;
p {
font-size: .65rem;
margin: 0;
}
}
} }
.hovered { .hovered {

View File

@ -6,6 +6,7 @@ import { createRoot } from "react-dom/client";
import PropTypes from "prop-types"; import PropTypes from "prop-types";
import { DragDropContext, Droppable, Draggable } from "react-beautiful-dnd"; import { DragDropContext, Droppable, Draggable } from "react-beautiful-dnd";
import { v4 as uuidv4 } from 'uuid'; import { v4 as uuidv4 } from 'uuid';
import ProcessOptions from "./shop_components.jsx";
const data = window.shop_data; const data = window.shop_data;
@ -622,7 +623,7 @@ class ProductCartItem extends React.PureComponent {
shouldTooltipWarningClassInverted, shouldTooltipWarningClassInverted,
} = this.props; } = this.props;
let warning; let warning, options, options_data;
if (data && data.warnings) { if (data && data.warnings) {
const warningsKeys = Object.keys(data.warnings); const warningsKeys = Object.keys(data.warnings);
if (warningsKeys && warningsKeys.length > 0) { if (warningsKeys && warningsKeys.length > 0) {
@ -631,6 +632,15 @@ class ProductCartItem extends React.PureComponent {
} }
} }
if (data && data.options) {
console.log(data.options_data);
options = data.options;
if (!data.options_data) data.options_data = {};
options_data = data.options_data;
}
let render_progress; let render_progress;
if (model.showProgress && data) { if (model.showProgress && data) {
switch(model.type) { switch(model.type) {
@ -699,9 +709,20 @@ class ProductCartItem extends React.PureComponent {
onMouseEnter={this.handleOnMouseEnterWarningItem.bind(this, index, warning)} onMouseEnter={this.handleOnMouseEnterWarningItem.bind(this, index, warning)}
onMouseLeave={this.handleOnMouseLeaveWarningItem.bind(this, index, warning)}> onMouseLeave={this.handleOnMouseLeaveWarningItem.bind(this, index, warning)}>
{warning && ( {warning ? (
<img className="alert-warning" src={warning ? `/images${warning.icon}` : null} /> <img className="alert-warning" src={`/images${warning.icon}`} />
)} ) : (options ? <img className="alert-info" src="/images/shop/icon-customize.svg" /> : null) }
{options ? (
<div
style={{'display': (model.showOverlayRemove && options) ? 'flex' : 'none'}}
className="overlayVariant">
{ProcessOptions({options: options, data: options_data, target: options_data})}
</div>
) : null }
{warning && model.showWarning && ( {warning && model.showWarning && (
<div className={`k-popup-warning ${shouldTooltipWarningClassInverted ? 'inverted': ''}`}> <div className={`k-popup-warning ${shouldTooltipWarningClassInverted ? 'inverted': ''}`}>
@ -848,7 +869,9 @@ class Cart extends React.PureComponent {
let itemData; let itemData;
if (data.itemsData && index in data.itemsData) { if (data.itemsData && index in data.itemsData) {
itemData = data.itemsData[index]; itemData = data.itemsData[index];
console.log(itemData.options_data);
} }
return ( return (
<ProductCartItem <ProductCartItem
isMobile={isMobile} isMobile={isMobile}
@ -1429,12 +1452,18 @@ class OrderSumary extends React.PureComponent {
</button> </button>
</div> </div>
{warning && ( {warning ? (
<img <img
style={{'marginLeft': '10px'}} style={{'marginLeft': '10px'}}
className="alert-warning" className="alert-warning"
src={`/images/${warning.icon}`} src={`/images/${warning.icon}`}
/> />
) : (
<img
style={{'marginLeft': '10px'}}
className="alert-warning"
src="/images/shop/icon-customize.svg"
/>
)} )}
{!warning && ( {!warning && (
@ -1833,10 +1862,11 @@ class Shop extends React.PureComponent {
type: this.state.currentMode, type: this.state.currentMode,
}; };
const clonedCart = Array.from(this.state.columns.cart.items); const clonedCart = Array.from(this.state.columns.cart.items);
console.log(clonedCart);
for (const i in clonedCart) { for (const i in clonedCart) {
const item = clonedCart[i]; const item = clonedCart[i];
crate.items.push({ crate.items.push({
'pn': item.name_number, 'pn': item.name_number
}); });
} }
@ -2040,6 +2070,8 @@ class Shop extends React.PureComponent {
const itemsCloned = Array.from(newItems); const itemsCloned = Array.from(newItems);
const itemsData = []; const itemsData = [];
console.log(prevItems);
console.log(this.state);
const rules = {}; const rules = {};
@ -2132,6 +2164,9 @@ class Shop extends React.PureComponent {
rules[ddkali.rules.follow.type] = {...ddkali.rules.follow}; rules[ddkali.rules.follow.type] = {...ddkali.rules.follow};
} }
} }
console.log(idx);
if (idx in this.state.columns.cart.itemsData && this.state.columns.cart.itemsData[idx].options_data)
itemsData[idx].options_data = this.state.columns.cart.itemsData[idx].options_data;
} }
if (idxK.length === 0) { if (idxK.length === 0) {

View File

@ -0,0 +1,73 @@
'use strict';
import React, {useState} from "react";
import jsonLogic from 'json-logic-js';
import { v4 as uuidv4 } from 'uuid';
// https://stackoverflow.com/a/70511311
const trueTypeOf = (obj) => Object.prototype.toString.call(obj).slice(8, -1).toLowerCase();
function Radio(target, {title, variants, outvar}) {
console.log(target)
function handleClick(variant) {
console.log(variant)
target[outvar] = variant;
//this.setState()
}
return (
<div className="shop-radio" key={uuidv4()}>
{title}
{variants.map((variant, _) => (
<div className="form-check" key={outvar + variant}>
<input
className="form-check-input"
type="radio"
name={outvar}
id={outvar + variant}
checked={target[outvar] === variant}
onClick={() => handleClick(variant)}
onChange={() => handleClick(variant)}
/>
<label className="form-check-label" htmlFor={outvar + variant}>
{variant}
</label>
</div>
))}
</div>
);
}
function MissingComponent(...args) {
console.error("Missing component with args:", args)
return <label style={{background: "red"}}>MISSING</label>
}
const componentsList = {
"Radio": Radio,
"Default": MissingComponent,
};
export default function ProcessOptions({options, data, target}) {
let options_t = trueTypeOf(options);
if (options_t === "array") {
return Array.from(
options.map((option_item, _) => ProcessOptions({options: option_item, data: data, target: target}))
);
} else if (options_t === "object") {
if (
trueTypeOf(options.type) === "string" &&
trueTypeOf(options.args) === "object"
) {
if (options.type in componentsList) {
return componentsList[options.type](target, options.args);
}else {
return componentsList["Default"](target, options.args);
}
} else {
return ProcessOptions({options: jsonLogic.apply(options, data), data: data, target: target});
}
}
}

View File

@ -64,6 +64,34 @@ const shop_data = {
nbrCurrentClock: 0, nbrCurrentClock: 0,
slotOccupied: 1, slotOccupied: 1,
clockOccupied: 0, clockOccupied: 0,
options: [
{type: "Radio", args: {title: "Variant", outvar: "variant", variants: ["standalone", "master", "satellite"]}},
{
"if": [
{
"in": [
{"var": "variant"}, [
"master", "standalone"
]
]
},
[
{type: "LineIPv4", args: {title: "IPv4", outvar: "ipv4", default: "192.168.1.75/24"}},
{type: "SwitchLine", args: {title: "IPv6", outvar: "ipv6"}},
{type: "SwitchLine", args: {title: "MAC", outvar: "mac"}},
{type: "Switch", args: {title: "Ext CLK", outvar: "ext_clk"}},
],
null
]
},
{
"if": [
{"===": [{"var": "ext_clk"}, true]},
{type: "line", args: {title: "Frequency", outvar: "ext_clk"}},
null
]
}
],
rules: { rules: {
maxSlot: { maxSlot: {
type: 'kasli-max-slot', type: 'kasli-max-slot',