added some styling and async createList action

This commit is contained in:
Kemal S 2019-05-23 15:30:28 +02:00
parent 64aed858ae
commit b4e7e8b194
8 changed files with 122 additions and 32 deletions

View File

@ -1,5 +1,5 @@
import { action, computed, observable, runInAction } from "mobx";
import { RootStore } from "./RootStore"; import { RootStore } from "./RootStore";
import { observable, action, computed } from "mobx";
export enum ApplicationStatus { export enum ApplicationStatus {
Loading = "Loading", Loading = "Loading",
@ -26,7 +26,7 @@ export class AppStore {
} }
@action @action
private setInitialState() { private setInitialState(): void {
this.status = ApplicationStatus.CreateList; this.status = ApplicationStatus.CreateList;
this.listTitle = null; this.listTitle = null;
this.items = []; this.items = [];
@ -50,18 +50,27 @@ export class AppStore {
} }
@action @action
public confirmListCreation(listTitle: string) { public async createList(listTitle: string): Promise<void> {
this.status = ApplicationStatus.CreateItems; return new Promise<void>((resolve, reject) => {
this.listTitle = listTitle; // Mock creating list
setTimeout(() => {
runInAction(() => {
this.status = ApplicationStatus.CreateItems;
this.listTitle = listTitle;
resolve();
});
}, 1000);
});
} }
@action @action
public addListItem(item: IFakeItem) { public addListItem(item: IFakeItem): void {
this.items.push(item); this.items.push(item);
} }
@action @action
public confirmItems() { public confirmItems(): void {
this.status = ApplicationStatus.Completed; this.status = ApplicationStatus.Completed;
} }
} }

View File

@ -26,7 +26,6 @@ export class ConfigStore {
@action @action
private loadConfigration() { private loadConfigration() {
this.isLoading = false; this.isLoading = false;
this.applicationTitle = "Default Application Title";
this.allowImportantItems = true; this.allowImportantItems = true;
this.rootStore.appStore.isLoadingConfiguration = false; this.rootStore.appStore.isLoadingConfiguration = false;
} }

View File

@ -21,7 +21,7 @@
"description": { "default": "An example of a webpart using mobx for managing the application state" }, "description": { "default": "An example of a webpart using mobx for managing the application state" },
"officeFabricIconFontName": "Page", "officeFabricIconFontName": "Page",
"properties": { "properties": {
"description": "MobxTutorial" "ApplicationTitle": "Mobx Tutorial Title (change in webpart properties) 😎"
} }
}] }]
} }

View File

