added some styling and async createList action
This commit is contained in:
parent
64aed858ae
commit
b4e7e8b194
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) 😎"
|
||||||
}
|
}
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
})
|
})
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
export interface IMobxTutorialProps {
|
|
||||||
description: string;
|
|
||||||
}
|
|
|
@ -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 });
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue