This commit is contained in:
2018-08-14 00:02:06 -05:00
commit 4757abfff3
29 changed files with 14255 additions and 0 deletions

3
.babelrc Normal file
View File

@@ -0,0 +1,3 @@
{
"presets": ["env", "react"]
}

24
.compilerc Normal file
View File

@@ -0,0 +1,24 @@
{
"env": {
"development": {
"application/javascript": {
"presets": [
["env", { "targets": { "electron": "1.4" } }],
"react"
],
"plugins": ["transform-async-to-generator"],
"sourceMaps": "inline"
}
},
"production": {
"application/javascript": {
"presets": [
["env", { "targets": { "electron": "1.4" } }],
"react"
],
"plugins": ["transform-async-to-generator"],
"sourceMaps": "none"
}
}
}
}

3
.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
node_modules
out
build

6
.prettierrc Normal file
View File

@@ -0,0 +1,6 @@
{
"singleQuote": true,
"tabWidth": 2,
"trailingComma": "all",
"printWidth": 120
}

6
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,6 @@
{
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.organizeImports": true
}
}

2
@types/all/index.d.ts vendored Normal file
View File

@@ -0,0 +1,2 @@
// for libraries that don't have types
declare module 'this-is-a-test-module';

6
app/app.tsx Normal file
View File

@@ -0,0 +1,6 @@
import React from 'react';
import ReactDOM from 'react-dom';
import { Home } from './components';
import './scss/index.scss';
ReactDOM.render(<Home />, document.getElementById('app'));

97
app/components/home.tsx Normal file
View File

@@ -0,0 +1,97 @@
import { WebviewTag } from 'electron';
import React from 'react';
import { PoeService } from '../services/poe.service';
import { LoginWebview } from './login-webview';
import { PriceListItem } from './price-list-item/price-list-item';
interface IState {
showLogin: boolean;
data: any;
}
export class Home extends React.Component<any, IState> {
private webview: WebviewTag;
constructor(props: any) {
super(props);
this.state = {
showLogin: false,
data: [],
};
}
componentDidMount() {
this.addWebviewListeners();
}
public addWebviewListeners() {
this.webview = this.refs['webview'] as any;
this.webview.addEventListener('dom-ready', () => {
// this.webview.openDevTools();
});
this.webview.addEventListener('ipc-message', e => {
if (e.channel === 'html-content') {
const htmlContents = e.args[0];
this.handleResponse(htmlContents);
}
});
}
public handleResponse(res: any) {
const json = JSON.parse(res);
if (json === null || json['error']) {
this.setState({ showLogin: true });
} else if (json.items) {
this.setState({ showLogin: false, data: json.items });
this.getItemPrice(json.items, 0);
console.log(json.items);
}
}
onLogin = () => {
this.setState({ showLogin: false });
this.webview.reload();
};
async getItemPrice(data: any[], index: number) {
if (!data[index] || data !== this.state.data) {
return;
}
const res = await PoeService.priceCheck(data[index].typeLine);
if (res.currency_rec && res.min_price) {
const dataCopy: any = [...data];
dataCopy[index].priceInfo = res;
await new Promise(resolve => this.setState({ data: dataCopy }, resolve));
}
setTimeout(() => {
this.getItemPrice(this.state.data, index + 1);
}, 1000);
}
renderPriceList = (data: any[]) => {
return data.map((item, index) => <PriceListItem data={item} key={index} />);
};
public render() {
const { data, showLogin } = this.state;
return (
<div style={{ padding: '20px' }}>
{showLogin && <LoginWebview onSuccess={this.onLogin} />}
{data && this.renderPriceList(data)}
{/* {data && <StashTab data={data} />} */}
<webview
ref="webview"
partition="persist:poe"
preload="ipc-renderer.js"
src="https://www.pathofexile.com/character-window/get-stash-items?league=Incursion&tabs=1&tabIndex=13&accountName=DoctorCoctor"
style={{ opacity: 0, width: '0', height: '0' }}
/>
</div>
);
}
}