@ -11,14 +11,21 @@ import MobxTutorialProvider from './components/MobxTutorialProvider';
configure({ enforceActions: "always" }); configure({ enforceActions: "always" });
export interface IMobxTutorialWebPartProps { export interface IMobxTutorialWebPartProps {
description: string; ApplicationTitle: string;
} }
export default class MobxTutorialWebPart extends BaseClientSideWebPart<IMobxTutorialWebPartProps> { export default class MobxTutorialWebPart extends BaseClientSideWebPart<IMobxTutorialWebPartProps> {
private readonly dependencies = { rootStore: new RootStore() }; private readonly dependencies = { rootStore: new RootStore() };
public render(): void { protected onInit() {
return new Promise<void>((resolve, reject) => {
const { configStore } = this.dependencies.rootStore;
configStore.setApplicationTitle(this.properties.ApplicationTitle);
resolve();
});
}
public render(): void {
const element: React.ReactElement<{}> = React.createElement( const element: React.ReactElement<{}> = React.createElement(
MobxTutorialProvider, MobxTutorialProvider,
{ {
@ -30,7 +37,7 @@ export default class MobxTutorialWebPart extends BaseClientSideWebPart<IMobxTuto
} }
protected onPropertyPaneFieldChanged(propertyPath: string, oldValue: any, newValue: any): void { protected onPropertyPaneFieldChanged(propertyPath: string, oldValue: any, newValue: any): void {
if (propertyPath === "Application title") { if (propertyPath === "ApplicationTitle") {
const { configStore } = this.dependencies.rootStore; const { configStore } = this.dependencies.rootStore;
configStore.setApplicationTitle(newValue); configStore.setApplicationTitle(newValue);
} }
@ -55,8 +62,8 @@ export default class MobxTutorialWebPart extends BaseClientSideWebPart<IMobxTuto
{ {
groupName: strings.BasicGroupName, groupName: strings.BasicGroupName,
groupFields: [ groupFields: [
PropertyPaneTextField('Application title', { PropertyPaneTextField('ApplicationTitle', {
label: strings.AppTitleFieldLabel label: strings.AppTitleFieldLabel,
}) })
] ]
} }

View File

@ -1,3 +0,0 @@
export interface IMobxTutorialProps {
description: string;
}

View File

@ -0,0 +1,72 @@
import { inject, observer } from "mobx-react";
import { PrimaryButton } from 'office-ui-fabric-react/lib/Button';
import { Spinner, SpinnerSize } from 'office-ui-fabric-react/lib/Spinner';
import { TextField } from 'office-ui-fabric-react/lib/TextField';
import * as React from 'react';
import { AppStore } from '../../../stores/AppStore';
import { Stores } from "../../../stores/RootStore";
export type ListCreatorStoreProps = {
appStore: AppStore;
};
export type ListCreatorProps = Partial<ListCreatorStoreProps>;
export type ListCreatorState = {
loading: boolean;
errorMessage: string;
listTitle: string;
};
@inject(Stores.AppStore)
@observer
export class ListCreator extends React.Component<ListCreatorProps, ListCreatorState> {
public state = {
loading: false,
errorMessage: undefined,
listTitle: null
};
public render(): React.ReactElement<ListCreatorProps> {
const spinner = (<Spinner size={SpinnerSize.xSmall} label="Creating list ..." labelPosition="right" />);
return (
<div>
<TextField
label="List title"
errorMessage={this.state.errorMessage}
onChange={this._onChangeListTitle}
value={this.state.listTitle}
/>
<PrimaryButton
onClick={() => this.createList()}
disabled={this.state.loading}
>
{this.state.loading ? spinner : "Create List"}
</PrimaryButton>
</div>
);
}
public async createList() {
if (this.state.listTitle && this.state.listTitle.length > 0) {
this.setState({ ...this.state, loading: true, errorMessage: undefined });
await this.props.appStore.createList("MOCK TITLE");
this.setState({ ...this.state, loading: false });
}
else {
this.setState({ ...this.state, errorMessage: "Required" });
}
}
private _onChangeListTitle = (ev: React.FormEvent<HTMLInputElement>, newValue?: string) => {
if (newValue === "" && newValue.length === 0) {
this.setState({ ...this.state, listTitle: newValue, errorMessage: "Required" });
}
else {
this.setState({ ...this.state, listTitle: newValue });
}
};
}

View File

@ -9,8 +9,6 @@
.row { .row {
@include ms-Grid-row; @include ms-Grid-row;
@include ms-fontColor-white;
background-color: $ms-color-themeDark;
padding: 20px; padding: 20px;
} }
@ -24,17 +22,10 @@
.title { .title {
@include ms-font-xl; @include ms-font-xl;
@include ms-fontColor-white;
} }
.subTitle { .subTitle {
@include ms-font-l; @include ms-font-l;
@include ms-fontColor-white;
}
.description {
@include ms-font-l;
@include ms-fontColor-white;
} }
.button { .button {
@ -51,7 +42,7 @@
// Basic Button // Basic Button
outline: transparent; outline: transparent;
position: relative; position: relative;
font-family: "Segoe UI WestEuropean","Segoe UI",-apple-system,BlinkMacSystemFont,Roboto,"Helvetica Neue",sans-serif; font-family: "Segoe UI WestEuropean", "Segoe UI", -apple-system, BlinkMacSystemFont, Roboto, "Helvetica Neue", sans-serif;
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
font-size: $ms-font-size-m; font-size: $ms-font-size-m;
font-weight: $ms-font-weight-regular; font-weight: $ms-font-weight-regular;
@ -71,4 +62,4 @@
display: inline-block; display: inline-block;
} }
} }
} }

View File

@ -6,6 +6,8 @@ import { ConfigStore } from '../../../stores/ConfigStore';
import { Stores } from '../../../stores/RootStore'; import { Stores } from '../../../stores/RootStore';
import { FakeItemContainer } from './FakeItemContainer'; import { FakeItemContainer } from './FakeItemContainer';
import { ProgressIndicator } from './ProgressIndicator'; import { ProgressIndicator } from './ProgressIndicator';
import { ListCreator } from './ListCreator';
import styles from './MobxTutorial.module.scss';
export type MobxTutorialStoreProps = { export type MobxTutorialStoreProps = {
appStore: AppStore; appStore: AppStore;
@ -24,10 +26,23 @@ export class MobxTutorial extends React.Component<MobxTutorialProps, {}> {
return (<Spinner size={SpinnerSize.large} label="Loading... please hodl" ariaLive="assertive" labelPosition="left" />); return (<Spinner size={SpinnerSize.large} label="Loading... please hodl" ariaLive="assertive" labelPosition="left" />);
return ( return (
<div> <div className={styles.mobxTutorial}>
<h1>{configStore.applicationTitle}</h1>
<ProgressIndicator></ProgressIndicator> <div className={styles.row}>
<FakeItemContainer></FakeItemContainer> <div className={styles.title}>{configStore.applicationTitle}</div>
<ProgressIndicator></ProgressIndicator>
</div>
<div className={styles.row}>
<div className={styles.subTitle}>1) Create List</div>
<ListCreator></ListCreator>
</div>
<div className={styles.row}>
<div className={styles.subTitle}>2) Create Items</div>
<FakeItemContainer></FakeItemContainer>
</div>
</div> </div>
); );
} }