genesis
This commit is contained in:
38
.eslintrc
Normal file
38
.eslintrc
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
{
|
||||||
|
"parser": "@babel/eslint-parser",
|
||||||
|
"env": {
|
||||||
|
"browser": true,
|
||||||
|
"commonjs": true,
|
||||||
|
"es6": true,
|
||||||
|
"node": false
|
||||||
|
},
|
||||||
|
"rules": {
|
||||||
|
"react/prop-types": "off",
|
||||||
|
"no-restricted-imports": [
|
||||||
|
"error",
|
||||||
|
{
|
||||||
|
"patterns": ["@mui/*/*/*", "!@mui/material/test-utils/*"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"parserOptions": {
|
||||||
|
"requireConfigFile": false,
|
||||||
|
"babelOptions": {
|
||||||
|
"presets": ["@babel/preset-react"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"plugins": [
|
||||||
|
"react",
|
||||||
|
"@studysync/eslint-plugin-material-ui"
|
||||||
|
],
|
||||||
|
"extends": [
|
||||||
|
"eslint:recommended",
|
||||||
|
"plugin:react/recommended",
|
||||||
|
"plugin:react/jsx-runtime"
|
||||||
|
],
|
||||||
|
"settings": {
|
||||||
|
"react": {
|
||||||
|
"version": "detect"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
node_modules
|
||||||
|
dist
|
||||||
38
package.json
Normal file
38
package.json
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
{
|
||||||
|
"name": "search",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "search.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/eslint-parser": "^7.25.1",
|
||||||
|
"@emotion/react": "^11.13.3",
|
||||||
|
"@emotion/styled": "^11.13.0",
|
||||||
|
"@fontsource/source-sans-pro": "^5.0.8",
|
||||||
|
"@mui/icons-material": "^6.0.2",
|
||||||
|
"@mui/material": "^6.0.2",
|
||||||
|
"@mui/styled-engine": "^6.0.2",
|
||||||
|
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.15",
|
||||||
|
"@studysync/eslint-plugin-material-ui": "^1.2.1",
|
||||||
|
"async": "^3.2.6",
|
||||||
|
"babel-loader": "^9.1.3",
|
||||||
|
"compression": "^1.7.4",
|
||||||
|
"css-loader": "^7.1.2",
|
||||||
|
"eslint-plugin-react": "^7.35.2",
|
||||||
|
"eslint-webpack-plugin": "^4.2.0",
|
||||||
|
"express": "^4.19.2",
|
||||||
|
"html-webpack-plugin": "^5.6.0",
|
||||||
|
"mssql": "^11.0.1",
|
||||||
|
"mysql": "^2.18.1",
|
||||||
|
"react": "^18.3.1",
|
||||||
|
"socket.io": "^4.7.5",
|
||||||
|
"socket.io-client": "^4.7.5",
|
||||||
|
"style-loader": "^4.0.0",
|
||||||
|
"webpack-dev-middleware": "^7.4.2",
|
||||||
|
"webpack-hot-middleware": "^2.26.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
236
search.js
Normal file
236
search.js
Normal file
@@ -0,0 +1,236 @@
|
|||||||
|
const webpack = require("webpack");
|
||||||
|
const ReactRefreshWebpackPlugin = require("@pmmmwh/react-refresh-webpack-plugin");
|
||||||
|
const HtmlWebpackPlugin = require("html-webpack-plugin");
|
||||||
|
const ESLintPlugin = require("eslint-webpack-plugin");
|
||||||
|
const fs = require("fs");
|
||||||
|
const isDev = false;
|
||||||
|
|
||||||
|
const compiler = webpack({
|
||||||
|
mode: isDev ? "development" : "production",
|
||||||
|
entry: ["./src/index.js", ...(isDev ? ["webpack-hot-middleware/client?reload=true&overlay=true"] : [])],
|
||||||
|
module: {
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
test: /\.js$/,
|
||||||
|
exclude: /node_modules/,
|
||||||
|
use: [
|
||||||
|
{
|
||||||
|
loader: require.resolve("babel-loader"),
|
||||||
|
options: {
|
||||||
|
plugins: [isDev && require.resolve("react-refresh/babel")].filter(Boolean),
|
||||||
|
presets: [["@babel/preset-react", { runtime: "automatic" }]]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.css$/,
|
||||||
|
use: ["style-loader", "css-loader"]
|
||||||
|
}
|
||||||
|
/* {
|
||||||
|
test: /\.(woff(2)?|ttf|eot|svg)(\?v=\d+\.\d+\.\d+)?$/,
|
||||||
|
use: [
|
||||||
|
{
|
||||||
|
loader: 'file-loader',
|
||||||
|
options: {
|
||||||
|
name: '[name].[ext]',
|
||||||
|
outputPath: 'fonts/'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}*/
|
||||||
|
/*{
|
||||||
|
test: /\.(woff|woff2)$/i,
|
||||||
|
use: ['base64-inline-loader'],
|
||||||
|
type: 'javascript/auto'
|
||||||
|
}*/
|
||||||
|
]
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
new HtmlWebpackPlugin({
|
||||||
|
templateContent: "<!DOCTYPE html>\n<html><head>" + '<meta name="viewport" content="width=device-width, initial-scale=1"><link rel="icon" href="data:;base64,iVBORw0KGgo="></head><body style="background-color: rgb(192,208,208)"></body></html>'
|
||||||
|
}),
|
||||||
|
//new BundleAnalyzerPlugin({analyzerHost:'0.0.0.0'}),
|
||||||
|
...(isDev ? [new ReactRefreshWebpackPlugin(), new webpack.HotModuleReplacementPlugin(), new ESLintPlugin()] : [])
|
||||||
|
],
|
||||||
|
resolve: {
|
||||||
|
extensions: ["*", ".js"],
|
||||||
|
fallback: { crypto: false }
|
||||||
|
},
|
||||||
|
performance: {
|
||||||
|
maxEntrypointSize: 2024000,
|
||||||
|
maxAssetSize: 2024000
|
||||||
|
},
|
||||||
|
devtool: isDev ? "source-map" : false,
|
||||||
|
optimization: {
|
||||||
|
moduleIds: "deterministic",
|
||||||
|
splitChunks: {
|
||||||
|
chunks: "all",
|
||||||
|
cacheGroups: {
|
||||||
|
commons: {
|
||||||
|
test: /[\\/]node_modules[\\/]/,
|
||||||
|
name: "vendors",
|
||||||
|
chunks: "all"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
output: {
|
||||||
|
filename: "[name].[contenthash].js",
|
||||||
|
chunkFilename: "[name].[contenthash].js",
|
||||||
|
clean: true,
|
||||||
|
asyncChunks: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const express = require("express");
|
||||||
|
const app = express();
|
||||||
|
const http = require("http");
|
||||||
|
const server = http.createServer(app);
|
||||||
|
const compression = require("compression");
|
||||||
|
const { Server } = require("socket.io");
|
||||||
|
const async = require("async");
|
||||||
|
|
||||||
|
var onlyOnce = true;
|
||||||
|
|
||||||
|
async function run() {
|
||||||
|
|
||||||
|
const io = new Server(server);
|
||||||
|
const interval = setInterval(async () => {
|
||||||
|
const sockets = await io.fetchSockets();
|
||||||
|
|
||||||
|
async.forEachOf(
|
||||||
|
sockets,
|
||||||
|
async function (socket, key, callback) {
|
||||||
|
if (socket.data && socket.data.auth) {
|
||||||
|
callback();
|
||||||
|
} else {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async function (err) {}
|
||||||
|
);
|
||||||
|
}, 1000 * 10);
|
||||||
|
|
||||||
|
let globalHash;
|
||||||
|
|
||||||
|
var connListener = io.on("connection", (socket) => {
|
||||||
|
if (socket.handshake.headers.authorization) {
|
||||||
|
const authheader = socket.handshake.headers.authorization;
|
||||||
|
const auth = new Buffer.from(authheader.split(" ")[1], "base64").toString().split(":");
|
||||||
|
console.log(auth);
|
||||||
|
}
|
||||||
|
socket.on("getHash", () => {
|
||||||
|
if (globalHash) socket.emit("hash", globalHash);
|
||||||
|
});
|
||||||
|
runapp(socket);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (isDev) {
|
||||||
|
app.use(
|
||||||
|
require("webpack-dev-middleware")(compiler, {
|
||||||
|
headers: (req, res, context) => {
|
||||||
|
if (req.url == "/") {
|
||||||
|
res.setHeader("Cache-Control", "max-age=0");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
app.use(require("webpack-hot-middleware")(compiler));
|
||||||
|
|
||||||
|
compiler.hooks.done.tap("MyPlugin", (params) => {
|
||||||
|
globalHash = params.toJson().hash;
|
||||||
|
if (onlyOnce) io.emit("hash", globalHash);
|
||||||
|
onlyOnce = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
} else {
|
||||||
|
compiler.run((err, stats) => {
|
||||||
|
if (err || stats.hasErrors()) {
|
||||||
|
console.log(err);
|
||||||
|
}
|
||||||
|
globalHash = "prod" + stats.hash;
|
||||||
|
io.emit("hash", globalHash);
|
||||||
|
console.log("prod" + stats.hash);
|
||||||
|
console.log(stats.toString({ colors: true }));
|
||||||
|
});
|
||||||
|
|
||||||
|
app.use(function (req, res, next) {
|
||||||
|
if (req.path == "/") {
|
||||||
|
express.static("dist")(req, res, next);
|
||||||
|
} else {
|
||||||
|
express.static("dist", { maxAge: 60 * 60 * 24 * 100 * 1000 })(req, res, next);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
app.use(compression());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
let printerOnline = false;
|
||||||
|
|
||||||
|
|
||||||
|
server.listen(1111, "0.0.0.0", () => {});
|
||||||
|
}
|
||||||
|
|
||||||
|
run();
|
||||||
|
|
||||||
|
var mysql = require('mysql');
|
||||||
|
var connection = mysql.createConnection({
|
||||||
|
host : 'localhost',
|
||||||
|
user : 'jtlshop',
|
||||||
|
password : 'jtlshop',
|
||||||
|
database : 'jtldb'
|
||||||
|
});
|
||||||
|
connection.connect();
|
||||||
|
|
||||||
|
function permute(nums) {
|
||||||
|
let result = [];
|
||||||
|
if (nums.length === 0) return [];
|
||||||
|
if (nums.length === 1) return [nums];
|
||||||
|
for (let i = 0; i < nums.length; i++) {
|
||||||
|
const currentNum = nums[i];
|
||||||
|
const remainingNums = nums.slice(0, i).concat(nums.slice(i + 1));
|
||||||
|
const remainingNumsPermuted = permute(remainingNums);
|
||||||
|
for (let j = 0; j < remainingNumsPermuted.length; j++) {
|
||||||
|
const permutedArray = [currentNum].concat(remainingNumsPermuted[j]);
|
||||||
|
result.push(permutedArray);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function runapp(socket){
|
||||||
|
|
||||||
|
socket.on("search", (text, callback) => {
|
||||||
|
|
||||||
|
try{
|
||||||
|
|
||||||
|
if(text.length > 2){
|
||||||
|
|
||||||
|
let queries = [];
|
||||||
|
let qstr = '';
|
||||||
|
|
||||||
|
for(const per of permute(text.toString().trim().replace(/ {2,}/g, " ").split(' '))){
|
||||||
|
queries.push('%'+(per.join('%'))+'%');
|
||||||
|
qstr+= ' OR cName LIKE ? ';
|
||||||
|
}
|
||||||
|
|
||||||
|
connection.query('SELECT tartikel.kArtikel,cArtNr,cName,cSeo FROM tartikel LEFT OUTER JOIN tartikelpict ON (tartikelpict.kArtikel = tartikel.kArtikel) WHERE 1=2 '+qstr+' limit 15',queries, function (error, results) {
|
||||||
|
if (callback) callback(error,results);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
}else{
|
||||||
|
callback(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(e){
|
||||||
|
callback(e);
|
||||||
|
console.log('exception',e);
|
||||||
|
}
|
||||||
|
finally{
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
90
src/Content.js
Normal file
90
src/Content.js
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
import {
|
||||||
|
Paper,
|
||||||
|
TextField,
|
||||||
|
Stack,
|
||||||
|
Popper,
|
||||||
|
Avatar,
|
||||||
|
Typography,
|
||||||
|
Card,
|
||||||
|
InputAdornment
|
||||||
|
} from "@mui/material";
|
||||||
|
|
||||||
|
import SearchIcon from "@mui/icons-material/Search";
|
||||||
|
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
export default class Content extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
searchtext:'',
|
||||||
|
result:[],
|
||||||
|
anchorEl:null
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
handleSearch = (searchtext) => {
|
||||||
|
if(searchtext.trim().length > 2){
|
||||||
|
this.props.socket.emit('search',searchtext,(err,res)=>{
|
||||||
|
if(!err){
|
||||||
|
this.setState({ result:res });
|
||||||
|
console.log(res);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
console.log('Err',err);
|
||||||
|
this.setState({ result:[] });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
this.setState({ result:[] });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div style={{ width:'100%'}}>
|
||||||
|
<Stack spacing={2}>
|
||||||
|
<Card style={{ width:'100%',margin:'20px auto'}} sx={{ maxWidth: 'sm' }}>
|
||||||
|
<TextField
|
||||||
|
spellCheck={false}
|
||||||
|
InputProps={{
|
||||||
|
startAdornment: (
|
||||||
|
<InputAdornment>
|
||||||
|
<SearchIcon style={{ marginRight:'20px'}}/>
|
||||||
|
</InputAdornment>
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
value={this.state.searchtext}
|
||||||
|
inputRef={(input) => {input && input.focus()}}
|
||||||
|
onChange={(e) => {
|
||||||
|
this.setState({ anchorEl:e.target,searchtext: e.target.value });
|
||||||
|
this.handleSearch(e.target.value);
|
||||||
|
}}
|
||||||
|
autoComplete="off"
|
||||||
|
fullWidth
|
||||||
|
/>
|
||||||
|
</Card>
|
||||||
|
<Popper
|
||||||
|
open={this.state.result.length > 0}
|
||||||
|
anchorEl={this.state.anchorEl}
|
||||||
|
placement={'bottom-start'}
|
||||||
|
>
|
||||||
|
<Paper style={{ padding: 20}}>
|
||||||
|
<Stack>
|
||||||
|
{this.state.result.map((line,i)=>(
|
||||||
|
<Stack key={i} direction="row" spacing={2} style={{cursor: 'pointer',userSelect:'none'}} sx={{alignItems: "center"}} onClick={() => { window.location = 'https://t.growheads.de/'+line.cSeo }}>
|
||||||
|
<Avatar src={'https://t.growheads.de/media/image/product/'+(line.kArtikel)+'/xs/'+(line.cSeo)+'.jpg'} sx={{ width: 40, height: 40 }} variant="square"/>
|
||||||
|
<Typography>{line.cName}</Typography>
|
||||||
|
</Stack>
|
||||||
|
))}
|
||||||
|
</Stack>
|
||||||
|
</Paper>
|
||||||
|
</Popper>
|
||||||
|
</Stack>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
62
src/Wrapper.js
Normal file
62
src/Wrapper.js
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
const io = require("socket.io-client");
|
||||||
|
import React, { lazy, Suspense } from "react";
|
||||||
|
|
||||||
|
const Content = lazy(() => import("./Content"));
|
||||||
|
|
||||||
|
var globalHash;
|
||||||
|
|
||||||
|
export default class Wrapper extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
const socket = io("", { transports: ["websocket"] });
|
||||||
|
|
||||||
|
this.socket = socket;
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
socket: socket
|
||||||
|
};
|
||||||
|
|
||||||
|
this.setState.bind(this);
|
||||||
|
|
||||||
|
socket.io.on("reconnect", () => {
|
||||||
|
console.log('reconnect');
|
||||||
|
socket.emit('getHash');
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on("disconnect", (reason) => {
|
||||||
|
console.log('disconnect');
|
||||||
|
if (reason == "io server disconnect") {
|
||||||
|
setTimeout(() => {
|
||||||
|
console.log('reconnect attempt');
|
||||||
|
socket.connect();
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
socket.on("connect", () => {
|
||||||
|
console.log('connect');
|
||||||
|
socket.emit('getHash');
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on("hash", (hash) => {
|
||||||
|
console.log('hash',hash);
|
||||||
|
if (globalHash) {
|
||||||
|
if (globalHash !== hash) {
|
||||||
|
setTimeout(function () {
|
||||||
|
window.location.reload();
|
||||||
|
}, 1500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
globalHash = hash;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
componentDidMount() {}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<Suspense fallback={<div></div>}>
|
||||||
|
<Content socket={this.state.socket} />
|
||||||
|
</Suspense>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
53
src/index.js
Normal file
53
src/index.js
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
import * as ReactDOM from "react-dom/client";
|
||||||
|
import "@fontsource/source-sans-pro/300.css";
|
||||||
|
import "@fontsource/source-sans-pro/400.css";
|
||||||
|
import "@fontsource/source-sans-pro/600.css";
|
||||||
|
import "@fontsource/source-sans-pro/700.css";
|
||||||
|
import CssBaseline from "@mui/material/CssBaseline";
|
||||||
|
import { ThemeProvider, createTheme } from "@mui/material/styles";
|
||||||
|
|
||||||
|
import Wrapper from "./Wrapper";
|
||||||
|
|
||||||
|
import "./styles.css";
|
||||||
|
|
||||||
|
function App() {
|
||||||
|
return <Wrapper/>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const theme = createTheme({
|
||||||
|
palette: {
|
||||||
|
background: {
|
||||||
|
default: "#c0d0d0;"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
typography: {
|
||||||
|
fontFamily: "Source Sans Pro,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif",
|
||||||
|
fontWeightBold: 700,
|
||||||
|
fontWeightMedium: 600,
|
||||||
|
fontWeightRegular: 400,
|
||||||
|
fontWeightLight: 300
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
MuiTableCell: {
|
||||||
|
styleOverrides: {
|
||||||
|
head: {
|
||||||
|
fontWeight: 700
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
MuiInputBase: {
|
||||||
|
styleOverrides: {
|
||||||
|
input: {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var appDiv = document.createElement("div");
|
||||||
|
document.body.appendChild(appDiv);
|
||||||
|
ReactDOM.createRoot(appDiv).render(
|
||||||
|
<ThemeProvider theme={theme}>
|
||||||
|
<CssBaseline />
|
||||||
|
<App />
|
||||||
|
</ThemeProvider>
|
||||||
|
);
|
||||||
4
src/styles.css
Normal file
4
src/styles.css
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
body {
|
||||||
|
overflow-y: scroll;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user