less hacking way of pulling poe data
This commit is contained in:
14
app/app.tsx
14
app/app.tsx
@@ -1,6 +1,16 @@
|
||||
import { Provider } from 'mobx-react';
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { Home } from './components';
|
||||
import './scss/index.scss';
|
||||
import { RootStore } from './stores/root.store';
|
||||
import { Wrapper } from './wrapper';
|
||||
|
||||
ReactDOM.render(<Home />, document.getElementById('app'));
|
||||
const rootStore = new RootStore();
|
||||
|
||||
const app = (
|
||||
<Provider {...rootStore}>
|
||||
<Wrapper />
|
||||
</Provider>
|
||||
);
|
||||
|
||||
ReactDOM.render(app, document.getElementById('app'));
|
||||
|
||||
@@ -1,109 +0,0 @@
|
||||
import { WebviewTag } from 'electron';
|
||||
import * as _ from 'lodash';
|
||||
import React from 'react';
|
||||
import { ItemTextService } from '../services';
|
||||
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) {
|
||||
const items = _.map(json.items, item => {
|
||||
item.fullText = ItemTextService.parseItem(item);
|
||||
return item;
|
||||
});
|
||||
|
||||
this.setState({ showLogin: false, data: items });
|
||||
this.getItemPrice(items, 0);
|
||||
}
|
||||
}
|
||||
|
||||
onLogin = () => {
|
||||
this.setState({ showLogin: false });
|
||||
this.webview.reload();
|
||||
};
|
||||
|
||||
async getItemPrice(data: any[], index: number) {
|
||||
if (!data[index] || data !== this.state.data) {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(data[index]);
|
||||
console.log(data[index].fullText + '\n\n\n');
|
||||
const res = await PoeService.priceCheck(data[index].fullText);
|
||||
if ((res.min && res.currency) || (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;
|
||||
|
||||
const url =
|
||||
'https://www.pathofexile.com/character-window/get-stash-items' +
|
||||
'?league=Incursion&tabs=1&tabIndex=0&accountName=DoctorCoctor';
|
||||
|
||||
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={url}
|
||||
style={{ opacity: 0, width: '0', height: '0' }}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
0
app/components/home/home.scss
Normal file
0
app/components/home/home.scss
Normal file
34
app/components/home/home.tsx
Normal file
34
app/components/home/home.tsx
Normal file
@@ -0,0 +1,34 @@
|
||||
import { inject, observer } from 'mobx-react';
|
||||
import React from 'react';
|
||||
import { AppStore } from '../../stores/app.store';
|
||||
import { Navbar } from '../navbar/navbar';
|
||||
import { PriceListItem } from '../price-list-item/price-list-item';
|
||||
import './home.scss';
|
||||
|
||||
interface IProps {
|
||||
appStore?: AppStore;
|
||||
}
|
||||
|
||||
interface IState {}
|
||||
|
||||
@inject('appStore')
|
||||
@observer
|
||||
export class Home extends React.Component<IProps, IState> {
|
||||
constructor(props: IProps) {
|
||||
super(props);
|
||||
this.state = {};
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<Navbar />
|
||||
<div style={{ padding: '10px' }}>
|
||||
{this.props.appStore!.stashItems.map((v, k) => {
|
||||
return <PriceListItem key={k} data={v} />;
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
export * from './home';
|
||||
export * from './login-webview';
|
||||
export * from './price-list';
|
||||
export * from './home/home';
|
||||
export * from './login-webview/login-webview';
|
||||
export * from './navbar/navbar';
|
||||
export * from './price-list-item/price-list-item';
|
||||
export * from './stash-tab';
|
||||
export * from './price-list/price-list';
|
||||
export * from './stash-tab/stash-tab';
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
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: '500px', width: '100%' }}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
53
app/components/login-webview/login-webview.tsx
Normal file
53
app/components/login-webview/login-webview.tsx
Normal file
@@ -0,0 +1,53 @@
|
||||
import { WebviewTag } from 'electron';
|
||||
import * as _ from 'lodash';
|
||||
import { inject, observer } from 'mobx-react';
|
||||
import React from 'react';
|
||||
import { POE_HOME } from '../../constants';
|
||||
import { AppStore } from '../../stores/app.store';
|
||||
|
||||
interface IProps {
|
||||
appStore?: AppStore;
|
||||
}
|
||||
|
||||
@inject('appStore')
|
||||
@observer
|
||||
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);
|
||||
}
|
||||
|
||||
// if webview redirect to my-account - means user logged in
|
||||
didStopLoading = (event: any) => {
|
||||
if ((event.target.src as string).includes('my-account')) {
|
||||
this.getCookies();
|
||||
}
|
||||
};
|
||||
|
||||
// get cookies from login and store username/sessionID
|
||||
getCookies() {
|
||||
const session = this.webview.getWebContents().session;
|
||||
session.cookies.get({ url: POE_HOME }, async (error, cookies) => {
|
||||
if (error) {
|
||||
console.error(error);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const cookie: any = _.find(cookies, c => c.name === 'POESESSID');
|
||||
this.props.appStore!.performLogin(cookie.value);
|
||||
} catch (e) {
|
||||
this.props.appStore!.resetState();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
return <webview ref="webview" src={`${POE_HOME}/login`} style={{ height: '100%', width: '100%' }} />;
|
||||
}
|
||||
}
|
||||
10
app/components/navbar/navbar.scss
Normal file
10
app/components/navbar/navbar.scss
Normal file
@@ -0,0 +1,10 @@
|
||||
@import '../../scss/variables.scss';
|
||||
|
||||
.navbar {
|
||||
background: $dark2;
|
||||
border-bottom: 1px solid $dark1;
|
||||
height: 50px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 20px;
|
||||
}
|
||||
68
app/components/navbar/navbar.tsx
Normal file
68
app/components/navbar/navbar.tsx
Normal file
@@ -0,0 +1,68 @@
|
||||
import { inject, observer } from 'mobx-react';
|
||||
import React from 'react';
|
||||
import { AppStore } from '../../stores/app.store';
|
||||
import './navbar.scss';
|
||||
|
||||
interface IProps {
|
||||
appStore?: AppStore;
|
||||
}
|
||||
|
||||
@inject('appStore')
|
||||
@observer
|
||||
export class Navbar extends React.Component<IProps, any> {
|
||||
constructor(props: IProps) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
onLeagueSelect = (event: any) => {
|
||||
this.props.appStore!.setActiveLeague(event.target.value);
|
||||
};
|
||||
|
||||
onStashSelect = (event: any) => {
|
||||
this.props.appStore!.loadItems(event.target.value);
|
||||
};
|
||||
|
||||
renderStashTabSelector() {
|
||||
const { stashTabs } = this.props.appStore!;
|
||||
if (stashTabs.length < 1) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<select defaultValue={stashTabs[0].n} onChange={this.onStashSelect}>
|
||||
{stashTabs.map((v, k) => (
|
||||
<option key={k} value={k}>
|
||||
{v.n}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
);
|
||||
}
|
||||
|
||||
renderLeagueSelector() {
|
||||
const { activeLeague, leagues } = this.props.appStore!;
|
||||
if (!leagues || !activeLeague) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<select onChange={this.onLeagueSelect} defaultValue={activeLeague.id}>
|
||||
{leagues!.map((l, k) => {
|
||||
return (
|
||||
<option key={k} value={l.id}>
|
||||
{l.id}
|
||||
</option>
|
||||
);
|
||||
})}
|
||||
</select>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="navbar">
|
||||
{this.renderLeagueSelector()}
|
||||
{this.renderStashTabSelector()}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,23 +1,22 @@
|
||||
@import '~open-color/open-color.scss';
|
||||
@import '../../scss/variables.scss';
|
||||
|
||||
.pli {
|
||||
padding: 20px;
|
||||
padding: 10px;
|
||||
border-radius: 4px;
|
||||
background: $oc-gray-3;
|
||||
border-color: $oc-gray-5;
|
||||
background: $dark3;
|
||||
border: 1px solid $dark1;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
width: 300px;
|
||||
word-break: break-word;
|
||||
|
||||
& + & {
|
||||
margin-top: 20px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
&__img {
|
||||
max-width: 100px;
|
||||
max-width: 50px;
|
||||
max-height: 50px;
|
||||
padding-right: 20px;
|
||||
cursor: pointer;
|
||||
padding-right: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
import React from 'react';
|
||||
import { FrameType } from '../../model/frame-type';
|
||||
import { IItem } from '../../model/item';
|
||||
import { RarityColor } from '../../model/rarity-color';
|
||||
import { ItemTextService } from '../../services';
|
||||
import './price-list-item.scss';
|
||||
|
||||
interface IProps {
|
||||
data: any;
|
||||
data: IItem;
|
||||
}
|
||||
|
||||
interface IState {
|
||||
@@ -18,16 +22,23 @@ export class PriceListItem extends React.Component<IProps, IState> {
|
||||
componentDidMount() {}
|
||||
|
||||
render() {
|
||||
const { fullText, icon, priceInfo, typeLine } = this.props.data;
|
||||
const { icon, priceInfo, stackSize, typeLine, frameType } = this.props.data;
|
||||
const name = ItemTextService.filterName(typeLine);
|
||||
const fullText = ItemTextService.parseItem(this.props.data);
|
||||
|
||||
const rarityColor = RarityColor[(FrameType[frameType] || '').toLowerCase()];
|
||||
|
||||
return (
|
||||
<div className="pli" title={fullText}>
|
||||
<div style={{ width: '100px' }}>
|
||||
<img src={icon} className="pli__img" />
|
||||
<div className="pli" onClick={() => console.log(this.props.data)}>
|
||||
<div style={{ width: '60px' }}>
|
||||
<img title={fullText} src={icon} className="pli__img" />
|
||||
</div>
|
||||
<div style={{ flex: 1 }}>
|
||||
<div style={{ flex: 1 }} className="ellipsis">
|
||||
<div style={{ marginBottom: '10px' }}>
|
||||
<b>{typeLine}</b>
|
||||
<div className="ellipsis" title={name} style={{ color: rarityColor }}>
|
||||
{name}
|
||||
</div>
|
||||
<div className="text-secondary">{stackSize && <small>Stack Size: {stackSize}</small>}</div>
|
||||
</div>
|
||||
<div>
|
||||
{priceInfo ? `${priceInfo.min || priceInfo.min_price} ${priceInfo.currency || priceInfo.currency_rec}` : ''}
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
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} />);
|
||||
}
|
||||
14
app/components/price-list/price-list.tsx
Normal file
14
app/components/price-list/price-list.tsx
Normal file
@@ -0,0 +1,14 @@
|
||||
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);
|
||||
}
|
||||
|
||||
render = () => this.props.data.map((value, index) => <PriceListItem data={value} key={index} />);
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
import React from 'react';
|
||||
import { PoeService } from '../services/poe.service';
|
||||
import './stash-tab.scss';
|
||||
|
||||
interface IProps {
|
||||
@@ -7,13 +6,6 @@ interface IProps {
|
||||
}
|
||||
|
||||
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" />;
|
||||
}
|
||||
7
app/constants.ts
Normal file
7
app/constants.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
export const POE_HOME = 'https://www.pathofexile.com';
|
||||
export const POE_LOGIN_URL = `${POE_HOME}/login`;
|
||||
export const POE_LOGIN_STEAM_URL = `${POE_LOGIN_URL}/steam`;
|
||||
export const POE_MY_ACCOUNT_URL = `${POE_HOME}/my-account`;
|
||||
export const POE_GET_CHARACTERS_URL = `${POE_HOME}/character-window/get-characters`;
|
||||
export const POE_STASH_ITEMS_URL = `${POE_HOME}/character-window/get-stash-items`;
|
||||
export const POE_LEAGUE_LIST_URL = 'http://api.pathofexile.com/leagues?type=main&compact=1';
|
||||
@@ -1,3 +1,7 @@
|
||||
import axios from 'axios';
|
||||
|
||||
export const http = axios.create();
|
||||
|
||||
export const setHeader = (header: string, value: string) => {
|
||||
http.defaults.headers[header] = value;
|
||||
};
|
||||
|
||||
1
app/model/index.ts
Normal file
1
app/model/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from './league';
|
||||
21
app/model/item.ts
Normal file
21
app/model/item.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
export interface IItem {
|
||||
category: any[];
|
||||
descrText: string;
|
||||
explicitMods: string[];
|
||||
frameType: number;
|
||||
h: number;
|
||||
icon: string;
|
||||
id: string;
|
||||
identified: boolean;
|
||||
ilvl: number;
|
||||
inventoryId: string;
|
||||
league: string;
|
||||
name: string;
|
||||
properties: any[];
|
||||
stackSize?: number;
|
||||
typeLine: string;
|
||||
verified: boolean;
|
||||
w: number;
|
||||
x: number;
|
||||
y: number;
|
||||
}
|
||||
6
app/model/league.ts
Normal file
6
app/model/league.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
export interface ILeague {
|
||||
endAt?: string;
|
||||
id: string;
|
||||
startAt: string;
|
||||
url: string;
|
||||
}
|
||||
6
app/model/rarity-color.ts
Normal file
6
app/model/rarity-color.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
export const RarityColor: any = {
|
||||
unique: '#af6025',
|
||||
rare: '#a3a314',
|
||||
magic: 'rgb(117, 117, 255)',
|
||||
normal: '#eee',
|
||||
};
|
||||
18
app/model/stash-tab.ts
Normal file
18
app/model/stash-tab.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
interface IStashTabColor {
|
||||
r: number;
|
||||
g: number;
|
||||
b: number;
|
||||
}
|
||||
|
||||
export interface IStashTab {
|
||||
colour: IStashTabColor;
|
||||
hidden: boolean;
|
||||
i: number;
|
||||
id: string;
|
||||
n: string;
|
||||
selected: boolean;
|
||||
srcC: string;
|
||||
srcL: string;
|
||||
srcR: string;
|
||||
type: string;
|
||||
}
|
||||
@@ -1,3 +1,27 @@
|
||||
@import './variables.scss';
|
||||
|
||||
html {
|
||||
font-family: 'Roboto Condensed', sans-serif;
|
||||
}
|
||||
|
||||
html,
|
||||
body,
|
||||
#app {
|
||||
height: 100%;
|
||||
background: $dark4;
|
||||
color: $textPrimary;
|
||||
}
|
||||
|
||||
.text-secondary {
|
||||
color: $textSecondary;
|
||||
}
|
||||
|
||||
small {
|
||||
font-size: 75%;
|
||||
}
|
||||
|
||||
.ellipsis {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
10
app/scss/variables.scss
Normal file
10
app/scss/variables.scss
Normal file
@@ -0,0 +1,10 @@
|
||||
@import '~open-color/open-color.scss';
|
||||
|
||||
$dark1: lighten(#0e0e0e, 20%);
|
||||
$dark2: lighten(#0e0e0e, 15%);
|
||||
$dark3: lighten(#0e0e0e, 10%);
|
||||
$dark4: lighten(#0e0e0e, 5%);
|
||||
$dark5: #0e0e0e;
|
||||
|
||||
$textPrimary: $oc-gray-3;
|
||||
$textSecondary: $oc-gray-5;
|
||||
@@ -63,14 +63,16 @@ const getSockets = (sockets: any[]): string => {
|
||||
return content.trim() + '\n';
|
||||
};
|
||||
|
||||
/** filter unwanted characters from item name */
|
||||
const filterName = (name: string): string => {
|
||||
const index = name.lastIndexOf('>');
|
||||
const newString = name.replace(/>/g, '>');
|
||||
const index = newString.lastIndexOf('>');
|
||||
if (index < 0) {
|
||||
return name;
|
||||
}
|
||||
|
||||
return name
|
||||
.slice(index + 4, name.length)
|
||||
.slice(index + 1, name.length)
|
||||
.replace('{', '')
|
||||
.replace('}', '');
|
||||
};
|
||||
@@ -103,5 +105,6 @@ const getProperties = (p?: any[], precedingText?: string): string => {
|
||||
};
|
||||
|
||||
export const ItemTextService = {
|
||||
filterName,
|
||||
parseItem,
|
||||
};
|
||||
|
||||
@@ -1,20 +1,44 @@
|
||||
import PQueue from 'p-queue';
|
||||
import { POE_HOME, POE_LEAGUE_LIST_URL, POE_STASH_ITEMS_URL } from '../constants';
|
||||
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;
|
||||
}
|
||||
const queue = new PQueue({ concurrency: 1 });
|
||||
|
||||
public static async priceCheck(item: any) {
|
||||
const res = await http.get(`https://poeprices.info/api?l=Incursion&i=${encodeURI(btoa(item))}`, {
|
||||
headers: {
|
||||
'Cache-Control': 'max-age=600',
|
||||
},
|
||||
const getStash = async (username: string, league: string, tabIndex: number | string): Promise<any> => {
|
||||
const res = await http.get(
|
||||
`${POE_STASH_ITEMS_URL}?league=${league}&tabs=1&tabIndex=${tabIndex}&accountName=${username}`,
|
||||
);
|
||||
return res.data;
|
||||
};
|
||||
|
||||
const priceCheck = async (item: any): Promise<any> => {
|
||||
return new Promise(resolve => {
|
||||
queue.add(() => {
|
||||
return http
|
||||
.get(`https://poeprices.info/api?l=Incursion&i=${encodeURI(btoa(item))}`, {
|
||||
headers: {
|
||||
'Cache-Control': 'max-age=600',
|
||||
},
|
||||
})
|
||||
.then(resolve);
|
||||
});
|
||||
return res.data;
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const getUsername = async (): Promise<any> => {
|
||||
const res = await http.get(POE_HOME);
|
||||
const username = res.data.match(/\/account\/view-profile\/(.*?)\"/);
|
||||
return username[1];
|
||||
};
|
||||
|
||||
const getLeagues = async (): Promise<any> => {
|
||||
const res = await http.get(POE_LEAGUE_LIST_URL);
|
||||
return res.data;
|
||||
};
|
||||
|
||||
export const PoeService = {
|
||||
getLeagues,
|
||||
getStash,
|
||||
getUsername,
|
||||
priceCheck,
|
||||
};
|
||||
|
||||
25
app/services/storage.service.ts
Normal file
25
app/services/storage.service.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import Store from 'electron-store';
|
||||
const store = new Store();
|
||||
|
||||
const storeUsername = (username: string) => {
|
||||
store.set('user', username);
|
||||
};
|
||||
|
||||
const storeSessionID = (sessionID: string) => {
|
||||
store.set('sessionID', sessionID);
|
||||
};
|
||||
|
||||
const getSessionID = (): string | undefined => {
|
||||
return store.get('sessionID') || undefined;
|
||||
};
|
||||
|
||||
const getUsername = (): string | undefined => {
|
||||
return store.get('user') || undefined;
|
||||
};
|
||||
|
||||
export const StorageService = {
|
||||
getUsername,
|
||||
getSessionID,
|
||||
storeUsername,
|
||||
storeSessionID,
|
||||
};
|
||||
114
app/stores/app.store.ts
Normal file
114
app/stores/app.store.ts
Normal file
@@ -0,0 +1,114 @@
|
||||
import Store from 'electron-store';
|
||||
import { action, computed, observable } from 'mobx';
|
||||
import { setHeader } from '../http';
|
||||
import { ILeague } from '../model';
|
||||
import { IItem } from '../model/item';
|
||||
import { IStashTab } from '../model/stash-tab';
|
||||
import { PoeService } from '../services';
|
||||
import { StorageService } from '../services/storage.service';
|
||||
const store = new Store();
|
||||
|
||||
export class AppStore {
|
||||
@observable
|
||||
public username?: string;
|
||||
@observable
|
||||
public sessionID?: string;
|
||||
@observable
|
||||
public activeLeague: ILeague;
|
||||
@observable
|
||||
public selectedTabIndex: number = 0;
|
||||
@observable
|
||||
public stashTabs: IStashTab[] = [];
|
||||
@observable
|
||||
public stashItems: IItem[] = [];
|
||||
@observable
|
||||
public leagues: ILeague[] = [];
|
||||
@observable
|
||||
public appReady: boolean;
|
||||
|
||||
constructor() {
|
||||
this.bootstrap();
|
||||
}
|
||||
|
||||
private async bootstrap() {
|
||||
try {
|
||||
this.username = StorageService.getUsername();
|
||||
this.sessionID = StorageService.getSessionID();
|
||||
if (this.sessionID) {
|
||||
await this.loadLeagues();
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
this.appReady = true;
|
||||
}
|
||||
|
||||
@action
|
||||
private async loadLeagues() {
|
||||
try {
|
||||
const leagues = await PoeService.getLeagues();
|
||||
if (!leagues) {
|
||||
return;
|
||||
}
|
||||
this.leagues = leagues;
|
||||
// set active league if not set
|
||||
if (!this.activeLeague && this.leagues!.length > 0) {
|
||||
this.setActiveLeague(this.leagues[0].id);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
@computed
|
||||
public get isLoggedIn() {
|
||||
return this.username && this.sessionID;
|
||||
}
|
||||
|
||||
@action
|
||||
public resetState() {
|
||||
delete this.username;
|
||||
delete this.sessionID;
|
||||
setHeader('Cookie', '');
|
||||
store.clear();
|
||||
}
|
||||
|
||||
@action
|
||||
public setSessionID(sessionID: string) {
|
||||
setHeader('Cookie', `POESESSID=${sessionID}`);
|
||||
this.sessionID = sessionID;
|
||||
StorageService.storeSessionID(sessionID);
|
||||
}
|
||||
|
||||
@action
|
||||
public setUsername(username: string) {
|
||||
this.username = username;
|
||||
StorageService.storeUsername(username);
|
||||
}
|
||||
|
||||
@action
|
||||
public setActiveLeague(id: string) {
|
||||
const league = this.leagues.find(l => l.id === id);
|
||||
if (league) {
|
||||
this.activeLeague = league;
|
||||
this.stashTabs = [];
|
||||
this.selectedTabIndex = 0;
|
||||
this.stashItems = [];
|
||||
this.loadItems(this.selectedTabIndex);
|
||||
}
|
||||
}
|
||||
|
||||
@action
|
||||
public async performLogin(sessionID: string) {
|
||||
this.setSessionID(sessionID);
|
||||
const username = await PoeService.getUsername();
|
||||
this.setUsername(username);
|
||||
}
|
||||
|
||||
@action
|
||||
public async loadItems(tabIndex: number | string) {
|
||||
const data = await PoeService.getStash(this.username!, this.activeLeague.id, tabIndex);
|
||||
this.stashTabs = data.tabs;
|
||||
this.stashItems = data.items;
|
||||
}
|
||||
}
|
||||
5
app/stores/root.store.ts
Normal file
5
app/stores/root.store.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import { AppStore } from './app.store';
|
||||
|
||||
export class RootStore {
|
||||
public appStore = new AppStore();
|
||||
}
|
||||
32
app/wrapper.tsx
Normal file
32
app/wrapper.tsx
Normal file
@@ -0,0 +1,32 @@
|
||||
import { inject, observer } from 'mobx-react';
|
||||
import React from 'react';
|
||||
import { Home, LoginWebview } from './components';
|
||||
import { AppStore } from './stores/app.store';
|
||||
|
||||
interface IProps {
|
||||
appStore?: AppStore;
|
||||
}
|
||||
|
||||
interface IState {}
|
||||
|
||||
@inject('appStore')
|
||||
@observer
|
||||
export class Wrapper extends React.Component<IProps, IState> {
|
||||
constructor(props: any) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
public render() {
|
||||
const { appStore } = this.props;
|
||||
|
||||
if (!appStore!.appReady) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!appStore!.isLoggedIn) {
|
||||
return <LoginWebview />;
|
||||
}
|
||||
|
||||
return <Home />;
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0" />
|
||||
<title></title>
|
||||
</head>
|
||||
|
||||
|
||||
106
package-lock.json
generated
106
package-lock.json
generated
@@ -84,6 +84,14 @@
|
||||
"vue-template-es2015-compiler": "1.6.0"
|
||||
}
|
||||
},
|
||||
"@types/electron-store": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/electron-store/-/electron-store-1.3.0.tgz",
|
||||
"integrity": "sha512-PplQbntPl3xNcckjizjoQShPwLot72jFiaI67CZ0JOr+AuGwqXdL73sU3vfuuP+RZecOh8vX1G7yWjmxs4lvBQ==",
|
||||
"requires": {
|
||||
"@types/node": "7.0.69"
|
||||
}
|
||||
},
|
||||
"@types/lodash": {
|
||||
"version": "4.14.116",
|
||||
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.116.tgz",
|
||||
@@ -94,6 +102,11 @@
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-7.0.69.tgz",
|
||||
"integrity": "sha512-S5NC8HV6HnRipg8nC0j30TPl7ktXjRTKqgyINLNe8K/64UJUI8Lq0sRopXC0hProsV2F5ibj8IqPkl1xpGggrw=="
|
||||
},
|
||||
"@types/p-queue": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/p-queue/-/p-queue-2.3.1.tgz",
|
||||
"integrity": "sha512-JyO7uMAtkcMMULmsTQ4t/lCC8nxirTtweGG1xAFNNIAoC1RemmeIxq8PiKghuEy99XdbS6Lwx4zpbXUjfeSSAA=="
|
||||
},
|
||||
"@types/prop-types": {
|
||||
"version": "15.5.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.5.5.tgz",
|
||||
@@ -2621,6 +2634,18 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"conf": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/conf/-/conf-2.0.0.tgz",
|
||||
"integrity": "sha512-iCLzBsGFi8S73EANsEJZz0JnJ/e5VZef/kSaxydYZLAvw0rFNAUx5R7K5leC/CXXR2mZfXWhUvcZOO/dM2D5xg==",
|
||||
"requires": {
|
||||
"dot-prop": "4.2.0",
|
||||
"env-paths": "1.0.0",
|
||||
"make-dir": "1.3.0",
|
||||
"pkg-up": "2.0.0",
|
||||
"write-file-atomic": "2.3.0"
|
||||
}
|
||||
},
|
||||
"console-browserify": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz",
|
||||
@@ -3523,6 +3548,14 @@
|
||||
"domelementtype": "1.3.0"
|
||||
}
|
||||
},
|
||||
"dot-prop": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz",
|
||||
"integrity": "sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ==",
|
||||
"requires": {
|
||||
"is-obj": "1.0.1"
|
||||
}
|
||||
},
|
||||
"ds-store": {
|
||||
"version": "0.1.6",
|
||||
"resolved": "https://registry.npmjs.org/ds-store/-/ds-store-0.1.6.tgz",
|
||||
@@ -4727,6 +4760,14 @@
|
||||
"debug": "2.6.9"
|
||||
}
|
||||
},
|
||||
"electron-store": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/electron-store/-/electron-store-2.0.0.tgz",
|
||||
"integrity": "sha512-1WCFYHsYvZBqDsoaS0Relnz0rd81ZkBAI0Fgx7Nq2UWU77rSNs1qxm4S6uH7TCZ0bV3LQpJFk7id/is/ZgoOPA==",
|
||||
"requires": {
|
||||
"conf": "2.0.0"
|
||||
}
|
||||
},
|
||||
"electron-to-chromium": {
|
||||
"version": "1.3.58",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.58.tgz",
|
||||
@@ -5055,8 +5096,7 @@
|
||||
"env-paths": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/env-paths/-/env-paths-1.0.0.tgz",
|
||||
"integrity": "sha1-QWgTO0K7BcOKNbGuQ5fIKYqzaeA=",
|
||||
"dev": true
|
||||
"integrity": "sha1-QWgTO0K7BcOKNbGuQ5fIKYqzaeA="
|
||||
},
|
||||
"errno": {
|
||||
"version": "0.1.7",
|
||||
@@ -6735,6 +6775,11 @@
|
||||
"integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=",
|
||||
"dev": true
|
||||
},
|
||||
"hoist-non-react-statics": {
|
||||
"version": "2.5.5",
|
||||
"resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-2.5.5.tgz",
|
||||
"integrity": "sha512-rqcy4pJo55FTTLWt+bU8ukscqHeE/e9KWvsOW2b/a3afxQZhwkQdT1rPPCJ0rYXdj4vNcasY8zHTH+jF/qStxw=="
|
||||
},
|
||||
"home-or-tmp": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz",
|
||||
@@ -7350,6 +7395,11 @@
|
||||
"kind-of": "3.2.2"
|
||||
}
|
||||
},
|
||||
"is-obj": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz",
|
||||
"integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8="
|
||||
},
|
||||
"is-plain-obj": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz",
|
||||
@@ -8611,6 +8661,20 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"mobx": {
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/mobx/-/mobx-5.1.0.tgz",
|
||||
"integrity": "sha512-cQzBmF2gbpcBR2xKwt5jZx0ncDMC9Hg5nYrp3Krv0qHH4GFqWZyR+ZLkRJRcvVF4rqxpy2G96Qbk5YzyQ8tdXw=="
|
||||
},
|
||||
"mobx-react": {
|
||||
"version": "5.2.5",
|
||||
"resolved": "https://registry.npmjs.org/mobx-react/-/mobx-react-5.2.5.tgz",
|
||||
"integrity": "sha512-vSwsjGwmaqTmaEsPWET/APccjirTiIIchQA3YVasKzaxIGv62BNJUHFjrkIAbGBLeqJma+ZgSu158OqQLK0vaQ==",
|
||||
"requires": {
|
||||
"hoist-non-react-statics": "2.5.5",
|
||||
"react-lifecycles-compat": "3.0.4"
|
||||
}
|
||||
},
|
||||
"move-concurrently": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz",
|
||||
@@ -9326,6 +9390,11 @@
|
||||
"p-limit": "1.3.0"
|
||||
}
|
||||
},
|
||||
"p-queue": {
|
||||
"version": "2.4.2",
|
||||
"resolved": "https://registry.npmjs.org/p-queue/-/p-queue-2.4.2.tgz",
|
||||
"integrity": "sha512-n8/y+yDJwBjoLQe1GSJbbaYQLTI7QHNZI2+rpmCDbe++WLf9HC3gf6iqj5yfPAV71W4UF3ql5W1+UBPXoXTxng=="
|
||||
},
|
||||
"p-try": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz",
|
||||
@@ -9536,6 +9605,24 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"pkg-up": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-2.0.0.tgz",
|
||||
"integrity": "sha1-yBmscoBZpGHKscOImivjxJoATX8=",
|
||||
"requires": {
|
||||
"find-up": "2.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"find-up": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz",
|
||||
"integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=",
|
||||
"requires": {
|
||||
"locate-path": "2.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"plist": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/plist/-/plist-2.1.0.tgz",
|
||||
@@ -10494,6 +10581,11 @@
|
||||
"prop-types": "15.6.2"
|
||||
}
|
||||
},
|
||||
"react-lifecycles-compat": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz",
|
||||
"integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA=="
|
||||
},
|
||||
"read-pkg": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz",
|
||||
@@ -13504,6 +13596,16 @@
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"write-file-atomic": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.3.0.tgz",
|
||||
"integrity": "sha512-xuPeK4OdjWqtfi59ylvVL0Yn35SF3zgcAcv7rBPFHVaEapaDr4GdGgm3j7ckTwH9wHL7fGmgfAnb0+THrHb8tA==",
|
||||
"requires": {
|
||||
"graceful-fs": "4.1.11",
|
||||
"imurmurhash": "0.1.4",
|
||||
"signal-exit": "3.0.2"
|
||||
}
|
||||
},
|
||||
"xml-name-validator": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-2.0.1.tgz",
|
||||
|
||||
@@ -47,7 +47,9 @@
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/electron-store": "^1.3.0",
|
||||
"@types/lodash": "^4.14.116",
|
||||
"@types/p-queue": "^2.3.1",
|
||||
"@types/react": "^16.4.9",
|
||||
"@types/react-dom": "^16.0.7",
|
||||
"autoprefixer": "^9.1.1",
|
||||
@@ -61,13 +63,17 @@
|
||||
"electron": "^2.0.7",
|
||||
"electron-compile": "^6.4.3",
|
||||
"electron-squirrel-startup": "^1.0.0",
|
||||
"electron-store": "^2.0.0",
|
||||
"file-loader": "^1.1.11",
|
||||
"font-awesome": "^4.7.0",
|
||||
"html-webpack-plugin": "^3.2.0",
|
||||
"lodash": "^4.17.10",
|
||||
"mobx": "^5.1.0",
|
||||
"mobx-react": "^5.2.5",
|
||||
"node-sass": "^4.9.3",
|
||||
"normalize.css": "^8.0.0",
|
||||
"open-color": "^1.6.3",
|
||||
"p-queue": "^2.4.2",
|
||||
"postcss-loader": "^3.0.0",
|
||||
"react": "^16.4.2",
|
||||
"react-dom": "^16.4.2",
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"rules": {
|
||||
"semicolon": [true, "always", "ignore-bound-class-methods"],
|
||||
"max-line-length": [true, 120],
|
||||
"variable-name": [true, "ban-keywords", "check-format", "allow-pascal-case"],
|
||||
"variable-name": [false, "ban-keywords", "check-format", "allow-pascal-case"],
|
||||
"import-name": false,
|
||||
"ter-arrow-parens": [true, "as-needed"],
|
||||
"align": [true, "parameters", "statements"]
|
||||
|
||||
Reference in New Issue
Block a user