5
app/components/index.ts Normal file
View File

@@ -0,0 +1,5 @@
export * from './home';
export * from './login-webview';
export * from './price-list';
export * from './price-list-item/price-list-item';
export * from './stash-tab';

View File

@@ -0,0 +1,37 @@
import { WebviewTag } from 'electron';
import React from 'react';
interface IProps {
onSuccess: () => void;
}
export class LoginWebview extends React.Component<IProps, any> {
private webview: WebviewTag;
constructor(props: IProps) {
super(props);
}
componentDidMount() {
this.webview = this.refs['webview'] as any;
this.webview.addEventListener('did-stop-loading', this.didStopLoading);
}
didStopLoading = (event: any) => {
if ((event.target.src as string).includes('my-account')) {
this.props.onSuccess();
}
};
render() {
return (
<webview
ref="webview"
partition="persist:poe"
src="https://www.pathofexile.com/login"
style={{ height: '100%', width: '100%' }}
/>
);
}
}

View File

@@ -0,0 +1,23 @@
@import '~open-color/open-color.scss';
.pli {
padding: 20px;
border-radius: 4px;
background: $oc-gray-3;
border-color: $oc-gray-5;
display: flex;
flex-direction: row;
width: 300px;
word-break: break-word;
& + & {
margin-top: 20px;
}
&__img {
max-width: 100px;
max-height: 50px;
padding-right: 20px;
cursor: pointer;
}
}

View File

@@ -0,0 +1,36 @@
import React from 'react';
import './price-list-item.scss';
interface IProps {
data: any;
}
interface IState {
price?: String;
}
export class PriceListItem extends React.Component<IProps, IState> {
constructor(props: IProps) {
super(props);
this.state = {};
}
componentDidMount() {}
render() {
const { data } = this.props;
return (
<div className="pli">
<div style={{ width: '100px' }}>
<img src={data.icon} className="pli__img" />
</div>
<div style={{ flex: 1 }}>
<div style={{ marginBottom: '10px' }}>
<b>{data.typeLine}</b>
</div>
<div>{data.priceInfo ? `${data.priceInfo.min_price} ${data.priceInfo.currency_rec}` : ''}</div>
</div>
</div>
);
}
}

View File

@@ -0,0 +1,25 @@
import React from 'react';
import { PriceListItem } from './price-list-item/price-list-item';
interface IProps {
data: any[];
}
export class PriceList extends React.Component<IProps, any> {
constructor(props: IProps) {
super(props);
}
// componentDidMount() {
// console.log(this.props.data);
// }
// componentWillReceiveProps(nextProps: IProps) {
// if (this.props !== nextProps) {
// // do stuff
// console.log(nextProps);
// }
// }
render = () => this.props.data.map((value, index) => <PriceListItem data={value} key={index} />);
}

View File

@@ -0,0 +1,5 @@
.quad-tab {
background-size: 24px 24px;
background-image: linear-gradient(to right, grey 1px, transparent 1px),
linear-gradient(to bottom, grey 1px, transparent 1px);
}

View File

@@ -0,0 +1,20 @@
import React from 'react';
import { PoeService } from '../services/poe.service';
import './stash-tab.scss';
interface IProps {
data: any;
}
export class StashTab extends React.Component<IProps, any> {
componentDidMount() {
console.log(this.props.data);
PoeService.priceCheck(`Superior Laboratory Map`).then(res => {
console.log(res);
});
}
render() {
return <div style={{ height: '577px', width: '577px' }} className="quad-tab" />;
}
}

3
app/http/http.ts Normal file
View File

@@ -0,0 +1,3 @@
import axios from 'axios';
export const http = axios.create();

1
app/http/index.ts Normal file
View File

@@ -0,0 +1 @@
export * from './http';

4
app/scss/index.scss Normal file
View File

@@ -0,0 +1,4 @@
@import '~font-awesome/css/font-awesome.css';
@import '~normalize.css/normalize.css';
@import '~open-color/open-color.scss';
@import './style.scss';

3
app/scss/style.scss Normal file
View File

