Alex Mikhalev
7 years ago
19 changed files with 262 additions and 130 deletions
@ -0,0 +1,75 @@ |
|||||||
|
import { AppState, injectState } from "@app/state"; |
||||||
|
import log from "@common/logger"; |
||||||
|
import { computed, observable } from "mobx"; |
||||||
|
import { observer } from "mobx-react"; |
||||||
|
import * as React from "react"; |
||||||
|
import { Container, Dimmer, Form, Header, InputOnChangeData, Loader, Segment } from "semantic-ui-react"; |
||||||
|
|
||||||
|
class LoginPageState { |
||||||
|
@observable username = ""; |
||||||
|
@observable password = ""; |
||||||
|
|
||||||
|
@observable loading: boolean = false; |
||||||
|
|
||||||
|
@computed get canLogin() { |
||||||
|
return this.username.length > 0 && this.password.length > 0; |
||||||
|
} |
||||||
|
|
||||||
|
onUsernameChange = (e: any, data: InputOnChangeData) => { |
||||||
|
this.username = data.value; |
||||||
|
} |
||||||
|
|
||||||
|
onPasswordChange = (e: any, data: InputOnChangeData) => { |
||||||
|
this.password = data.value; |
||||||
|
} |
||||||
|
|
||||||
|
login(appState: AppState) { |
||||||
|
this.loading = true; |
||||||
|
appState.httpApi.tokenStore.grantPassword(this.username, this.password) |
||||||
|
.then(() => { |
||||||
|
this.loading = false; |
||||||
|
log.info("logged in"); |
||||||
|
appState.history.push("/"); |
||||||
|
}) |
||||||
|
.catch((err) => { |
||||||
|
this.loading = false; |
||||||
|
log.error({ err }, "login error"); |
||||||
|
}); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
class LoginPage extends React.Component<{ appState: AppState }> { |
||||||
|
pageState = new LoginPageState(); |
||||||
|
|
||||||
|
render() { |
||||||
|
const { username, password, canLogin, loading } = this.pageState; |
||||||
|
return ( |
||||||
|
<Container className="loginPage"> |
||||||
|
<Segment> |
||||||
|
<Dimmer inverted active={loading}> |
||||||
|
<Loader/> |
||||||
|
</Dimmer> |
||||||
|
|
||||||
|
<Header as="h1">Login</Header> |
||||||
|
<Form> |
||||||
|
<Form.Input label="Username" value={username} onChange={this.pageState.onUsernameChange}/> |
||||||
|
<Form.Input |
||||||
|
label="Password" |
||||||
|
value={password} |
||||||
|
type="password" |
||||||
|
onChange={this.pageState.onPasswordChange} |
||||||
|
/> |
||||||
|
<Form.Button disabled={!canLogin} onClick={this.login}>Login</Form.Button> |
||||||
|
</Form> |
||||||
|
</Segment> |
||||||
|
</Container> |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
login = () => { |
||||||
|
this.pageState.login(this.props.appState); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const DecoratedLoginPage = injectState(observer(LoginPage)); |
||||||
|
export { DecoratedLoginPage as LoginPage }; |
@ -0,0 +1,18 @@ |
|||||||
|
import * as React from "react"; |
||||||
|
import { RouteComponentProps } from "react-router"; |
||||||
|
|
||||||
|
import { DevicesView, MessageTest} from "@app/components"; |
||||||
|
|
||||||
|
export { LoginPage } from "./LoginPage"; |
||||||
|
|
||||||
|
export function DevicePage({ match }: RouteComponentProps<{ deviceId: string }>) { |
||||||
|
return ( |
||||||
|
<DevicesView deviceId={match.params.deviceId}/> |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
export function MessagesTestPage() { |
||||||
|
return ( |
||||||
|
<MessageTest/> |
||||||
|
); |
||||||
|
} |
@ -1,26 +1,28 @@ |
|||||||
import { WebSocketApiClient } from "@app/sprinklersRpc/websocketClient"; |
import { WebSocketRpcClient } from "@app/sprinklersRpc/websocketClient"; |
||||||
import HttpApi from "@app/state/HttpApi"; |
import HttpApi from "@app/state/HttpApi"; |
||||||
import { UiStore } from "@app/state/UiStore"; |
import { UiStore } from "@app/state/UiStore"; |
||||||
|
import { createBrowserHistory, History } from "history"; |
||||||
|
|
||||||
const isDev = process.env.NODE_ENV === "development"; |
const isDev = process.env.NODE_ENV === "development"; |
||||||
const websocketPort = isDev ? 8080 : location.port; |
const websocketPort = isDev ? 8080 : location.port; |
||||||
|
|
||||||
export default class ClientState { |
export default class AppState { |
||||||
sprinklersApi = new WebSocketApiClient(`ws://${location.hostname}:${websocketPort}`); |
history: History = createBrowserHistory(); |
||||||
uiStore = new UiStore(); |
uiStore = new UiStore(); |
||||||
httpApi = new HttpApi(); |
httpApi = new HttpApi(); |
||||||
|
tokenStore = this.httpApi.tokenStore; |
||||||
|
sprinklersRpc = new WebSocketRpcClient(`ws://${location.hostname}:${websocketPort}`, |
||||||
|
this.tokenStore); |
||||||
|
|
||||||
async start() { |
async start() { |
||||||
if (!this.httpApi.tokenStore.accessToken.isValid) { |
if (!this.httpApi.tokenStore.accessToken.isValid) { |
||||||
if (this.httpApi.tokenStore.refreshToken.isValid) { |
if (this.httpApi.tokenStore.refreshToken.isValid) { |
||||||
await this.httpApi.tokenStore.grantRefresh(); |
await this.httpApi.tokenStore.grantRefresh(); |
||||||
} else { |
} else { |
||||||
await this.httpApi.tokenStore.grantPassword("alex", "kakashka"); |
this.history.push("/login"); |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
this.sprinklersApi.accessToken = this.httpApi.tokenStore.accessToken.token!; |
this.sprinklersRpc.start(); |
||||||
|
|
||||||
this.sprinklersApi.start(); |
|
||||||
} |
} |
||||||
} |
} |
@ -1,9 +1,3 @@ |
|||||||
export { UiMessage, UiStore } from "./UiStore"; |
export { UiMessage, UiStore } from "./UiStore"; |
||||||
export * from "./reactContext"; |
export * from "./reactContext"; |
||||||
export { ClientState as StateBase } from "./ClientState"; |
export { default as AppState } from "./AppState"; |
||||||
|
|
||||||
import ClientState from "./ClientState"; |
|
||||||
|
|
||||||
|
|
||||||
export class WebApiState extends ClientState { |
|
||||||
} |
|
||||||
|
Loading…
Reference in new issue