mirror of
https://github.com/usatiuk/writer.git
synced 2025-10-28 16:07:49 +01:00
add a document upload indicator
This commit is contained in:
@@ -10,6 +10,9 @@ module.exports = {
|
||||
...pathsToModuleNameMapper(compilerOptions.paths, {
|
||||
prefix: "<rootDir>/",
|
||||
}),
|
||||
"react-spring/renderprops":
|
||||
"<rootDir>/node_modules/react-spring/renderprops.cjs",
|
||||
"react-spring": "<rootDir>/node_modules/react-spring/web.cjs",
|
||||
},
|
||||
setupFilesAfterEnv: ["<rootDir>/src/setupTests.ts"],
|
||||
};
|
||||
|
||||
@@ -24,6 +24,10 @@
|
||||
.bp3-navbar {
|
||||
transition: 0.3s;
|
||||
}
|
||||
|
||||
#uploadingStatusButton {
|
||||
width: 40px;
|
||||
}
|
||||
}
|
||||
|
||||
#mainContainer.bp3-dark {
|
||||
|
||||
@@ -6,9 +6,11 @@ import {
|
||||
Button,
|
||||
Classes,
|
||||
IBreadcrumbProps,
|
||||
Icon,
|
||||
Menu,
|
||||
Navbar,
|
||||
Popover,
|
||||
Spinner,
|
||||
} from "@blueprintjs/core";
|
||||
import * as React from "react";
|
||||
import { connect } from "react-redux";
|
||||
@@ -24,10 +26,13 @@ import { toggleDarkMode } from "~redux/localSettings/actions";
|
||||
import { IAppState } from "~redux/reducers";
|
||||
import { logoutUser } from "~redux/user/actions";
|
||||
|
||||
interface IHomeProps extends RouteComponentProps {
|
||||
export interface IHomeProps extends RouteComponentProps {
|
||||
allDocs: { [key: number]: IDocumentJSON };
|
||||
user: IUserJSON | null;
|
||||
|
||||
fetching: boolean;
|
||||
uploading: boolean;
|
||||
|
||||
darkMode: boolean;
|
||||
|
||||
logout: () => void;
|
||||
@@ -72,6 +77,13 @@ export class HomeComponent extends React.PureComponent<IHomeProps> {
|
||||
<Breadcrumbs items={breadcrumbs} />
|
||||
</Navbar.Group>
|
||||
<Navbar.Group align={Alignment.RIGHT}>
|
||||
<Button id="uploadingStatusButton">
|
||||
{this.props.uploading ? (
|
||||
<Spinner size={20} />
|
||||
) : (
|
||||
<Icon icon="saved" />
|
||||
)}
|
||||
</Button>
|
||||
<Popover
|
||||
target={
|
||||
<Button id="userButton">
|
||||
@@ -161,6 +173,8 @@ function mapStateToProps(state: IAppState) {
|
||||
allDocs: state.docs.all,
|
||||
user: state.user.user,
|
||||
darkMode: state.localSettings.darkMode,
|
||||
fetching: state.docs.fetching,
|
||||
uploading: state.docs.uploading,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
52
frontend/src/Home/tests/Home.test.tsx
Normal file
52
frontend/src/Home/tests/Home.test.tsx
Normal file
@@ -0,0 +1,52 @@
|
||||
import { shallow } from "enzyme";
|
||||
import * as React from "react";
|
||||
|
||||
import { Icon, Spinner } from "@blueprintjs/core";
|
||||
import { HomeComponent, IHomeProps } from "../Home";
|
||||
|
||||
const defaultHomeProps: IHomeProps = {
|
||||
allDocs: {},
|
||||
user: { id: 1, username: "test" },
|
||||
|
||||
fetching: false,
|
||||
uploading: false,
|
||||
|
||||
darkMode: false,
|
||||
|
||||
logout: jest.fn(),
|
||||
dispatchToggleDarkMode: jest.fn(),
|
||||
|
||||
history: { location: { pathname: "/" } } as any,
|
||||
location: { pathname: "/" } as any,
|
||||
match: {
|
||||
params: {
|
||||
id: null,
|
||||
},
|
||||
} as any,
|
||||
};
|
||||
|
||||
describe("<Home />", () => {
|
||||
it("should show a spinner when uploading", () => {
|
||||
const wrapper = shallow(
|
||||
<HomeComponent {...defaultHomeProps} uploading={true} />,
|
||||
);
|
||||
expect(
|
||||
wrapper.find("#uploadingStatusButton").find(Spinner),
|
||||
).toHaveLength(1);
|
||||
expect(wrapper.find("#uploadingStatusButton").find(Icon)).toHaveLength(
|
||||
0,
|
||||
);
|
||||
});
|
||||
|
||||
it("should show a saved icon when not uploading", () => {
|
||||
const wrapper = shallow(
|
||||
<HomeComponent {...defaultHomeProps} uploading={false} />,
|
||||
);
|
||||
expect(
|
||||
wrapper.find("#uploadingStatusButton").find(Spinner),
|
||||
).toHaveLength(0);
|
||||
expect(wrapper.find("#uploadingStatusButton").find(Icon)).toHaveLength(
|
||||
1,
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -7,6 +7,7 @@ import { DocsAction, DocsTypes } from "./actions";
|
||||
export interface IDocsState {
|
||||
all: { [key: number]: IDocumentJSON };
|
||||
fetching: boolean;
|
||||
uploading: boolean;
|
||||
error: string | null;
|
||||
spinner: boolean;
|
||||
|
||||
@@ -18,6 +19,7 @@ export interface IDocsState {
|
||||
const defaultDocsState: IDocsState = {
|
||||
all: null,
|
||||
fetching: false,
|
||||
uploading: false,
|
||||
error: null,
|
||||
spinner: false,
|
||||
newDocumentID: null,
|
||||
@@ -64,11 +66,17 @@ export const docsReducer: Reducer<IDocsState, DocsAction> = (
|
||||
all[deletedDocument.id] = deletedDocument;
|
||||
return { ...state, deletedDocument: null, all };
|
||||
}
|
||||
case DocsTypes.DOC_UPDATE_START: {
|
||||
return { ...state, uploading: true };
|
||||
}
|
||||
case DocsTypes.DOC_UPDATE_FAIL: {
|
||||
return { ...state, uploading: false };
|
||||
}
|
||||
case DocsTypes.DOC_UPDATE_SUCCESS: {
|
||||
const all = { ...state.all };
|
||||
const doc = action.payload.doc;
|
||||
all[doc.id] = doc;
|
||||
return { ...state, all };
|
||||
return { ...state, all, uploading: false };
|
||||
}
|
||||
case DocsTypes.DOCS_FETCH_FAIL:
|
||||
return { ...defaultDocsState, ...action.payload };
|
||||
|
||||
Reference in New Issue
Block a user