@@ -0,0 +1,3 @@
html {
font-family: 'Roboto Condensed', sans-serif;
}

View File

@@ -0,0 +1,23 @@
import { http } from '../http';
export class PoeService {
public static async getStash(): Promise<any> {
const res = await http.get(
'https://pathofexile.com/character-window/get-stash-items?league=Incursion&tabs=1&tabIndex=6&accountName=DoctorCoctor',
);
return res.data;
}
public static async priceCheck(item: any) {
const res = await http.get(`https://poeprices.info/api?l=Incursion&i=${encodeURI(btoa(item))}`, {
headers: {
// Host: 'poeprices.info',
// Connection: 'keep-alive',
'Cache-Control': 'max-age=600',
// Origin: 'https://poeprices.info',
// Accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
},
});
return res.data;
}
}

13
index.html Normal file
View File

@@ -0,0 +1,13 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<div id="app"></div>
</body>
</html>

58
index.js Normal file
View File

@@ -0,0 +1,58 @@
import { app, BrowserWindow } from 'electron';
// Handle creating/removing shortcuts on Windows when installing/uninstalling.
if (require('electron-squirrel-startup')) {
// eslint-disable-line global-require
app.quit();
}
// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow;
const createWindow = () => {
// Create the browser window.
mainWindow = new BrowserWindow({
width: 800,
height: 600,
});
// and load the index.html of the app.
mainWindow.loadURL(`file://${__dirname}/build/index.html`);
// Open the DevTools.
mainWindow.webContents.openDevTools();
// Emitted when the window is closed.
mainWindow.on('closed', () => {
// Dereference the window object, usually you would store windows
// in an array if your app supports multi windows, this is the time
// when you should delete the corresponding element.
mainWindow = null;
});
};
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on('ready', createWindow);
// Quit when all windows are closed.
app.on('window-all-closed', () => {
// On OS X it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
if (process.platform !== 'darwin') {
app.quit();
}
});
app.on('activate', () => {
// On OS X it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (mainWindow === null) {
createWindow();
}
});
// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and import them here.

5
ipc-renderer.js Normal file
View File

@@ -0,0 +1,5 @@
// this is used to communicate from inside the webview
var ipcRenderer = require('electron').ipcRenderer;
document.addEventListener('DOMContentLoaded', function() {
ipcRenderer.sendToHost('html-content', document.querySelector('pre').innerHTML);
});

13645
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

88
package.json Normal file
View File

@@ -0,0 +1,88 @@
{
"name": "poe-auto-pricer",
"productName": "poe-auto-pricer",
"version": "1.0.0",
"description": "My Electron application description",
"main": "index.js",
"scripts": {
"start": "electron-forge start",
"package": "electron-forge package",
"make": "electron-forge make",
"publish": "electron-forge publish",
"watch": "webpack --progress --colors --watch --mode development"
},
"keywords": [],
"author": "Mitchell",
"license": "MIT",
"config": {
"forge": {
"make_targets": {
"win32": [
"squirrel"
],
"darwin": [
"zip"
],
"linux": [
"deb",
"rpm"
]
},
"electronPackagerConfig": {
"packageManager": "npm"
},
"electronWinstallerConfig": {
"name": "poe_auto_pricer"
},
"electronInstallerDebian": {},
"electronInstallerRedhat": {},
"github_repository": {
"owner": "",
"name": ""
},
"windowsStoreConfig": {
"packageName": "",
"name": "poeautopricer"
}
}
},
"dependencies": {
"@types/react": "^16.4.9",
"@types/react-dom": "^16.0.7",
"autoprefixer": "^9.1.1",
"axios": "^0.18.0",
"babel-core": "^6.26.3",
"babel-loader": "^7.1.5",
"babel-polyfill": "^6.26.0",
"clean-webpack-plugin": "^0.1.19",
"copy-webpack-plugin": "^4.5.2",
"css-loader": "^1.0.0",
"electron": "^2.0.7",
"electron-compile": "^6.4.3",
"electron-squirrel-startup": "^1.0.0",
"file-loader": "^1.1.11",
"font-awesome": "^4.7.0",
"html-webpack-plugin": "^3.2.0",
"node-sass": "^4.9.3",
"normalize.css": "^8.0.0",
"open-color": "^1.6.3",
"postcss-loader": "^3.0.0",
"react": "^16.4.2",
"react-dom": "^16.4.2",
"sass-loader": "^7.1.0",
"style-loader": "^0.22.1",
"ts-loader": "^4.4.2",
"tslint": "^5.11.0",
"tslint-config-airbnb": "^5.9.2",
"typescript": "^3.0.1",
"webpack": "^4.16.5",
"webpack-cli": "^3.1.0"
},
"devDependencies": {
"babel-plugin-transform-async-to-generator": "^6.24.1",
"babel-preset-env": "^1.7.0",
"babel-preset-react": "^6.24.1",
"electron-forge": "^5.2.2",
"electron-prebuilt-compile": "2.0.7"
}
}

