Restored all the functionality, but needs UI fixes
Signed-off-by: Egor Savkin <es@m-labs.hk>
This commit is contained in:
parent
59f726e805
commit
ff7eac97dc
@ -23,4 +23,4 @@ export function CrateMode({crate_index}) {
|
|||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
@ -1,5 +1,71 @@
|
|||||||
|
import {useShopStore} from "./shop_store";
|
||||||
|
import {useClickAway} from "./options/useClickAway";
|
||||||
|
import {Modal} from "react-bootstrap";
|
||||||
|
import React from "react";
|
||||||
|
import {Validation} from "./validate";
|
||||||
|
|
||||||
|
const JSONExample = JSON.stringify({
|
||||||
|
"items": [{"pn": "1124"}, {"pn": "2118"}, {"pn": "2118"}, {"pn": "2128"}],
|
||||||
|
"type": "desktop"
|
||||||
|
});
|
||||||
|
|
||||||
export function ImportJSON() {
|
export function ImportJSON() {
|
||||||
return (
|
const {shouldShow, data, loadDescription, updateImportDescription, closeImport, showImport} = useShopStore(state => ({
|
||||||
<div> Import JSON PLACEHOLDER</div>
|
shouldShow: state.importShouldOpen,
|
||||||
)
|
data: state.importValue,
|
||||||
|
loadDescription: state.loadDescription,
|
||||||
|
updateImportDescription: state.updateImportDescription,
|
||||||
|
closeImport: state.closeImport,
|
||||||
|
showImport: state.openImport,
|
||||||
|
}));
|
||||||
|
|
||||||
|
const ref = useClickAway((e) => {
|
||||||
|
if (e.type === "mousedown") // ignore touchstart
|
||||||
|
closeImport()
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return (<>
|
||||||
|
<button
|
||||||
|
className="btn btn-sm btn-outline-primary m-0 mb-2"
|
||||||
|
style={{'cursor': 'pointer'}}
|
||||||
|
onClick={showImport}>Import JSON
|
||||||
|
</button>
|
||||||
|
<Modal show={shouldShow} animation={true} centered>
|
||||||
|
<Modal.Body ref={ref}>
|
||||||
|
<div className="form-group">
|
||||||
|
<p className="small">
|
||||||
|
Input the JSON description below. Should be something like:
|
||||||
|
<br/>
|
||||||
|
{JSONExample}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="form-group w-100">
|
||||||
|
<textarea
|
||||||
|
onChange={(event) => {
|
||||||
|
console.log(event)
|
||||||
|
updateImportDescription(event.target.value)
|
||||||
|
}}
|
||||||
|
value={data.value}
|
||||||
|
className="form-control w-100"
|
||||||
|
rows="5"
|
||||||
|
placeholder="Input JSON description here."/>
|
||||||
|
</div>
|
||||||
|
{data.error !== Validation.OK ? (
|
||||||
|
<div className="form-group">
|
||||||
|
<p className="text-danger">{data.error === Validation.Empty ? "Empty input" : "Invalid JSON"}</p>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
|
||||||
|
<div className="d-flex flex-column flex-sm-row justify-content-end">
|
||||||
|
<a type="button" onClick={closeImport}
|
||||||
|
className="btn btn-sm btn-outline-primary m-0 mb-2 mb-sm-0 mr-sm-2">Close</a>
|
||||||
|
<a type="button" onClick={loadDescription}
|
||||||
|
className={`btn btn-sm btn-primary m-0 ml-sm-2 ${data.error ? 'disabled' : ''}`}>Load
|
||||||
|
configuration</a>
|
||||||
|
</div>
|
||||||
|
</Modal.Body>
|
||||||
|
</Modal>
|
||||||
|
</>)
|
||||||
}
|
}
|
@ -1,6 +1,7 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import {validateEmail, Validation} from "./validate.js";
|
import {validateEmail, Validation} from "./validate.js";
|
||||||
import {useShopStore} from "./shop_store";
|
import {useShopStore} from "./shop_store";
|
||||||
|
import {ShowJSON} from "./ShowJSON";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Components that renders the form to request quote.
|
* Components that renders the form to request quote.
|
||||||
@ -10,20 +11,18 @@ export function OrderForm() {
|
|||||||
email,
|
email,
|
||||||
note,
|
note,
|
||||||
isProcessing,
|
isProcessing,
|
||||||
isProcessingComplete,
|
|
||||||
showDescription,
|
|
||||||
updateEmail,
|
updateEmail,
|
||||||
updateNote,
|
updateNote,
|
||||||
submitForm,
|
submitForm,
|
||||||
|
submitDisabled,
|
||||||
} = useShopStore(state => ({
|
} = useShopStore(state => ({
|
||||||
email: state.email,
|
email: state.email,
|
||||||
note: state.note,
|
note: state.note,
|
||||||
isProcessing: state.isProcessing,
|
isProcessing: state.isProcessing,
|
||||||
isProcessingComplete: state.isProcessingComplete,
|
|
||||||
showDescription: state.showDescription,
|
|
||||||
updateEmail: state.updateEmail,
|
updateEmail: state.updateEmail,
|
||||||
updateNote: state.updateNote,
|
updateNote: state.updateNote,
|
||||||
submitForm: state.submitForm,
|
submitForm: state.submitForm,
|
||||||
|
submitDisabled: state.submitDisabled
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
||||||
@ -59,14 +58,10 @@ export function OrderForm() {
|
|||||||
placeholder="Additional notes"/>
|
placeholder="Additional notes"/>
|
||||||
|
|
||||||
<div className="d-flex flex-column flex-sm-row justify-content-between">
|
<div className="d-flex flex-column flex-sm-row justify-content-between">
|
||||||
<input
|
<ShowJSON/>
|
||||||
className="btn btn-outline-primary w-100 m-0 mb-2 mb-sm-0 me-sm-2"
|
|
||||||
style={{'cursor': 'pointer', 'fontWeight': '700'}}
|
|
||||||
defaultValue="Show JSON"
|
|
||||||
onClick={showDescription}
|
|
||||||
readOnly={true}/>
|
|
||||||
|
|
||||||
<input className="btn btn-primary w-100 m-0 ms-sm-2" type="submit"
|
<input className="btn btn-primary w-100 m-0 ms-sm-2" type="submit"
|
||||||
|
disabled={submitDisabled()}
|
||||||
value={`${isProcessing ? 'Processing ...' : 'Request quote'}`}/>
|
value={`${isProcessing ? 'Processing ...' : 'Request quote'}`}/>
|
||||||
</div>
|
</div>
|
||||||
{/*This will open an email window. Send the email to make your request.*/}
|
{/*This will open an email window. Send the email to make your request.*/}
|
||||||
|
@ -3,6 +3,8 @@ import {OrderSummary} from "./OrderSummary";
|
|||||||
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";
|
||||||
|
import {ImportJSON} from "./ImportJSON";
|
||||||
|
import {RFQFeedback} from "./RFQFeedback";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component that renders all things for order.
|
* Component that renders all things for order.
|
||||||
@ -22,13 +24,11 @@ export function OrderPanel({title, description}) {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<button
|
<ImportJSON/>
|
||||||
className="btn btn-sm btn-outline-primary m-0 mb-2"
|
|
||||||
style={{'cursor': 'pointer'}}
|
|
||||||
onClick={onClickOpenImport}>Import JSON
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<RFQFeedback/>
|
||||||
|
|
||||||
{isMobile ? (
|
{isMobile ? (
|
||||||
<div className="mobileBtnDisplaySideMenu">
|
<div className="mobileBtnDisplaySideMenu">
|
||||||
<button onClick={onClickToggleMobileSideMenu}>
|
<button onClick={onClickToggleMobileSideMenu}>
|
||||||
|
36
static/js/shop/RFQFeedback.jsx
Normal file
36
static/js/shop/RFQFeedback.jsx
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
import {useShopStore} from "./shop_store";
|
||||||
|
import {useClickAway} from "./options/useClickAway";
|
||||||
|
import {Modal} from "react-bootstrap";
|
||||||
|
import {Validation} from "./validate";
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
export function RFQFeedback() {
|
||||||
|
const {closeRFQ, shouldShow, status} = useShopStore(state => ({
|
||||||
|
closeRFQ: state.closeRFQFeedback,
|
||||||
|
shouldShow: state.shouldShowRFQFeedback,
|
||||||
|
status: state.processingResult
|
||||||
|
}))
|
||||||
|
|
||||||
|
const ref = useClickAway((e) => {
|
||||||
|
if (e.type === "mousedown") // ignore touchstart
|
||||||
|
closeRFQ()
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal show={shouldShow} animation={true} centered>
|
||||||
|
<Modal.Body ref={ref}>
|
||||||
|
<div className="d-flex">
|
||||||
|
<div>
|
||||||
|
{status.status === Validation.OK ?
|
||||||
|
<img width="30px" src="/images/shop/icon-done.svg" alt="close"/>
|
||||||
|
: <img width="30px" src="/images/shop/icon-warning.svg" alt="close"/>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
<div style={{'padding': '0 .5em'}}>
|
||||||
|
{status.message}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Modal.Body>
|
||||||
|
</Modal>
|
||||||
|
)
|
||||||
|
}
|
@ -8,7 +8,7 @@ import {OrderPanel} from "./OrderPanel";
|
|||||||
import {useShopStore} from "./shop_store";
|
import {useShopStore} from "./shop_store";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component that render the entire shop
|
* Component that renders the entire shop
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export function Shop() {
|
export function Shop() {
|
||||||
@ -18,7 +18,7 @@ export function Shop() {
|
|||||||
deleteCard: state.deleteCard,
|
deleteCard: state.deleteCard,
|
||||||
cardIndexById: state.cardIndexById
|
cardIndexById: state.cardIndexById
|
||||||
}));
|
}));
|
||||||
const handleOnDragEnd = (drop_result, provided) => {
|
const handleOnDragEnd = (drop_result, _provided) => {
|
||||||
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 +28,7 @@ export function Shop() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
addCardFromBacklog(null, [cardIndexById("kasli"), cardIndexById("eem_pwr_mod")], -1);
|
addCardFromBacklog(null, [cardIndexById("eem_pwr_mod"), cardIndexById("kasli")], -1);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -1,5 +1,43 @@
|
|||||||
|
import React from "react";
|
||||||
|
import {Modal} from "react-bootstrap";
|
||||||
|
import {useShopStore} from "./shop_store";
|
||||||
|
import {useClickAway} from "./options/useClickAway";
|
||||||
|
|
||||||
export function ShowJSON() {
|
export function ShowJSON() {
|
||||||
return (
|
const {shouldShow, description, showDescription, closeDescription} = useShopStore(state => ({
|
||||||
<div> SHOW JSON PLACEHOLDER</div>
|
shouldShow: state.shouldShowDescription,
|
||||||
)
|
description: state.description,
|
||||||
|
closeDescription: state.closeDescription,
|
||||||
|
showDescription: state.showDescription,
|
||||||
|
}));
|
||||||
|
|
||||||
|
const ref = useClickAway((e) => {
|
||||||
|
if (e.type === "mousedown") // ignore touchstart
|
||||||
|
closeDescription()
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return (<>
|
||||||
|
<input
|
||||||
|
className="btn btn-outline-primary w-100 m-0 mb-2 mb-sm-0 me-sm-2"
|
||||||
|
style={{'cursor': 'pointer', 'fontWeight': '700'}}
|
||||||
|
defaultValue="Show JSON"
|
||||||
|
onClick={showDescription}
|
||||||
|
readOnly={true}/>
|
||||||
|
<Modal show={shouldShow} animation={true} centered>
|
||||||
|
<Modal.Body ref={ref}>
|
||||||
|
<textarea
|
||||||
|
value={description}
|
||||||
|
className="form-control w-100"
|
||||||
|
rows={10}
|
||||||
|
readOnly={true}
|
||||||
|
placeholder="There should be description of the crate"/>
|
||||||
|
|
||||||
|
<div className="d-flex flex-column flex-sm-row justify-content-end m-1">
|
||||||
|
<a type="button" onClick={closeDescription}
|
||||||
|
className="btn btn-sm btn-outline-primary m-0 mb-2 mb-sm-0 mr-sm-2">Close</a>
|
||||||
|
</div>
|
||||||
|
</Modal.Body>
|
||||||
|
</Modal>
|
||||||
|
</>)
|
||||||
}
|
}
|
@ -1,4 +1,6 @@
|
|||||||
import {useShopStore} from "./shop_store";
|
import {useShopStore} from "./shop_store";
|
||||||
|
import {FilterOptions} from "./options/utils";
|
||||||
|
import {v4 as uuidv4} from "uuid";
|
||||||
|
|
||||||
|
|
||||||
export function validateJSON(description) {
|
export function validateJSON(description) {
|
||||||
@ -11,11 +13,15 @@ export function validateJSON(description) {
|
|||||||
const crate_modes = useShopStore.getState().crate_modes;
|
const crate_modes = useShopStore.getState().crate_modes;
|
||||||
const pn_to_card = useShopStore.getState().pn_to_cards;
|
const pn_to_card = useShopStore.getState().pn_to_cards;
|
||||||
|
|
||||||
for (const crate of crates_raw) {
|
try {
|
||||||
if (!crate.type || !crate.items || !(crate.type in crate_modes)) return false;
|
for (const crate of crates_raw) {
|
||||||
for (const card of crate.items) {
|
if (!crate.type || !crate.items || !(crate.type in crate_modes)) return false;
|
||||||
if (!(card.pn in pn_to_card)) return false;
|
for (const card of crate.items) {
|
||||||
|
if (!(card.pn in pn_to_card)) return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} catch (e) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -29,6 +35,7 @@ export function JSONToCrates(description) {
|
|||||||
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(),
|
||||||
options_data: card.options
|
options_data: card.options
|
||||||
}))),
|
}))),
|
||||||
warnings: [],
|
warnings: [],
|
||||||
|
@ -6,8 +6,8 @@ import {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 {TriggerCrateWarnings, TriggerWarnings} from "./warnings";
|
import {TriggerCrateWarnings, TriggerWarnings} from "./warnings";
|
||||||
import {Validation, validateEmail, validateNote} from "./validate";
|
import {Validation, validateEmail, validateNote, validateJSONInput} from "./validate";
|
||||||
import {CratesToJSON} from "./json_porter";
|
import {CratesToJSON, JSONToCrates} from "./json_porter";
|
||||||
|
|
||||||
|
|
||||||
const cards_to_pn_map = (cards) => {
|
const cards_to_pn_map = (cards) => {
|
||||||
@ -38,26 +38,46 @@ const useLayout = ((set, get) => ({
|
|||||||
isMobile: window.deviceIsMobile(),
|
isMobile: window.deviceIsMobile(),
|
||||||
sideMenuIsOpen: false,
|
sideMenuIsOpen: false,
|
||||||
newCardJustAdded: false,
|
newCardJustAdded: false,
|
||||||
importIsOpen: false,
|
|
||||||
|
|
||||||
switchSideMenu: () => set(state => ({
|
switchSideMenu: () => set(state => ({
|
||||||
sideMenuIsOpen: !state.sideMenuIsOpen
|
sideMenuIsOpen: !state.sideMenuIsOpen
|
||||||
})),
|
})),
|
||||||
|
}));
|
||||||
|
|
||||||
|
const useImportJSON = ((set, get) => ({
|
||||||
|
importShouldOpen: false,
|
||||||
|
importValue: {
|
||||||
|
value: "",
|
||||||
|
error: Validation.OK
|
||||||
|
},
|
||||||
openImport: () => set(state => ({
|
openImport: () => set(state => ({
|
||||||
importIsOpen: true
|
importShouldOpen: true
|
||||||
})),
|
})),
|
||||||
closeImport: () => set(state => ({
|
closeImport: () => set(state => ({
|
||||||
importIsOpen: false
|
importShouldOpen: false
|
||||||
})),
|
})),
|
||||||
}))
|
loadDescription: () => set(state => ({
|
||||||
|
importShouldOpen: false,
|
||||||
|
crates: JSONToCrates(state.importValue.value)
|
||||||
|
})),
|
||||||
|
updateImportDescription: (new_description) => set(state => ({
|
||||||
|
importValue: {
|
||||||
|
value: new_description,
|
||||||
|
error: validateJSONInput(new_description)
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
|
||||||
|
}));
|
||||||
|
|
||||||
const useSubmitForm = ((set, get) => ({
|
const useSubmitForm = ((set, get) => ({
|
||||||
// TODO think about it
|
// TODO think about it
|
||||||
isProcessing: false,
|
isProcessing: false,
|
||||||
shouldShowRFQFeedback: true,
|
shouldShowRFQFeedback: false,
|
||||||
RFQBodyType: 'email',
|
processingResult: {
|
||||||
isProcessingComplete: true,
|
status: Validation.OK,
|
||||||
|
message: ""
|
||||||
|
},
|
||||||
|
API_RFQ: shared_data.API_RFQ,
|
||||||
email: {
|
email: {
|
||||||
value: "",
|
value: "",
|
||||||
error: null
|
error: null
|
||||||
@ -83,6 +103,17 @@ const useSubmitForm = ((set, get) => ({
|
|||||||
}
|
}
|
||||||
})),
|
})),
|
||||||
|
|
||||||
|
_revalidateForm: () => set(state => ({
|
||||||
|
email: {
|
||||||
|
value: state.email.value,
|
||||||
|
error: validateEmail(state.email.value)
|
||||||
|
},
|
||||||
|
note: {
|
||||||
|
value: state.note.value,
|
||||||
|
error: validateEmail(state.note.value)
|
||||||
|
},
|
||||||
|
})),
|
||||||
|
|
||||||
updateDescription: () => set(state => ({
|
updateDescription: () => set(state => ({
|
||||||
description: CratesToJSON(state.crates)
|
description: CratesToJSON(state.crates)
|
||||||
})),
|
})),
|
||||||
@ -93,7 +124,41 @@ const useSubmitForm = ((set, get) => ({
|
|||||||
closeDescription: () => set(state => ({
|
closeDescription: () => set(state => ({
|
||||||
shouldShowDescription: false
|
shouldShowDescription: false
|
||||||
})),
|
})),
|
||||||
submitForm: () => set(state => ({})) // TODO
|
_submitForm: () => set(state => ({isProcessing: true})),
|
||||||
|
finishSubmitForm: (result) => set(state => ({
|
||||||
|
isProcessing: false,
|
||||||
|
shouldShowRFQFeedback: true,
|
||||||
|
processingResult: result})),
|
||||||
|
|
||||||
|
submitDisabled: () => (get().email.error !== Validation.OK),
|
||||||
|
|
||||||
|
submitForm: () => {
|
||||||
|
get().updateDescription();
|
||||||
|
get()._revalidateForm();
|
||||||
|
get()._submitForm();
|
||||||
|
if (get().submitDisabled()) return;
|
||||||
|
fetch(get().API_RFQ, {
|
||||||
|
method: "POST",
|
||||||
|
headers: {'Content-Type': 'application/json'},
|
||||||
|
body: JSON.stringify({
|
||||||
|
email: get().email.value,
|
||||||
|
note: get().note.value,
|
||||||
|
configuration: get().description
|
||||||
|
})
|
||||||
|
}).then(response => {
|
||||||
|
if (response.status !== 200) {
|
||||||
|
throw Error("Response status is not OK: " + response.status + ".\n" + response);
|
||||||
|
}
|
||||||
|
get().finishSubmitForm({status: Validation.OK, message: "We've received your request and will be in contact soon."})
|
||||||
|
}).catch(err => {
|
||||||
|
console.error("Request failed, reason:", err)
|
||||||
|
get().finishSubmitForm({
|
||||||
|
status: Validation.Invalid,
|
||||||
|
message: "We cannot receive your request. Try using the export by coping the configuration and send it to us at sales@m-labs.hk"
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
closeRFQFeedback: () => set(state => ({shouldShowRFQFeedback: false}))
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const useHighlighted = ((set, get) => ({
|
const useHighlighted = ((set, get) => ({
|
||||||
@ -263,7 +328,6 @@ const useCart = ((set, get) => ({
|
|||||||
},
|
},
|
||||||
|
|
||||||
setCrateMode: (id, mode) => {
|
setCrateMode: (id, mode) => {
|
||||||
console.log("setCrateMode", id, mode)
|
|
||||||
get()._setCrateMode(id, mode)
|
get()._setCrateMode(id, mode)
|
||||||
get().fillWarnings(id);
|
get().fillWarnings(id);
|
||||||
},
|
},
|
||||||
@ -292,8 +356,6 @@ const useCart = ((set, get) => ({
|
|||||||
get()._updateOptions(crate_id, index, new_options);
|
get()._updateOptions(crate_id, index, new_options);
|
||||||
get().fillWarnings(crate_id);
|
get().fillWarnings(crate_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO load and save jsons?
|
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
|
||||||
@ -304,4 +366,5 @@ export const useShopStore = create((...params) => ({
|
|||||||
...useSubmitForm(...params),
|
...useSubmitForm(...params),
|
||||||
...useLayout(...params),
|
...useLayout(...params),
|
||||||
...useHighlighted(...params),
|
...useHighlighted(...params),
|
||||||
|
...useImportJSON(...params),
|
||||||
}))
|
}))
|
@ -20,8 +20,8 @@ module.exports = {
|
|||||||
resolve: {
|
resolve: {
|
||||||
extensions: ['.tsx', '.ts', '.js', '.jsx'],
|
extensions: ['.tsx', '.ts', '.js', '.jsx'],
|
||||||
},
|
},
|
||||||
devtool: "inline-source-map",
|
//devtool: "inline-source-map",
|
||||||
mode: "development"
|
//mode: "development"
|
||||||
//devtool: false,
|
devtool: false,
|
||||||
//mode: "production"
|
mode: "production"
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user