10
postcss.config.js Normal file
View File

@@ -0,0 +1,10 @@
const browserList = [
'last 3 versions',
'> 1%'
];
module.exports = {
plugins: [
require('autoprefixer')(browserList)
]
};

25
tsconfig.json Normal file
View File

@@ -0,0 +1,25 @@
{
"compilerOptions": {
"experimentalDecorators": true,
"target": "es2015",
"module": "es2015",
"moduleResolution": "node",
"jsx": "react",
"allowSyntheticDefaultImports": true,
"noImplicitAny": true,
"noImplicitThis": true,
"strictNullChecks": true,
"preserveConstEnums": true,
"allowJs": false,
"sourceMap": true,
"noImplicitReturns": true,
"noUnusedParameters": true,
"noUnusedLocals": true,
"alwaysStrict": true,
"typeRoots": ["./node_modules/@types", "./@types"]
},
"filesGlob": ["typings/index.d.ts", "src/**/*.ts", "src/**/*.tsx"],
"include": ["app"],
"exclude": ["android", "ios", "build", "node_modules"],
"compileOnSave": false
}

11
tslint.json Normal file
View File

@@ -0,0 +1,11 @@
{
"extends": "tslint-config-airbnb",
"rules": {
"semicolon": [true, "always", "ignore-bound-class-methods"],
"max-line-length": [true, 120],
"variable-name": [true, "ban-keywords", "check-format", "allow-pascal-case"],
"import-name": false,
"ter-arrow-parens": [true, "as-needed"],
"align": [true, "parameters", "statements"]
}
}

68
webpack.config.js Normal file
View File

@@ -0,0 +1,68 @@
const CleanWebpackPlugin = require('clean-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');
const webpack = require('webpack');
const CopyWebpackPlugin = require('copy-webpack-plugin');
module.exports = {
entry: {
app: ['babel-polyfill', './app/app.tsx'],
},
target: 'electron-renderer',
output: {
path: path.resolve(__dirname, './build'),
filename: '[name].[hash].js',
},
resolve: {
extensions: ['.ts', '.tsx', '.js'],
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
use: ['babel-loader'],
},
{
test: /\.ts(x)?$/,
use: ['babel-loader', 'ts-loader'],
},
{
test: /\.scss$/,
use: ['style-loader', 'css-loader', 'postcss-loader', 'sass-loader'],
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
},
{
test: /\.woff2?$|\.ttf$|\.eot$|\.svg$/,
use: [
{
loader: 'file-loader',
options: {
name: 'static/[name].[hash].[ext]',
publicPath: './.',
},
},
],
},
],
},
optimization: {
occurrenceOrder: true,
splitChunks: {
chunks: 'all',
},
},
plugins: [
new CleanWebpackPlugin(['./build'], {
verbose: true,
}),
new HtmlWebpackPlugin({
filename: 'index.html',
template: './index.html',
}),
new webpack.HotModuleReplacementPlugin(),
new CopyWebpackPlugin(['./ipc-renderer.js']),
],
};