Setup chromatic and cleanup storybook (#3588)

This commit is contained in:
Krzysztof Żuraw 2023-05-12 13:06:27 +02:00 committed by GitHub
parent b9bf19ddfb
commit 50c8e93534
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
139 changed files with 15566 additions and 18270 deletions

View file

@ -0,0 +1,35 @@
name: QA
on: [pull_request]
jobs:
chromatic-storybook:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version-file: ".nvmrc"
- name: Cache node modules
uses: actions/cache@v3
env:
cache-name: cache-node-modules
with:
# npm cache files are stored in `~/.npm` on Linux/macOS
path: ~/.npm
key: ${{ runner.os }}-qa-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-qa-${{ env.cache-name }}-
${{ runner.os }}-qa-
${{ runner.os }}-
- name: Install deps
run: npm ci
- name: Publish to Chromatic
uses: chromaui/action@a89b674adf766dbde41ad9ea2b2b60b91188a0f0 # v6.17.4
with:
projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}

View file

@ -49,7 +49,7 @@ jobs:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- uses: actions/setup-node@v3 - uses: actions/setup-node@v3
with: with:
node-version-file: '.nvmrc' node-version-file: ".nvmrc"
- name: Cache node modules - name: Cache node modules
uses: actions/cache@v2 uses: actions/cache@v2
env: env:

1
.gitignore vendored
View file

@ -21,6 +21,7 @@
!.travis* !.travis*
!.tx !.tx
!.husky !.husky
!.storybook
*.log *.log
*.pyc *.pyc
*.mo *.mo

View file

@ -1,7 +1,8 @@
import { Card, CardContent } from "@material-ui/core"; import { Card, CardContent } from "@material-ui/core";
import { Decorator } from "@storybook/react";
import React from "react"; import React from "react";
const CardDecorator = storyFn => ( export const CardDecorator: Decorator = Story => (
<Card <Card
style={{ style={{
margin: "auto", margin: "auto",
@ -10,7 +11,8 @@ const CardDecorator = storyFn => (
width: 400, width: 400,
}} }}
> >
<CardContent>{storyFn()}</CardContent> <CardContent>
<Story />
</CardContent>
</Card> </Card>
); );
export default CardDecorator;

View file

@ -1,22 +1,23 @@
import "@saleor/macaw-ui/next/style"; import "@saleor/macaw-ui/next/style";
import { ExternalAppProvider } from "@dashboard/apps/components/ExternalAppContext";
import { Locale, RawLocaleProvider } from "@dashboard/components/Locale";
import { FlagsServiceProvider } from "@dashboard/hooks/useFlags/flagsService";
import { paletteOverrides, themeOverrides } from "@dashboard/themeOverrides";
import { ThemeProvider as LegacyThemeProvider } from "@saleor/macaw-ui"; import { ThemeProvider as LegacyThemeProvider } from "@saleor/macaw-ui";
import { ThemeProvider } from "@saleor/macaw-ui/next"; import { ThemeProvider } from "@saleor/macaw-ui/next";
import React from "react"; import React from "react";
import { IntlProvider } from "react-intl"; import { IntlProvider } from "react-intl";
import { BrowserRouter } from "react-router-dom"; import { BrowserRouter } from "react-router-dom";
import { ExternalAppProvider } from "../../src/apps/components/ExternalAppContext";
import { DevModeProvider } from "../../src/components/DevModePanel/DevModeProvider";
import { Locale, RawLocaleProvider } from "../../src/components/Locale";
import { FlagsServiceProvider } from "../../src/hooks/useFlags/flagsService";
import { paletteOverrides, themeOverrides } from "../../src/themeOverrides";
import { Provider as DateProvider } from "../../src/components/Date/DateContext";
import { TimezoneProvider } from "../../src/components/Timezone";
import MessageManagerProvider from "../../src/components/messages";
import { getAppMountUri } from "../../src/config";
import { ApolloMockedProvider } from "../../testUtils/ApolloMockedProvider"; import { ApolloMockedProvider } from "../../testUtils/ApolloMockedProvider";
import { Provider as DateProvider } from "../components/Date/DateContext";
import MessageManagerProvider from "../components/messages";
import { TimezoneProvider } from "../components/Timezone";
import { getAppMountUri } from "../config";
export const Decorator = storyFn => ( export const MockedProvidersDecorator: React.FC = ({ children }) => (
<ApolloMockedProvider> <ApolloMockedProvider>
<IntlProvider defaultLocale={Locale.EN} locale={Locale.EN}> <IntlProvider defaultLocale={Locale.EN} locale={Locale.EN}>
<RawLocaleProvider <RawLocaleProvider
@ -36,13 +37,15 @@ export const Decorator = storyFn => (
<ExternalAppProvider> <ExternalAppProvider>
<FlagsServiceProvider> <FlagsServiceProvider>
<MessageManagerProvider> <MessageManagerProvider>
<div <DevModeProvider>
style={{ <div
padding: 24, style={{
}} padding: 24,
> }}
{storyFn()} >
</div> {children}
</div>
</DevModeProvider>
</MessageManagerProvider> </MessageManagerProvider>
</FlagsServiceProvider> </FlagsServiceProvider>
</ExternalAppProvider> </ExternalAppProvider>
@ -55,4 +58,3 @@ export const Decorator = storyFn => (
</IntlProvider> </IntlProvider>
</ApolloMockedProvider> </ApolloMockedProvider>
); );
export default Decorator;

View file

@ -0,0 +1,10 @@
import { Decorator } from "@storybook/react";
import React from "react";
import { paginatorContextValues } from "../../src/fixtures";
import { PaginatorContext } from "../../src/hooks/usePaginator";
export const PaginatorContextDecorator: Decorator = Story => (
<PaginatorContext.Provider value={paginatorContextValues}>
<Story />
</PaginatorContext.Provider>
);

View file

@ -0,0 +1,3 @@
export * from "./CardDecorator";
export * from "./MockedProvidersDecorator";
export * from "./PaginatorContextDecorator";

View file

@ -1,7 +1,7 @@
import { UserContext } from "@dashboard/auth";
import { adminUserPermissions } from "@dashboard/fixtures";
import { UserFragment } from "@dashboard/graphql";
import * as React from "react"; import * as React from "react";
import { UserContext } from "../../src/auth";
import { adminUserPermissions } from "../../src/fixtures";
import { UserFragment } from "../../src/graphql";
export const MockedUserProvider: React.FC<{ export const MockedUserProvider: React.FC<{
customPermissions?: UserFragment["userPermissions"]; customPermissions?: UserFragment["userPermissions"];

View file

@ -0,0 +1,2 @@
export * from "./MockedUserProvider";
export * from "./formError";

42
.storybook/main.ts Normal file
View file

@ -0,0 +1,42 @@
import { withoutVitePlugins } from "@storybook/builder-vite";
import type { StorybookConfig } from "@storybook/react-vite";
import { resolve } from "path";
import { mergeConfig } from "vite";
const config: StorybookConfig = {
stories: ["../src/**/*.stories.@(js|jsx|ts|tsx)"],
addons: [
"@storybook/addon-links",
"@storybook/addon-essentials",
"@storybook/addon-interactions",
],
framework: {
name: "@storybook/react-vite",
options: {},
},
docs: {
autodocs: "tag",
},
features: {
storyStoreV7: true,
},
async viteFinal(config) {
config.plugins = await withoutVitePlugins(config.plugins, ["vite:html"]);
return mergeConfig(config, {
build: {
commonjsOptions: {
transformMixedEsModules: true,
},
},
resolve: {
alias: {
"@material-ui/lab": resolve("./node_modules/@material-ui/lab"),
},
},
});
},
};
export default config;

View file

@ -1,2 +1,3 @@
<div id="dashboard-app"></div>
<div id="portal"></div> <div id="portal"></div>
<div id="modal-root"></div> <div id="modal-root"></div>

View file

@ -2,6 +2,7 @@
window.__SALEOR_CONFIG__ = { window.__SALEOR_CONFIG__ = {
API_URL: "", API_URL: "",
APP_MOUNT_URI: "/", APP_MOUNT_URI: "/",
IS_CLOUD_INSTANCE: "", IS_CLOUD_INSTANCE: false,
}; };
window.process = { cwd: () => "" };
</script> </script>

25
.storybook/preview.tsx Normal file
View file

@ -0,0 +1,25 @@
import "@saleor/macaw-ui/next/style";
import type { Decorator, Preview } from "@storybook/react";
import React from "react";
import { MockedProvidersDecorator } from "./decorators";
export const preview: Preview = {
parameters: {
actions: { argTypesRegex: "^on[A-Z].*" },
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/,
},
},
},
};
export const decorators: Decorator[] = [
Story => (
<MockedProvidersDecorator>
<Story />
</MockedProvidersDecorator>
),
];

View file

Before

Width:  |  Height:  |  Size: 110 KiB

After

Width:  |  Height:  |  Size: 110 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 129 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 110 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 63 KiB

28514
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -150,6 +150,7 @@
"babel-core": "^7.0.0-bridge.0", "babel-core": "^7.0.0-bridge.0",
"babel-jest": "^27.5.1", "babel-jest": "^27.5.1",
"babel-loader": "^8.0.6", "babel-loader": "^8.0.6",
"babel-plugin-macros": "^3.1.0",
"ci-info": "^3.7.0", "ci-info": "^3.7.0",
"codecov": "^3.7.1", "codecov": "^3.7.1",
"core-js": "^3.7.0", "core-js": "^3.7.0",
@ -159,7 +160,6 @@
"dotenv": "^10.0.0", "dotenv": "^10.0.0",
"env-var": "^7.3.0", "env-var": "^7.3.0",
"esbuild-loader": "^2.18.0", "esbuild-loader": "^2.18.0",
"fork-ts-checker-webpack-plugin": "^3.1.1",
"graphql-request": "^3.7.0", "graphql-request": "^3.7.0",
"identity-obj-proxy": "^3.0.0", "identity-obj-proxy": "^3.0.0",
"is-ci": "^3.0.1", "is-ci": "^3.0.1",
@ -171,7 +171,6 @@
"rimraf": "^3.0.0", "rimraf": "^3.0.0",
"rollup-plugin-polyfill-node": "^0.11.0", "rollup-plugin-polyfill-node": "^0.11.0",
"start-server-and-test": "^1.11.0", "start-server-and-test": "^1.11.0",
"tsconfig-paths-webpack-plugin": "^3.2.0",
"typescript": "^5.0.2", "typescript": "^5.0.2",
"vite": "^3.2.4", "vite": "^3.2.4",
"vite-plugin-html": "^3.2.0", "vite-plugin-html": "^3.2.0",
@ -184,7 +183,11 @@
"workbox-strategies": "^6.1.2" "workbox-strategies": "^6.1.2"
}, },
"optionalDependencies": { "optionalDependencies": {
"@storybook/react": "^5.1.9", "@storybook/addon-essentials": "^7.0.8",
"@storybook/addon-interactions": "^7.0.8",
"@storybook/addon-links": "^7.0.8",
"@storybook/react": "^7.0.8",
"@storybook/react-vite": "^7.0.8",
"@swc/core-darwin-arm64": "1.3.40", "@swc/core-darwin-arm64": "1.3.40",
"@swc/core-darwin-x64": "1.3.40", "@swc/core-darwin-x64": "1.3.40",
"@swc/core-linux-arm-gnueabihf": "1.3.40", "@swc/core-linux-arm-gnueabihf": "1.3.40",
@ -201,7 +204,7 @@
"@testing-library/user-event": "^14.4.3", "@testing-library/user-event": "^14.4.3",
"@types/jest": "^26.0.14", "@types/jest": "^26.0.14",
"@types/setup-polly-jest": "^0.5.0", "@types/setup-polly-jest": "^0.5.0",
"@types/storybook__react": "^4.0.2", "chromatic": "^6.17.4",
"cypress": "^12.4.0", "cypress": "^12.4.0",
"cypress-file-upload": "^5.0.8", "cypress-file-upload": "^5.0.8",
"cypress-mailhog": "^1.3.0", "cypress-mailhog": "^1.3.0",
@ -234,6 +237,7 @@
"mochawesome-report-generator": "^6.0.1", "mochawesome-report-generator": "^6.0.1",
"prettier": "^2.8.4", "prettier": "^2.8.4",
"setup-polly-jest": "^0.9.1", "setup-polly-jest": "^0.9.1",
"storybook": "^7.0.8",
"ts-jest": "^27.1.5" "ts-jest": "^27.1.5"
}, },
"//@swc/*": "swc packages are required until https://github.com/npm/cli/issues/4828 is fixed", "//@swc/*": "swc packages are required until https://github.com/npm/cli/issues/4828 is fixed",
@ -294,7 +298,7 @@
"dev": "vite --host", "dev": "vite --host",
"build": "cross-env NODE_OPTIONS=--max_old_space_size=16384 vite build", "build": "cross-env NODE_OPTIONS=--max_old_space_size=16384 vite build",
"preview": "vite preview", "preview": "vite preview",
"build-storybook": "cross-env NODE_OPTIONS=--openssl-legacy-provider build-storybook -c src/storybook/ -o build/storybook", "build-storybook": "cross-env NODE_OPTIONS=--max_old_space_size=16384 storybook build -o build/storybook",
"build-types": "node scripts/build-types.js", "build-types": "node scripts/build-types.js",
"prebuild": "npm run build-types", "prebuild": "npm run build-types",
"check-strict-null-errors": "tsc --noEmit --strictNullChecks | node scripts/count-strict-null-check-errors.js", "check-strict-null-errors": "tsc --noEmit --strictNullChecks | node scripts/count-strict-null-check-errors.js",
@ -305,7 +309,7 @@
"heroku-postbuild": "npm run build", "heroku-postbuild": "npm run build",
"serve:lhci": "cross-env NODE_ENV=production npm run server", "serve:lhci": "cross-env NODE_ENV=production npm run server",
"prestart": "npm run build-types", "prestart": "npm run build-types",
"storybook": "cross-env NODE_OPTIONS=--openssl-legacy-provider start-storybook -p 3000 -c src/storybook/", "storybook": "storybook dev --port 3000",
"cy:run": "cypress run", "cy:run": "cypress run",
"cy:run:dashboard": "cypress run --record", "cy:run:dashboard": "cypress run --record",
"cy:open": "cypress open", "cy:open": "cypress open",
@ -324,7 +328,8 @@
"predev": "npm run build-types", "predev": "npm run build-types",
"release": "release-it", "release": "release-it",
"prepare": "is-ci || husky install", "prepare": "is-ci || husky install",
"dep-status": "depcruise --config .dependency-cruiser.js src" "dep-status": "depcruise --config .dependency-cruiser.js src",
"chromatic": "chromatic --exit-zero-on-changes"
}, },
"description": "![Saleor Dashboard](https://user-images.githubusercontent.com/44495184/185379472-2a204c0b-9b7a-4a3e-93c0-2cb85205ed5e.png)" "description": "![Saleor Dashboard](https://user-images.githubusercontent.com/44495184/185379472-2a204c0b-9b7a-4a3e-93c0-2cb85205ed5e.png)"
} }

View file

@ -1,20 +0,0 @@
import Decorator from "@dashboard/storybook/Decorator";
import { storiesOf } from "@storybook/react";
import React from "react";
import AppDeactivateDialog, {
AppDeactivateDialogProps,
} from "./AppDeactivateDialog";
const props: AppDeactivateDialogProps = {
confirmButtonState: "default",
name: "App",
onClose: () => undefined,
onConfirm: () => undefined,
open: true,
};
storiesOf("Views / Apps / Deactivate app", module)
.addDecorator(Decorator)
.add("default", () => <AppDeactivateDialog {...props} />)
.add("unnamed app", () => <AppDeactivateDialog {...props} name={null} />);

View file

@ -1,19 +0,0 @@
import Decorator from "@dashboard/storybook/Decorator";
import { storiesOf } from "@storybook/react";
import React from "react";
import AppDeleteDialog, { AppDeleteDialogProps } from "./AppDeleteDialog";
const props: AppDeleteDialogProps = {
confirmButtonState: "default",
name: "App",
onClose: () => undefined,
onConfirm: () => undefined,
open: true,
type: "EXTERNAL",
};
storiesOf("Views / Apps / Delete app", module)
.addDecorator(Decorator)
.add("default", () => <AppDeleteDialog {...props} />)
.add("unnamed app", () => <AppDeleteDialog {...props} name={null} />);

View file

@ -1,5 +1,3 @@
import Decorator from "@dashboard/storybook/Decorator";
import { storiesOf } from "@storybook/react";
import React from "react"; import React from "react";
import { appDetails } from "../../fixtures"; import { appDetails } from "../../fixtures";
@ -14,7 +12,10 @@ const props: AppDetailsPageProps = {
onAppDeleteOpen: () => undefined, onAppDeleteOpen: () => undefined,
}; };
storiesOf("Apps / App details", module) export default {
.addDecorator(Decorator) title: "Apps / App details",
.add("default", () => <AppDetailsPage {...props} />) };
.add("loading", () => <AppDetailsPage {...props} loading={true} />);
export const Default = () => <AppDetailsPage {...props} />;
export const Loading = () => <AppDetailsPage {...props} loading={true} />;

View file

@ -1,20 +0,0 @@
import Decorator from "@dashboard/storybook/Decorator";
import { storiesOf } from "@storybook/react";
import React from "react";
import AppInProgressDeleteDialog, {
AppInProgressDeleteDialogProps,
} from "./AppInProgressDeleteDialog";
const props: AppInProgressDeleteDialogProps = {
confirmButtonState: "default",
name: "App",
onClose: () => undefined,
onConfirm: () => undefined,
open: true,
};
storiesOf("Views / Apps / Delete app failed installation", module)
.addDecorator(Decorator)
.add("default", () => <AppInProgressDeleteDialog {...props} />)
.add("unnamed app", () => <AppInProgressDeleteDialog {...props} name="" />);

View file

@ -1,5 +1,3 @@
import Decorator from "@dashboard/storybook/Decorator";
import { storiesOf } from "@storybook/react";
import React from "react"; import React from "react";
import { installApp } from "../../fixtures"; import { installApp } from "../../fixtures";
@ -12,7 +10,10 @@ const props: AppInstallPageProps = {
onSubmit: () => Promise.resolve([]), onSubmit: () => Promise.resolve([]),
}; };
storiesOf("Apps / Install App", module) export default {
.addDecorator(Decorator) title: "Apps / Install App",
.add("default", () => <AppInstallPage {...props} />) };
.add("loading", () => <AppInstallPage {...props} loading={true} />);
export const Default = () => <AppInstallPage {...props} />;
export const Loading = () => <AppInstallPage {...props} loading={true} />;

View file

@ -1,6 +1,4 @@
import { installedAppsList } from "@dashboard/apps/fixtures"; import { installedAppsList } from "@dashboard/apps/fixtures";
import Decorator from "@dashboard/storybook/Decorator";
import { storiesOf } from "@storybook/react";
import React from "react"; import React from "react";
import AppListPage, { AppListPageProps } from "./AppListPage"; import AppListPage, { AppListPageProps } from "./AppListPage";
@ -10,14 +8,17 @@ const props: AppListPageProps = {
installedApps: installedAppsList, installedApps: installedAppsList,
}; };
storiesOf("Apps / New Apps / App List", module) export default {
.addDecorator(Decorator) title: "Apps / New Apps / App List",
.add("default", () => <AppListPage {...props} />) };
.add("empty", () => (
<AppListPage export const Default = () => <AppListPage {...props} />;
{...props}
installedApps={[]} export const Empty = () => (
installableMarketplaceApps={[]} <AppListPage
comingSoonMarketplaceApps={[]} {...props}
/> installedApps={[]}
)); installableMarketplaceApps={[]}
comingSoonMarketplaceApps={[]}
/>
);

View file

@ -1,5 +1,3 @@
import Decorator from "@dashboard/storybook/Decorator";
import { storiesOf } from "@storybook/react";
import React from "react"; import React from "react";
import { appDetails } from "../../fixtures"; import { appDetails } from "../../fixtures";
@ -11,9 +9,12 @@ const props: AppPageProps = {
onError: () => undefined, onError: () => undefined,
}; };
storiesOf("Apps / App", module) export default {
.addDecorator(Decorator) title: "Apps / App",
.add("default", () => <AppPage {...props} />) };
.add("settings", () => (
<AppPage {...props} url={appDetails.configurationUrl!} /> export const Default = () => <AppPage {...props} />;
));
export const Settings = () => (
<AppPage {...props} url={appDetails.configurationUrl!} />
);

View file

@ -20,7 +20,7 @@ import AttributeDetailsComponent from "./views/AttributeDetails";
import AttributeListComponent from "./views/AttributeList"; import AttributeListComponent from "./views/AttributeList";
const AttributeList: React.FC<RouteComponentProps<{}>> = ({ location }) => { const AttributeList: React.FC<RouteComponentProps<{}>> = ({ location }) => {
const qs = parseQs(location.search.substr(1)); const qs = parseQs(location.search.substr(1)) as any;
const params: AttributeListUrlQueryParams = asSortParams( const params: AttributeListUrlQueryParams = asSortParams(
qs, qs,
AttributeListUrlSortField, AttributeListUrlSortField,

View file

@ -1,8 +1,6 @@
import CardDecorator from "@dashboard/storybook/CardDecorator";
import Decorator from "@dashboard/storybook/Decorator";
import { storiesOf } from "@storybook/react";
import React from "react"; import React from "react";
import { CardDecorator } from "../../../../.storybook/decorators";
import LoginPage, { LoginCardProps } from "./LoginPage"; import LoginPage, { LoginCardProps } from "./LoginPage";
const props: Omit<LoginCardProps, "classes"> = { const props: Omit<LoginCardProps, "classes"> = {
@ -20,13 +18,21 @@ const props: Omit<LoginCardProps, "classes"> = {
onSubmit: () => undefined, onSubmit: () => undefined,
}; };
storiesOf("Authentication / Log in", module) export default {
.addDecorator(CardDecorator) title: "Authentication / Log in",
.addDecorator(Decorator) decorators: [CardDecorator],
.add("default", () => <LoginPage {...props} />) };
.add("error login", () => <LoginPage {...props} errors={["loginError"]} />)
.add("error external login", () => ( export const Default = () => <LoginPage {...props} />;
<LoginPage {...props} errors={["externalLoginError"]} />
)) export const ErrorLogin = () => (
.add("disabled", () => <LoginPage {...props} disabled={true} />) <LoginPage {...props} errors={["loginError"]} />
.add("loading", () => <LoginPage {...props} loading={true} />); );
export const ErrorExternalLogin = () => (
<LoginPage {...props} errors={["externalLoginError"]} />
);
export const Disabled = () => <LoginPage {...props} disabled={true} />;
export const Loading = () => <LoginPage {...props} loading={true} />;

View file

@ -1,30 +1,32 @@
import { AccountErrorCode } from "@dashboard/graphql"; import { AccountErrorCode } from "@dashboard/graphql";
import CardDecorator from "@dashboard/storybook//CardDecorator";
import Decorator from "@dashboard/storybook//Decorator";
import { storiesOf } from "@storybook/react";
import React from "react"; import React from "react";
import { CardDecorator } from "../../../../.storybook/decorators";
import NewPasswordPage from "./NewPasswordPage"; import NewPasswordPage from "./NewPasswordPage";
storiesOf("Authentication / Set up a new password", module) export default {
.addDecorator(CardDecorator) title: "Authentication / Set up a new password",
.addDecorator(Decorator) decorators: [CardDecorator],
.add("default", () => ( };
<NewPasswordPage errors={[]} loading={false} onSubmit={() => undefined} />
)) export const Default = () => (
.add("loading", () => ( <NewPasswordPage errors={[]} loading={false} onSubmit={() => undefined} />
<NewPasswordPage errors={[]} loading={true} onSubmit={() => undefined} /> );
))
.add("too short error", () => ( export const Loading = () => (
<NewPasswordPage <NewPasswordPage errors={[]} loading={true} onSubmit={() => undefined} />
errors={["password"].map(field => ({ );
__typename: "AccountError",
code: AccountErrorCode.PASSWORD_TOO_SHORT, export const TooShortError = () => (
field, <NewPasswordPage
addressType: null, errors={["password"].map(field => ({
message: null, __typename: "AccountError",
}))} code: AccountErrorCode.PASSWORD_TOO_SHORT,
loading={false} field,
onSubmit={() => undefined} addressType: null,
/> message: null,
)); }))}
loading={false}
onSubmit={() => undefined}
/>
);

View file

@ -1,9 +1,7 @@
import CardDecorator from "@dashboard/storybook/CardDecorator";
import Decorator from "@dashboard/storybook/Decorator";
import { formError } from "@dashboard/storybook/formError";
import { storiesOf } from "@storybook/react";
import React from "react"; import React from "react";
import { CardDecorator } from "../../../../.storybook/decorators";
import { formError } from "../../../../.storybook/helpers";
import ResetPasswordPage, { ResetPasswordPageProps } from "./ResetPasswordPage"; import ResetPasswordPage, { ResetPasswordPageProps } from "./ResetPasswordPage";
const props: ResetPasswordPageProps = { const props: ResetPasswordPageProps = {
@ -11,11 +9,16 @@ const props: ResetPasswordPageProps = {
error: undefined, error: undefined,
onSubmit: () => undefined, onSubmit: () => undefined,
}; };
storiesOf("Authentication / Reset password", module)
.addDecorator(CardDecorator) export default {
.addDecorator(Decorator) title: "Authentication / Reset password",
.add("default", () => <ResetPasswordPage {...props} />) decorators: [CardDecorator],
.add("loading", () => <ResetPasswordPage {...props} disabled={true} />) };
.add("error", () => (
<ResetPasswordPage {...props} error={formError("").message} /> export const Default = () => <ResetPasswordPage {...props} />;
));
export const Loading = () => <ResetPasswordPage {...props} disabled={true} />;
export const Error = () => (
<ResetPasswordPage {...props} error={formError("").message} />
);

View file

@ -1,11 +1,13 @@
import CardDecorator from "@dashboard/storybook/CardDecorator";
import Decorator from "@dashboard/storybook/Decorator";
import { storiesOf } from "@storybook/react";
import React from "react"; import React from "react";
import { CardDecorator } from "../../../../.storybook/decorators";
import ResetPasswordSuccessPage from "./ResetPasswordSuccessPage"; import ResetPasswordSuccessPage from "./ResetPasswordSuccessPage";
storiesOf("Authentication / Reset password success", module) export default {
.addDecorator(CardDecorator) title: "Authentication / Reset password success",
.addDecorator(Decorator) decorators: [CardDecorator],
.add("default", () => <ResetPasswordSuccessPage onBack={() => undefined} />); };
export const Default = () => (
<ResetPasswordSuccessPage onBack={() => undefined} />
);

View file

@ -16,7 +16,7 @@ import ResetPassword from "./views/ResetPassword";
import ResetPasswordSuccess from "./views/ResetPasswordSuccess"; import ResetPasswordSuccess from "./views/ResetPasswordSuccess";
const LoginView: React.FC<RouteComponentProps<any>> = () => { const LoginView: React.FC<RouteComponentProps<any>> = () => {
const qs = parseQs(location.search.substr(1)); const qs = parseQs(location.search.substr(1)) as any;
const params: LoginUrlQueryParams = qs; const params: LoginUrlQueryParams = qs;
return <LoginViewComponent params={params} />; return <LoginViewComponent params={params} />;

View file

@ -17,7 +17,9 @@ const NewPassword: React.FC<RouteComponentProps> = ({ location }) => {
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [errors, setErrors] = useState<SetPasswordData["errors"]>([]); const [errors, setErrors] = useState<SetPasswordData["errors"]>([]);
const params: NewPasswordUrlQueryParams = parseQs(location.search.substr(1)); const params: NewPasswordUrlQueryParams = parseQs(
location.search.substr(1),
) as any;
const handleSubmit = async (data: NewPasswordPageFormData) => { const handleSubmit = async (data: NewPasswordPageFormData) => {
setLoading(true); setLoading(true);

View file

@ -1,6 +1,4 @@
import { ProductErrorCode } from "@dashboard/graphql"; import { ProductErrorCode } from "@dashboard/graphql";
import Decorator from "@dashboard/storybook/Decorator";
import { storiesOf } from "@storybook/react";
import React from "react"; import React from "react";
import CategoryCreatePage, { import CategoryCreatePage, {
@ -15,29 +13,33 @@ const createProps: CategoryCreatePageProps = {
saveButtonBarState: "default", saveButtonBarState: "default",
}; };
storiesOf("Categories / Create category", module) export default {
.addDecorator(Decorator) title: "Categories / Create category",
.add("default", () => <CategoryCreatePage {...createProps} />) };
.add("When loading", () => (
<CategoryCreatePage {...createProps} disabled={true} /> export const Default = () => <CategoryCreatePage {...createProps} />;
))
.add("form errors", () => ( export const WhenLoading = () => (
<CategoryCreatePage <CategoryCreatePage {...createProps} disabled={true} />
{...createProps} );
errors={[
{ export const FormErrors = () => (
code: ProductErrorCode.REQUIRED, <CategoryCreatePage
field: "name", {...createProps}
message: "Product field name required", errors={[
}, {
{ code: ProductErrorCode.REQUIRED,
code: ProductErrorCode.REQUIRED, field: "name",
field: "description", message: "Product field name required",
message: "Product field description required", },
}, {
].map(err => ({ code: ProductErrorCode.REQUIRED,
__typename: "ProductError", field: "description",
...err, message: "Product field description required",
}))} },
/> ].map(err => ({
)); __typename: "ProductError",
...err,
}))}
/>
);

View file

@ -7,11 +7,9 @@ import {
sortPageProps, sortPageProps,
tabPageProps, tabPageProps,
} from "@dashboard/fixtures"; } from "@dashboard/fixtures";
import Decorator from "@dashboard/storybook/Decorator";
import { PaginatorContextDecorator } from "@dashboard/storybook/PaginatorContextDecorator";
import { storiesOf } from "@storybook/react";
import React from "react"; import React from "react";
import { PaginatorContextDecorator } from "../../../../.storybook/decorators";
import CategoryListPage, { CategoryTableProps } from "./CategoryListPage"; import CategoryListPage, { CategoryTableProps } from "./CategoryListPage";
const categoryTableProps: CategoryTableProps = { const categoryTableProps: CategoryTableProps = {
@ -28,13 +26,17 @@ const categoryTableProps: CategoryTableProps = {
}, },
}; };
storiesOf("Categories / Category list", module) export default {
.addDecorator(Decorator) title: "Categories / Category list",
.addDecorator(PaginatorContextDecorator) decorators: [PaginatorContextDecorator],
.add("default", () => <CategoryListPage {...categoryTableProps} />) };
.add("loading", () => (
<CategoryListPage {...categoryTableProps} categories={undefined} /> export const Default = () => <CategoryListPage {...categoryTableProps} />;
))
.add("empty", () => ( export const Loading = () => (
<CategoryListPage {...categoryTableProps} categories={[]} /> <CategoryListPage {...categoryTableProps} categories={undefined} />
)); );
export const Empty = () => (
<CategoryListPage {...categoryTableProps} categories={[]} />
);

View file

@ -2,12 +2,10 @@ import placeholderImage from "@assets/images/placeholder255x255.png";
import { category as categoryFixture } from "@dashboard/categories/fixtures"; import { category as categoryFixture } from "@dashboard/categories/fixtures";
import { listActionsProps } from "@dashboard/fixtures"; import { listActionsProps } from "@dashboard/fixtures";
import { ProductErrorCode } from "@dashboard/graphql"; import { ProductErrorCode } from "@dashboard/graphql";
import Decorator from "@dashboard/storybook/Decorator";
import { PaginatorContextDecorator } from "@dashboard/storybook/PaginatorContextDecorator";
import { mapEdgesToItems } from "@dashboard/utils/maps"; import { mapEdgesToItems } from "@dashboard/utils/maps";
import { storiesOf } from "@storybook/react";
import React from "react"; import React from "react";
import { PaginatorContextDecorator } from "../../../../.storybook/decorators";
import CategoryUpdatePage, { import CategoryUpdatePage, {
CategoryPageTab, CategoryPageTab,
CategoryUpdatePageProps, CategoryUpdatePageProps,
@ -35,61 +33,66 @@ const updateProps: Omit<CategoryUpdatePageProps, "classes"> = {
...listActionsProps, ...listActionsProps,
}; };
storiesOf("Categories / Update category", module) export default {
.addDecorator(Decorator) title: "Categories / Update category",
.addDecorator(PaginatorContextDecorator) decorators: [PaginatorContextDecorator],
.add("default", () => <CategoryUpdatePage {...updateProps} />) };
.add("products", () => (
<CategoryUpdatePage export const Default = () => <CategoryUpdatePage {...updateProps} />;
{...updateProps}
currentTab={CategoryPageTab.products} export const Products = () => (
/> <CategoryUpdatePage {...updateProps} currentTab={CategoryPageTab.products} />
)) );
.add("no background", () => (
<CategoryUpdatePage export const NoBackground = () => (
{...updateProps} <CategoryUpdatePage
category={{ {...updateProps}
...category, category={{
backgroundImage: null, ...category,
}} backgroundImage: null,
/> }}
)) />
.add("no subcategories", () => ( );
<CategoryUpdatePage {...updateProps} subcategories={[]} />
)) export const NoSubcategories = () => (
.add("no products", () => ( <CategoryUpdatePage {...updateProps} subcategories={[]} />
<CategoryUpdatePage );
{...updateProps}
products={[]} export const NoProducts = () => (
currentTab={CategoryPageTab.products} <CategoryUpdatePage
/> {...updateProps}
)) products={[]}
.add("loading", () => ( currentTab={CategoryPageTab.products}
<CategoryUpdatePage />
{...updateProps} );
subcategories={undefined}
disabled={true} export const Loading = () => (
products={undefined} <CategoryUpdatePage
category={undefined} {...updateProps}
/> subcategories={undefined}
)) disabled={true}
.add("form errors", () => ( products={undefined}
<CategoryUpdatePage category={undefined}
{...updateProps} />
errors={[ );
{
code: ProductErrorCode.REQUIRED, export const FormErrors = () => (
field: "name", <CategoryUpdatePage
message: "Product field name required", {...updateProps}
}, errors={[
{ {
code: ProductErrorCode.REQUIRED, code: ProductErrorCode.REQUIRED,
field: "description", field: "name",
message: "Product field description required", message: "Product field name required",
}, },
].map(err => ({ {
__typename: "ProductError", code: ProductErrorCode.REQUIRED,
...err, field: "description",
}))} message: "Product field description required",
/> },
)); ].map(err => ({
__typename: "ProductError",
...err,
}))}
/>
);

View file

@ -21,9 +21,9 @@ import CategoryListComponent from "./views/CategoryList";
interface CategoryDetailsRouteParams { interface CategoryDetailsRouteParams {
id: string; id: string;
} }
const CategoryDetails: React.FC<RouteComponentProps< const CategoryDetails: React.FC<
CategoryDetailsRouteParams RouteComponentProps<CategoryDetailsRouteParams>
>> = ({ location, match }) => { > = ({ location, match }) => {
const qs = parseQs(location.search.substr(1)); const qs = parseQs(location.search.substr(1));
const params: CategoryUrlQueryParams = qs; const params: CategoryUrlQueryParams = qs;
@ -38,16 +38,16 @@ const CategoryDetails: React.FC<RouteComponentProps<
interface CategoryCreateRouteParams { interface CategoryCreateRouteParams {
id: string; id: string;
} }
const CategoryCreate: React.FC<RouteComponentProps< const CategoryCreate: React.FC<
CategoryCreateRouteParams RouteComponentProps<CategoryCreateRouteParams>
>> = ({ match }) => ( > = ({ match }) => (
<CategoryCreateView <CategoryCreateView
parentId={match.params.id ? decodeURIComponent(match.params.id) : undefined} parentId={match.params.id ? decodeURIComponent(match.params.id) : undefined}
/> />
); );
const CategoryList: React.FC<RouteComponentProps<{}>> = ({ location }) => { const CategoryList: React.FC<RouteComponentProps<{}>> = ({ location }) => {
const qs = parseQs(location.search.substr(1)); const qs = parseQs(location.search.substr(1)) as any;
const params: CategoryListUrlQueryParams = { const params: CategoryListUrlQueryParams = {
...asSortParams(qs, CategoryListUrlSortField), ...asSortParams(qs, CategoryListUrlSortField),
}; };

View file

@ -29,7 +29,7 @@ const ChannelDetails: React.FC<RouteComponentProps<any>> = ({ match }) => {
}; };
const ChannelsList: React.FC<RouteComponentProps> = ({ location }) => { const ChannelsList: React.FC<RouteComponentProps> = ({ location }) => {
const qs = parseQs(location.search.substr(1)); const qs = parseQs(location.search.substr(1)) as any;
const params: ChannelsListUrlQueryParams = asSortParams( const params: ChannelsListUrlQueryParams = asSortParams(
qs, qs,
ChannelsListUrlSortField, ChannelsListUrlSortField,

View file

@ -1,8 +1,6 @@
import { channel, channelCreateErrors } from "@dashboard/channels/fixtures"; import { channel, channelCreateErrors } from "@dashboard/channels/fixtures";
import { countries } from "@dashboard/fixtures"; import { countries } from "@dashboard/fixtures";
import { ChannelErrorFragment } from "@dashboard/graphql"; import { ChannelErrorFragment } from "@dashboard/graphql";
import Decorator from "@dashboard/storybook/Decorator";
import { storiesOf } from "@storybook/react";
import React from "react"; import React from "react";
import ChannelDetailsPage, { import ChannelDetailsPage, {
@ -69,21 +67,26 @@ const props: ChannelDetailsPageProps<ChannelErrorFragment[]> = {
}, },
}; };
storiesOf("Channels / Channel details", module) export default {
.addDecorator(Decorator) title: "Channels / Channel details",
.add("default", () => <ChannelDetailsPage {...props} />) };
.add("disabled", () => <ChannelDetailsPage {...props} disabled={true} />)
.add("loading", () => ( export const Default = () => <ChannelDetailsPage {...props} />;
<ChannelDetailsPage {...props} saveButtonBarState={"loading"} />
)) export const Disabled = () => <ChannelDetailsPage {...props} disabled={true} />;
.add("with data", () => <ChannelDetailsPage {...props} channel={channel} />)
.add("without editable currency code", () => ( export const Loading = () => (
<ChannelDetailsPage <ChannelDetailsPage {...props} saveButtonBarState={"loading"} />
{...props} );
currencyCodes={undefined}
channel={channel} export const WithData = () => (
/> <ChannelDetailsPage {...props} channel={channel} />
)) );
.add("with errors", () => (
<ChannelDetailsPage {...props} errors={channelCreateErrors} /> export const WithoutEditableCurrencyCode = () => (
)); <ChannelDetailsPage {...props} currencyCodes={undefined} channel={channel} />
);
export const WithErrors = () => (
<ChannelDetailsPage {...props} errors={channelCreateErrors} />
);

View file

@ -1,7 +1,5 @@
import { channelsList } from "@dashboard/channels/fixtures"; import { channelsList } from "@dashboard/channels/fixtures";
import { limits, limitsReached } from "@dashboard/fixtures"; import { limits, limitsReached } from "@dashboard/fixtures";
import Decorator from "@dashboard/storybook/Decorator";
import { storiesOf } from "@storybook/react";
import React from "react"; import React from "react";
import ChannelsListPage, { ChannelsListPageProps } from "./ChannelsListPage"; import ChannelsListPage, { ChannelsListPageProps } from "./ChannelsListPage";
@ -12,11 +10,18 @@ const props: ChannelsListPageProps = {
onRemove: () => undefined, onRemove: () => undefined,
}; };
storiesOf("Channels / Channels list", module) export default {
.addDecorator(Decorator) title: "Channels / Channels list",
.add("default", () => <ChannelsListPage {...props} />) };
.add("empty", () => <ChannelsListPage {...props} channelsList={[]} />)
.add("no limits", () => <ChannelsListPage {...props} limits={undefined} />) export const Default = () => <ChannelsListPage {...props} />;
.add("limits reached", () => (
<ChannelsListPage {...props} limits={limitsReached} /> export const Empty = () => <ChannelsListPage {...props} channelsList={[]} />;
));
export const NoLimits = () => (
<ChannelsListPage {...props} limits={undefined} />
);
export const LimitsReached = () => (
<ChannelsListPage {...props} limits={limitsReached} />
);

View file

@ -1,8 +1,6 @@
import { channelsList } from "@dashboard/channels/fixtures"; import { channelsList } from "@dashboard/channels/fixtures";
import { createCollectionChannels } from "@dashboard/channels/utils"; import { createCollectionChannels } from "@dashboard/channels/utils";
import { CollectionErrorCode } from "@dashboard/graphql"; import { CollectionErrorCode } from "@dashboard/graphql";
import Decorator from "@dashboard/storybook/Decorator";
import { storiesOf } from "@storybook/react";
import React from "react"; import React from "react";
import CollectionCreatePage, { import CollectionCreatePage, {
@ -23,27 +21,33 @@ const props: Omit<CollectionCreatePageProps, "classes"> = {
saveButtonBarState: "default", saveButtonBarState: "default",
}; };
storiesOf("Collections / Create collection", module) export default {
.addDecorator(Decorator) title: "Collections / Create collection",
.add("default", () => <CollectionCreatePage {...props} />) };
.add("loading", () => <CollectionCreatePage {...props} disabled={true} />)
.add("form errors", () => ( export const Default = () => <CollectionCreatePage {...props} />;
<CollectionCreatePage
{...props} export const Loading = () => (
errors={[ <CollectionCreatePage {...props} disabled={true} />
{ );
code: CollectionErrorCode.REQUIRED,
field: "name", export const FormErrors = () => (
message: "Collection field name required", <CollectionCreatePage
}, {...props}
{ errors={[
code: CollectionErrorCode.REQUIRED, {
field: "description", code: CollectionErrorCode.REQUIRED,
message: "Collection field description required", field: "name",
}, message: "Collection field name required",
].map(err => ({ },
__typename: "CollectionError", {
...err, code: CollectionErrorCode.REQUIRED,
}))} field: "description",
/> message: "Collection field description required",
)); },
].map(err => ({
__typename: "CollectionError",
...err,
}))}
/>
);

View file

@ -4,11 +4,9 @@ import { createCollectionChannelsData } from "@dashboard/channels/utils";
import { collection as collectionFixture } from "@dashboard/collections/fixtures"; import { collection as collectionFixture } from "@dashboard/collections/fixtures";
import { listActionsProps, pageListProps } from "@dashboard/fixtures"; import { listActionsProps, pageListProps } from "@dashboard/fixtures";
import { CollectionErrorCode } from "@dashboard/graphql"; import { CollectionErrorCode } from "@dashboard/graphql";
import Decorator from "@dashboard/storybook/Decorator";
import { PaginatorContextDecorator } from "@dashboard/storybook/PaginatorContextDecorator";
import { storiesOf } from "@storybook/react";
import React from "react"; import React from "react";
import { PaginatorContextDecorator } from "../../../../.storybook/decorators";
import CollectionDetailsPage, { import CollectionDetailsPage, {
CollectionDetailsPageProps, CollectionDetailsPageProps,
} from "./CollectionDetailsPage"; } from "./CollectionDetailsPage";
@ -39,42 +37,47 @@ const props: Omit<CollectionDetailsPageProps, "classes"> = {
selectedChannelId: "123", selectedChannelId: "123",
}; };
storiesOf("Collections / Collection detailsCollection details", module) export default {
.addDecorator(Decorator) title: "Collections / Collection detailsCollection details",
.addDecorator(PaginatorContextDecorator) decorators: [PaginatorContextDecorator],
.add("default", () => <CollectionDetailsPage {...props} />) };
.add("loading", () => (
<CollectionDetailsPage {...props} collection={undefined} disabled={true} /> export const Default = () => <CollectionDetailsPage {...props} />;
))
.add("form errors", () => ( export const Loading = () => (
<CollectionDetailsPage <CollectionDetailsPage {...props} collection={undefined} disabled={true} />
{...props} );
errors={[
{ export const FormErrors = () => (
code: CollectionErrorCode.REQUIRED, <CollectionDetailsPage
field: "name", {...props}
message: "Collection field name required", errors={[
}, {
{ code: CollectionErrorCode.REQUIRED,
code: CollectionErrorCode.REQUIRED, field: "name",
field: "description", message: "Collection field name required",
message: "Collection field description required", },
}, {
].map(err => ({ code: CollectionErrorCode.REQUIRED,
__typename: "CollectionError", field: "description",
...err, message: "Collection field description required",
}))} },
/> ].map(err => ({
)) __typename: "CollectionError",
.add("no products", () => ( ...err,
<CollectionDetailsPage }))}
{...props} />
collection={{ );
...collection,
products: { export const NoProducts = () => (
...collection.products, <CollectionDetailsPage
edges: [], {...props}
}, collection={{
}} ...collection,
/> products: {
)); ...collection.products,
edges: [],
},
}}
/>
);

View file

@ -1,9 +1,7 @@
import { CollectionListUrlSortField } from "@dashboard/collections/urls"; import { CollectionListUrlSortField } from "@dashboard/collections/urls";
import Decorator from "@dashboard/storybook/Decorator";
import { PaginatorContextDecorator } from "@dashboard/storybook/PaginatorContextDecorator";
import { storiesOf } from "@storybook/react";
import React from "react"; import React from "react";
import { PaginatorContextDecorator } from "../../../../.storybook/decorators";
import CollectionListPage, { import CollectionListPage, {
CollectionListPageProps, CollectionListPageProps,
} from "../../../collections/components/CollectionListPage"; } from "../../../collections/components/CollectionListPage";
@ -34,11 +32,15 @@ const props: CollectionListPageProps = {
filterOpts: collectionListFilterOpts, filterOpts: collectionListFilterOpts,
}; };
storiesOf("Collections / Collection list", module) export default {
.addDecorator(Decorator) title: "Collections / Collection list",
.addDecorator(PaginatorContextDecorator) decorators: [PaginatorContextDecorator],
.add("default", () => <CollectionListPage {...props} />) };
.add("loading", () => (
<CollectionListPage {...props} collections={undefined} disabled={true} /> export const Default = () => <CollectionListPage {...props} />;
))
.add("no data", () => <CollectionListPage {...props} collections={[]} />); export const Loading = () => (
<CollectionListPage {...props} collections={undefined} disabled={true} />
);
export const NoData = () => <CollectionListPage {...props} collections={[]} />;

View file

@ -20,7 +20,7 @@ import CollectionDetailsView from "./views/CollectionDetails";
import CollectionListView from "./views/CollectionList"; import CollectionListView from "./views/CollectionList";
const CollectionList: React.FC<RouteComponentProps<{}>> = ({ location }) => { const CollectionList: React.FC<RouteComponentProps<{}>> = ({ location }) => {
const qs = parseQs(location.search.substr(1)); const qs = parseQs(location.search.substr(1)) as any;
const params: CollectionListUrlQueryParams = asSortParams( const params: CollectionListUrlQueryParams = asSortParams(
qs, qs,
CollectionListUrlSortField, CollectionListUrlSortField,
@ -31,9 +31,9 @@ const CollectionList: React.FC<RouteComponentProps<{}>> = ({ location }) => {
interface CollectionDetailsRouteProps { interface CollectionDetailsRouteProps {
id: string; id: string;
} }
const CollectionDetails: React.FC<RouteComponentProps< const CollectionDetails: React.FC<
CollectionDetailsRouteProps RouteComponentProps<CollectionDetailsRouteProps>
>> = ({ location, match }) => { > = ({ location, match }) => {
const qs = parseQs(location.search.substr(1)); const qs = parseQs(location.search.substr(1));
const params: CollectionUrlQueryParams = qs; const params: CollectionUrlQueryParams = qs;
return ( return (

View file

@ -3,8 +3,6 @@ import {
AppStateContextType, AppStateContextType,
} from "@dashboard/containers/AppState"; } from "@dashboard/containers/AppState";
import { initialAppState } from "@dashboard/containers/AppState/state"; import { initialAppState } from "@dashboard/containers/AppState/state";
import Decorator from "@dashboard/storybook/Decorator";
import { storiesOf } from "@storybook/react";
import React from "react"; import React from "react";
import ErrorPage, { ErrorPageProps } from "./ErrorPage"; import ErrorPage, { ErrorPageProps } from "./ErrorPage";
@ -29,15 +27,18 @@ const props: Omit<ErrorPageProps, "classes"> = {
onRefresh: () => undefined, onRefresh: () => undefined,
}; };
storiesOf("Error / Error page", module) export default {
.addDecorator(Decorator) title: "Error / Error page",
.add("default", () => ( };
<AppStateContext.Provider value={initialAppStateFixture}>
<ErrorPage {...props} /> export const Default = () => (
</AppStateContext.Provider> <AppStateContext.Provider value={initialAppStateFixture}>
)) <ErrorPage {...props} />
.add("with error id", () => ( </AppStateContext.Provider>
<AppStateContext.Provider value={errorAppStateFixture}> );
<ErrorPage {...props} />
</AppStateContext.Provider> export const WithErrorId = () => (
)); <AppStateContext.Provider value={errorAppStateFixture}>
<ErrorPage {...props} />
</AppStateContext.Provider>
);

View file

@ -1,9 +1,9 @@
import Decorator from "@dashboard/storybook/Decorator";
import { storiesOf } from "@storybook/react";
import React from "react"; import React from "react";
import NotFoundPage from "./NotFoundPage"; import NotFoundPage from "./NotFoundPage";
storiesOf("Error / Not found", module) export default {
.addDecorator(Decorator) title: "Error / Not found",
.add("default", () => <NotFoundPage onBack={() => undefined} />); };
export const Default = () => <NotFoundPage onBack={() => undefined} />;

View file

@ -1,13 +1,15 @@
import { createConfigurationMenu } from "@dashboard/configuration"; import { createConfigurationMenu } from "@dashboard/configuration";
import { UserFragment } from "@dashboard/graphql"; import { UserFragment } from "@dashboard/graphql";
import { staffMember } from "@dashboard/staff/fixtures"; import { staffMember } from "@dashboard/staff/fixtures";
import Decorator from "@dashboard/storybook/Decorator";
import { storiesOf } from "@storybook/react";
import React from "react"; import React from "react";
import { useIntl } from "react-intl"; import { useIntl } from "react-intl";
import { ConfigurationPage } from "./ConfigurationPage"; import { ConfigurationPage } from "./ConfigurationPage";
export default {
title: "Configuration / Configuration",
};
const user = { const user = {
__typename: staffMember.__typename, __typename: staffMember.__typename,
avatar: { avatar: {
@ -40,14 +42,13 @@ const Story: React.FC<{ user: UserFragment }> = ({ user }) => {
); );
}; };
storiesOf("Configuration", module) export const Default = () => <Story user={user} />;
.addDecorator(Decorator)
.add("default", () => <Story user={user} />) export const PartialAccess = () => (
.add("partial access", () => ( <Story
<Story user={{
user={{ ...user,
...user, userPermissions: user.userPermissions.slice(2, 6),
userPermissions: user.userPermissions.slice(2, 6), }}
}} />
/> );
));

View file

@ -1,6 +1,4 @@
import { WebhookErrorCode } from "@dashboard/graphql"; import { WebhookErrorCode } from "@dashboard/graphql";
import Decorator from "@dashboard/storybook/Decorator";
import { storiesOf } from "@storybook/react";
import React from "react"; import React from "react";
import { webhook } from "../../fixtures"; import { webhook } from "../../fixtures";
@ -18,21 +16,29 @@ const props: WebhookDetailsPageProps = {
webhook, webhook,
availableEvents: [], availableEvents: [],
}; };
storiesOf("Apps / Webhooks / Webhook details", module)
.addDecorator(Decorator) export default {
.add("default", () => <WebhookDetailsPage {...props} />) title: "Apps / Webhooks / Webhook details",
.add("undefined", () => <WebhookDetailsPage {...props} webhook={undefined} />) };
.add("loading", () => (
<WebhookDetailsPage {...props} webhook={undefined} disabled={true} /> export const Default = () => <WebhookDetailsPage {...props} />;
))
.add("form errors", () => ( export const Undefined = () => (
<WebhookDetailsPage <WebhookDetailsPage {...props} webhook={undefined} />
{...props} );
errors={["name", "targetUrl", "secretKey", null].map(field => ({
__typename: "WebhookError", export const Loading = () => (
code: WebhookErrorCode.INVALID, <WebhookDetailsPage {...props} webhook={undefined} disabled={true} />
field, );
message: "Webhook invalid",
}))} export const FormErrors = () => (
/> <WebhookDetailsPage
)); {...props}
errors={["name", "targetUrl", "secretKey", null].map(field => ({
__typename: "WebhookError",
code: WebhookErrorCode.INVALID,
field,
message: "Webhook invalid",
}))}
/>
);

View file

@ -1,5 +1,3 @@
import Decorator from "@dashboard/storybook/Decorator";
import { storiesOf } from "@storybook/react";
import React from "react"; import React from "react";
import { customer } from "../../fixtures"; import { customer } from "../../fixtures";
@ -14,15 +12,19 @@ const props: CustomerAddressListPageProps = {
onSetAsDefault: () => undefined, onSetAsDefault: () => undefined,
}; };
storiesOf("Customers / Address Book", module) export default {
.addDecorator(Decorator) title: "Customers / Address Book",
.add("default", () => <CustomerAddressListPage {...props} />) };
.add("loading", () => (
<CustomerAddressListPage {...props} customer={undefined} disabled={true} /> export const Default = () => <CustomerAddressListPage {...props} />;
))
.add("no data", () => ( export const Loading = () => (
<CustomerAddressListPage <CustomerAddressListPage {...props} customer={undefined} disabled={true} />
{...props} );
customer={{ ...customer, addresses: [] }}
/> export const NoData = () => (
)); <CustomerAddressListPage
{...props}
customer={{ ...customer, addresses: [] }}
/>
);

View file

@ -1,6 +1,4 @@
import { AccountErrorCode } from "@dashboard/graphql"; import { AccountErrorCode } from "@dashboard/graphql";
import Decorator from "@dashboard/storybook/Decorator";
import { storiesOf } from "@storybook/react";
import React from "react"; import React from "react";
import CustomerCreatePage, { import CustomerCreatePage, {
@ -19,14 +17,19 @@ const props: Omit<CustomerCreatePageProps, "classes"> = {
saveButtonBar: "default", saveButtonBar: "default",
}; };
storiesOf("Customers / Create customer", module) export default {
.addDecorator(Decorator) title: "Customers / Create customer",
.add("default", () => <CustomerCreatePage {...props} />) };
.add("loading", () => <CustomerCreatePage {...props} disabled={true} />)
.add("form errors", () => ( export const Default = () => <CustomerCreatePage {...props} />;
<CustomerCreatePage
{...props} export const Loading = () => <CustomerCreatePage {...props} disabled={true} />;
errors={([
export const FormErrors = () => (
<CustomerCreatePage
{...props}
errors={(
[
"city", "city",
"cityArea", "cityArea",
"companyName", "companyName",
@ -40,12 +43,13 @@ storiesOf("Customers / Create customer", module)
"postalCode", "postalCode",
"streetAddress1", "streetAddress1",
"streetAddress2", "streetAddress2",
] as Array<keyof CustomerCreatePageFormData>).map(field => ({ ] as Array<keyof CustomerCreatePageFormData>
__typename: "AccountError", ).map(field => ({
code: AccountErrorCode.INVALID, __typename: "AccountError",
field, code: AccountErrorCode.INVALID,
addressType: null, field,
message: "Account invalid error", addressType: null,
}))} message: "Account invalid error",
/> }))}
)); />
);

View file

@ -1,9 +1,7 @@
import { AccountErrorCode } from "@dashboard/graphql"; import { AccountErrorCode } from "@dashboard/graphql";
import Decorator from "@dashboard/storybook/Decorator";
import { MockedUserProvider } from "@dashboard/storybook/MockedUserProvider";
import { storiesOf } from "@storybook/react";
import React from "react"; import React from "react";
import { MockedUserProvider } from "../../../../.storybook/helpers";
import { customer } from "../../fixtures"; import { customer } from "../../fixtures";
import CustomerDetailsPageComponent, { import CustomerDetailsPageComponent, {
CustomerDetailsPageProps, CustomerDetailsPageProps,
@ -32,84 +30,96 @@ const CustomerDetailsPage = props => (
</MockedUserProvider> </MockedUserProvider>
); );
storiesOf("Customers / Customer details", module) export default {
.addDecorator(Decorator) title: "Customers / Customer details",
.add("default", () => <CustomerDetailsPage {...props} />) };
.add("loading", () => (
<CustomerDetailsPage {...props} customer={undefined} disabled={true} /> export const Default = () => <CustomerDetailsPage {...props} />;
))
.add("form errors", () => ( export const Loading = () => (
<CustomerDetailsPage <CustomerDetailsPage {...props} customer={undefined} disabled={true} />
{...props} );
errors={(["email", "firstName", "lastName"] as Array<
export const FormErrors = () => (
<CustomerDetailsPage
{...props}
errors={(
["email", "firstName", "lastName"] as Array<
keyof CustomerDetailsPageErrors keyof CustomerDetailsPageErrors
>).map(field => ({ >
__typename: "AccountError", ).map(field => ({
code: AccountErrorCode.INVALID, __typename: "AccountError",
field, code: AccountErrorCode.INVALID,
addressType: null, field,
message: "Account invalid", addressType: null,
}))} message: "Account invalid",
/> }))}
)) />
.add("different addresses", () => ( );
<CustomerDetailsPage
{...props} export const DifferentAddresses = () => (
customer={{ <CustomerDetailsPage
...customer, {...props}
defaultBillingAddress: { customer={{
...customer.defaultBillingAddress, ...customer,
id: "AvSduf72=", defaultBillingAddress: {
}, ...customer.defaultBillingAddress,
}} id: "AvSduf72=",
/> },
)) }}
.add("never logged", () => ( />
<CustomerDetailsPage );
{...props}
customer={{ export const NeverLogged = () => (
...customer, <CustomerDetailsPage
lastLogin: null, {...props}
}} customer={{
/> ...customer,
)) lastLogin: null,
.add("never placed order", () => ( }}
<CustomerDetailsPage />
{...props} );
customer={{
...customer, export const NeverPlacedOrder = () => (
lastPlacedOrder: { <CustomerDetailsPage
...customer.lastPlacedOrder, {...props}
edges: [], customer={{
}, ...customer,
}} lastPlacedOrder: {
/> ...customer.lastPlacedOrder,
)) edges: [],
.add("no default billing address", () => ( },
<CustomerDetailsPage }}
{...props} />
customer={{ );
...customer,
defaultBillingAddress: null, export const NoDefaultBillingAddress = () => (
}} <CustomerDetailsPage
/> {...props}
)) customer={{
.add("no default shipping address", () => ( ...customer,
<CustomerDetailsPage defaultBillingAddress: null,
{...props} }}
customer={{ />
...customer, );
defaultShippingAddress: null,
}} export const NoDefaultShippingAddress = () => (
/> <CustomerDetailsPage
)) {...props}
.add("no address at all", () => ( customer={{
<CustomerDetailsPage ...customer,
{...props} defaultShippingAddress: null,
customer={{ }}
...customer, />
defaultBillingAddress: null, );
defaultShippingAddress: null,
}} export const NoAddressAtAll = () => (
/> <CustomerDetailsPage
)); {...props}
customer={{
...customer,
defaultBillingAddress: null,
defaultShippingAddress: null,
}}
/>
);

View file

@ -6,12 +6,10 @@ import {
sortPageProps, sortPageProps,
tabPageProps, tabPageProps,
} from "@dashboard/fixtures"; } from "@dashboard/fixtures";
import Decorator from "@dashboard/storybook/Decorator";
import { MockedUserProvider } from "@dashboard/storybook/MockedUserProvider";
import { PaginatorContextDecorator } from "@dashboard/storybook/PaginatorContextDecorator";
import { storiesOf } from "@storybook/react";
import React from "react"; import React from "react";
import { PaginatorContextDecorator } from "../../../../.storybook/decorators";
import { MockedUserProvider } from "../../../../.storybook/helpers";
import { customerList } from "../../fixtures"; import { customerList } from "../../fixtures";
import { CustomerListUrlSortField } from "../../urls"; import { CustomerListUrlSortField } from "../../urls";
import CustomerListPageComponent, { import CustomerListPageComponent, {
@ -55,11 +53,15 @@ const CustomerListPage = props => (
</MockedUserProvider> </MockedUserProvider>
); );
storiesOf("Customers / Customer list", module) export default {
.addDecorator(Decorator) title: "Customers / Customer list",
.addDecorator(PaginatorContextDecorator) decorators: [PaginatorContextDecorator],
.add("default", () => <CustomerListPage {...props} />) };
.add("loading", () => (
<CustomerListPage {...props} disabled={true} customers={undefined} /> export const Default = () => <CustomerListPage {...props} />;
))
.add("no data", () => <CustomerListPage {...props} customers={[]} />); export const Loading = () => (
<CustomerListPage {...props} disabled={true} customers={undefined} />
);
export const NoData = () => <CustomerListPage {...props} customers={[]} />;

View file

@ -22,7 +22,7 @@ import CustomerDetailsViewComponent from "./views/CustomerDetails";
import CustomerListViewComponent from "./views/CustomerList"; import CustomerListViewComponent from "./views/CustomerList";
const CustomerListView: React.FC<RouteComponentProps<{}>> = ({ location }) => { const CustomerListView: React.FC<RouteComponentProps<{}>> = ({ location }) => {
const qs = parseQs(location.search.substr(1)); const qs = parseQs(location.search.substr(1)) as any;
const params: CustomerListUrlQueryParams = asSortParams( const params: CustomerListUrlQueryParams = asSortParams(
qs, qs,
CustomerListUrlSortField, CustomerListUrlSortField,
@ -34,9 +34,9 @@ const CustomerListView: React.FC<RouteComponentProps<{}>> = ({ location }) => {
interface CustomerDetailsRouteParams { interface CustomerDetailsRouteParams {
id: string; id: string;
} }
const CustomerDetailsView: React.FC<RouteComponentProps< const CustomerDetailsView: React.FC<
CustomerDetailsRouteParams RouteComponentProps<CustomerDetailsRouteParams>
>> = ({ location, match }) => { > = ({ location, match }) => {
const qs = parseQs(location.search.substr(1)); const qs = parseQs(location.search.substr(1));
const params: CustomerUrlQueryParams = qs; const params: CustomerUrlQueryParams = qs;
@ -51,9 +51,9 @@ const CustomerDetailsView: React.FC<RouteComponentProps<
interface CustomerAddressesRouteParams { interface CustomerAddressesRouteParams {
id: string; id: string;
} }
const CustomerAddressesView: React.FC<RouteComponentProps< const CustomerAddressesView: React.FC<
CustomerAddressesRouteParams RouteComponentProps<CustomerAddressesRouteParams>
>> = ({ match }) => { > = ({ match }) => {
const qs = parseQs(location.search.substr(1)); const qs = parseQs(location.search.substr(1));
const params: CustomerAddressesUrlQueryParams = qs; const params: CustomerAddressesUrlQueryParams = qs;

View file

@ -1,8 +1,6 @@
import { channelsList } from "@dashboard/channels/fixtures"; import { channelsList } from "@dashboard/channels/fixtures";
import { createSaleChannels } from "@dashboard/channels/utils"; import { createSaleChannels } from "@dashboard/channels/utils";
import { DiscountErrorCode } from "@dashboard/graphql"; import { DiscountErrorCode } from "@dashboard/graphql";
import Decorator from "@dashboard/storybook/Decorator";
import { storiesOf } from "@storybook/react";
import React from "react"; import React from "react";
import SaleCreatePage, { SaleCreatePageProps } from "./SaleCreatePage"; import SaleCreatePage, { SaleCreatePageProps } from "./SaleCreatePage";
@ -21,19 +19,23 @@ const props: SaleCreatePageProps = {
saveButtonBarState: "default", saveButtonBarState: "default",
}; };
storiesOf("Discounts / Sale create", module) export default {
.addDecorator(Decorator) title: "Discounts / Sale create",
.add("default", () => <SaleCreatePage {...props} />) };
.add("loading", () => <SaleCreatePage {...props} disabled={true} />)
.add("form errors", () => ( export const Default = () => <SaleCreatePage {...props} />;
<SaleCreatePage
{...props} export const Loading = () => <SaleCreatePage {...props} disabled={true} />;
errors={["name", "startDate", "endDate", "value"].map(field => ({
__typename: "DiscountError", export const FormErrors = () => (
channels: [], <SaleCreatePage
code: DiscountErrorCode.INVALID, {...props}
field, errors={["name", "startDate", "endDate", "value"].map(field => ({
message: "Discount invalid", __typename: "DiscountError",
}))} channels: [],
/> code: DiscountErrorCode.INVALID,
)); field,
message: "Discount invalid",
}))}
/>
);

View file

@ -3,11 +3,9 @@ import { createSaleChannels } from "@dashboard/channels/utils";
import { sale } from "@dashboard/discounts/fixtures"; import { sale } from "@dashboard/discounts/fixtures";
import { listActionsProps } from "@dashboard/fixtures"; import { listActionsProps } from "@dashboard/fixtures";
import { DiscountErrorCode } from "@dashboard/graphql"; import { DiscountErrorCode } from "@dashboard/graphql";
import Decorator from "@dashboard/storybook/Decorator";
import { PaginatorContextDecorator } from "@dashboard/storybook/PaginatorContextDecorator";
import { storiesOf } from "@storybook/react";
import React from "react"; import React from "react";
import { PaginatorContextDecorator } from "../../../../.storybook/decorators";
import SaleDetailsPage, { import SaleDetailsPage, {
SaleDetailsPageProps, SaleDetailsPageProps,
SaleDetailsPageTab, SaleDetailsPageTab,
@ -50,28 +48,34 @@ const props: SaleDetailsPageProps = {
...listActionsProps, ...listActionsProps,
}; };
storiesOf(" Discounts / Sale details", module) export default {
.addDecorator(Decorator) title: " Discounts / Sale details",
.addDecorator(PaginatorContextDecorator) decorators: [PaginatorContextDecorator],
.add("default", () => <SaleDetailsPage {...props} />) };
.add("loading", () => (
<SaleDetailsPage {...props} sale={undefined} disabled={true} /> export const Default = () => <SaleDetailsPage {...props} />;
))
.add("form errors", () => ( export const Loading = () => (
<SaleDetailsPage <SaleDetailsPage {...props} sale={undefined} disabled={true} />
{...props} );
errors={["name", "startDate", "endDate", "value"].map(field => ({
__typename: "DiscountError", export const FormErrors = () => (
channels: [], <SaleDetailsPage
code: DiscountErrorCode.INVALID, {...props}
field, errors={["name", "startDate", "endDate", "value"].map(field => ({
message: "Discount invalid", __typename: "DiscountError",
}))} channels: [],
/> code: DiscountErrorCode.INVALID,
)) field,
.add("collections", () => ( message: "Discount invalid",
<SaleDetailsPage {...props} activeTab={SaleDetailsPageTab.collections} /> }))}
)) />
.add("products", () => ( );
<SaleDetailsPage {...props} activeTab={SaleDetailsPageTab.products} />
)); export const Collections = () => (
<SaleDetailsPage {...props} activeTab={SaleDetailsPageTab.collections} />
);
export const Products = () => (
<SaleDetailsPage {...props} activeTab={SaleDetailsPageTab.products} />
);

View file

@ -8,11 +8,9 @@ import {
tabPageProps, tabPageProps,
} from "@dashboard/fixtures"; } from "@dashboard/fixtures";
import { DiscountStatusEnum, DiscountValueTypeEnum } from "@dashboard/graphql"; import { DiscountStatusEnum, DiscountValueTypeEnum } from "@dashboard/graphql";
import Decorator from "@dashboard/storybook/Decorator";
import { PaginatorContextDecorator } from "@dashboard/storybook/PaginatorContextDecorator";
import { storiesOf } from "@storybook/react";
import React from "react"; import React from "react";
import { PaginatorContextDecorator } from "../../../../.storybook/decorators";
import SaleListPage, { SaleListPageProps } from "./SaleListPage"; import SaleListPage, { SaleListPageProps } from "./SaleListPage";
const props: SaleListPageProps = { const props: SaleListPageProps = {
@ -56,16 +54,21 @@ const props: SaleListPageProps = {
}, },
}; };
storiesOf("Discounts / Sale list", module) export default {
.addDecorator(Decorator) title: "Discounts / Sale list",
.addDecorator(PaginatorContextDecorator) decorators: [PaginatorContextDecorator],
.add("default", () => <SaleListPage {...props} />) };
.add("loading", () => <SaleListPage {...props} sales={undefined} />)
.add("no data", () => <SaleListPage {...props} sales={[]} />) export const Default = () => <SaleListPage {...props} />;
.add("no channels", () => (
<SaleListPage export const Loading = () => <SaleListPage {...props} sales={undefined} />;
{...props}
sales={saleList.map(sale => ({ ...sale, channelListings: [] }))} export const NoData = () => <SaleListPage {...props} sales={[]} />;
selectedChannelId=""
/> export const NoChannels = () => (
)); <SaleListPage
{...props}
sales={saleList.map(sale => ({ ...sale, channelListings: [] }))}
selectedChannelId=""
/>
);

View file

@ -1,8 +1,6 @@
import { channelsList } from "@dashboard/channels/fixtures"; import { channelsList } from "@dashboard/channels/fixtures";
import { createVoucherChannels } from "@dashboard/channels/utils"; import { createVoucherChannels } from "@dashboard/channels/utils";
import { DiscountErrorCode } from "@dashboard/graphql"; import { DiscountErrorCode } from "@dashboard/graphql";
import Decorator from "@dashboard/storybook/Decorator";
import { storiesOf } from "@storybook/react";
import React from "react"; import React from "react";
import VoucherCreatePage, { import VoucherCreatePage, {
@ -23,13 +21,17 @@ const props: VoucherCreatePageProps = {
saveButtonBarState: "default", saveButtonBarState: "default",
}; };
storiesOf("Discounts / Voucher create", module) export default {
.addDecorator(Decorator) title: "Discounts / Voucher create",
.add("default", () => <VoucherCreatePage {...props} />) };
.add("form errors", () => (
<VoucherCreatePage export const Default = () => <VoucherCreatePage {...props} />;
{...props}
errors={([ export const FormErrors = () => (
<VoucherCreatePage
{...props}
errors={(
[
"applyOncePerOrder", "applyOncePerOrder",
"code", "code",
"discountType", "discountType",
@ -40,12 +42,13 @@ storiesOf("Discounts / Voucher create", module)
"type", "type",
"usageLimit", "usageLimit",
"value", "value",
] as Array<keyof FormData>).map(field => ({ ] as Array<keyof FormData>
__typename: "DiscountError", ).map(field => ({
channels: [], __typename: "DiscountError",
code: DiscountErrorCode.INVALID, channels: [],
field, code: DiscountErrorCode.INVALID,
message: "Discount invalid", field,
}))} message: "Discount invalid",
/> }))}
)); />
);

View file

@ -2,11 +2,9 @@ import { channelsList } from "@dashboard/channels/fixtures";
import { createChannelsDataWithDiscountPrice } from "@dashboard/channels/utils"; import { createChannelsDataWithDiscountPrice } from "@dashboard/channels/utils";
import { listActionsProps, pageListProps } from "@dashboard/fixtures"; import { listActionsProps, pageListProps } from "@dashboard/fixtures";
import { DiscountErrorCode } from "@dashboard/graphql"; import { DiscountErrorCode } from "@dashboard/graphql";
import Decorator from "@dashboard/storybook/Decorator";
import { PaginatorContextDecorator } from "@dashboard/storybook/PaginatorContextDecorator";
import { storiesOf } from "@storybook/react";
import React from "react"; import React from "react";
import { PaginatorContextDecorator } from "../../../../.storybook/decorators";
import { voucherDetails } from "../../fixtures"; import { voucherDetails } from "../../fixtures";
import VoucherDetailsPage, { import VoucherDetailsPage, {
VoucherDetailsPageFormData, VoucherDetailsPageFormData,
@ -54,17 +52,22 @@ const props: VoucherDetailsPageProps = {
voucher: voucherDetails, voucher: voucherDetails,
}; };
storiesOf("Discounts / Voucher details", module) export default {
.addDecorator(Decorator) title: "Discounts / Voucher details",
.addDecorator(PaginatorContextDecorator) decorators: [PaginatorContextDecorator],
.add("default", () => <VoucherDetailsPage {...props} />) };
.add("loading", () => (
<VoucherDetailsPage {...props} disabled={true} voucher={undefined} /> export const Default = () => <VoucherDetailsPage {...props} />;
))
.add("form errors", () => ( export const Loading = () => (
<VoucherDetailsPage <VoucherDetailsPage {...props} disabled={true} voucher={undefined} />
{...props} );
errors={([
export const Error = () => (
<VoucherDetailsPage
{...props}
errors={(
[
"applyOncePerOrder", "applyOncePerOrder",
"code", "code",
"discountType", "discountType",
@ -75,12 +78,13 @@ storiesOf("Discounts / Voucher details", module)
"type", "type",
"usageLimit", "usageLimit",
"discountValue", "discountValue",
] as Array<keyof VoucherDetailsPageFormData>).map(field => ({ ] as Array<keyof VoucherDetailsPageFormData>
__typename: "DiscountError", ).map(field => ({
channels: [], __typename: "DiscountError",
code: DiscountErrorCode.INVALID, channels: [],
field, code: DiscountErrorCode.INVALID,
message: "Discount invalid", field,
}))} message: "Discount invalid",
/> }))}
)); />
);

View file

@ -9,11 +9,9 @@ import {
tabPageProps, tabPageProps,
} from "@dashboard/fixtures"; } from "@dashboard/fixtures";
import { DiscountStatusEnum, VoucherDiscountType } from "@dashboard/graphql"; import { DiscountStatusEnum, VoucherDiscountType } from "@dashboard/graphql";
import Decorator from "@dashboard/storybook/Decorator";
import { PaginatorContextDecorator } from "@dashboard/storybook/PaginatorContextDecorator";
import { storiesOf } from "@storybook/react";
import React from "react"; import React from "react";
import { PaginatorContextDecorator } from "../../../../.storybook/decorators";
import VoucherListPage, { VoucherListPageProps } from "./VoucherListPage"; import VoucherListPage, { VoucherListPageProps } from "./VoucherListPage";
const props: VoucherListPageProps = { const props: VoucherListPageProps = {
@ -65,19 +63,24 @@ const props: VoucherListPageProps = {
vouchers: voucherList, vouchers: voucherList,
}; };
storiesOf("Discounts / Voucher list", module) export default {
.addDecorator(Decorator) title: "Discounts / Voucher list",
.addDecorator(PaginatorContextDecorator) decorators: [PaginatorContextDecorator],
.add("default", () => <VoucherListPage {...props} />) };
.add("loading", () => <VoucherListPage {...props} vouchers={undefined} />)
.add("no data", () => <VoucherListPage {...props} vouchers={[]} />) export const Default = () => <VoucherListPage {...props} />;
.add("no channels", () => (
<VoucherListPage export const Loading = () => (
{...props} <VoucherListPage {...props} vouchers={undefined} />
selectedChannelId="" );
vouchers={voucherList.map(voucher => ({
...voucher, export const NoChannels = () => (
channelListings: [], <VoucherListPage
}))} {...props}
/> selectedChannelId=""
)); vouchers={voucherList.map(voucher => ({
...voucher,
channelListings: [],
}))}
/>
);

View file

@ -30,7 +30,7 @@ import VoucherDetailsViewComponent from "./views/VoucherDetails";
import VoucherListViewComponent from "./views/VoucherList"; import VoucherListViewComponent from "./views/VoucherList";
const SaleListView: React.FC<RouteComponentProps<{}>> = ({ location }) => { const SaleListView: React.FC<RouteComponentProps<{}>> = ({ location }) => {
const qs = parseQs(location.search.substr(1)); const qs = parseQs(location.search.substr(1)) as any;
const params: SaleListUrlQueryParams = asSortParams(qs, SaleListUrlSortField); const params: SaleListUrlQueryParams = asSortParams(qs, SaleListUrlSortField);
return <SaleListViewComponent params={params} />; return <SaleListViewComponent params={params} />;
}; };
@ -58,7 +58,7 @@ const SaleCreateView: React.FC<RouteComponentProps> = ({ location }) => {
}; };
const VoucherListView: React.FC<RouteComponentProps<{}>> = ({ location }) => { const VoucherListView: React.FC<RouteComponentProps<{}>> = ({ location }) => {
const qs = parseQs(location.search.substr(1)); const qs = parseQs(location.search.substr(1)) as any;
const params: VoucherListUrlQueryParams = asSortParams( const params: VoucherListUrlQueryParams = asSortParams(
qs, qs,
VoucherListUrlSortField, VoucherListUrlSortField,

View file

@ -31,7 +31,7 @@ const GiftCardUpdatePage: React.FC<RouteComponentProps<{ id: string }>> = ({
}; };
const GiftCardList: React.FC<RouteComponentProps<any>> = () => { const GiftCardList: React.FC<RouteComponentProps<any>> = () => {
const qs = parseQs(location.search.substr(1)); const qs = parseQs(location.search.substr(1)) as any;
const params: GiftCardListUrlQueryParams = asSortParams( const params: GiftCardListUrlQueryParams = asSortParams(
qs, qs,
GiftCardUrlSortField, GiftCardUrlSortField,

View file

@ -2,12 +2,10 @@ import placeholderImage from "@assets/images/placeholder60x60.png";
import { adminUserPermissions } from "@dashboard/fixtures"; import { adminUserPermissions } from "@dashboard/fixtures";
import { PermissionEnum } from "@dashboard/graphql"; import { PermissionEnum } from "@dashboard/graphql";
import { shop as shopFixture } from "@dashboard/home/fixtures"; import { shop as shopFixture } from "@dashboard/home/fixtures";
import Decorator from "@dashboard/storybook/Decorator";
import { MockedUserProvider } from "@dashboard/storybook/MockedUserProvider";
import { mapEdgesToItems } from "@dashboard/utils/maps"; import { mapEdgesToItems } from "@dashboard/utils/maps";
import { storiesOf } from "@storybook/react";
import React from "react"; import React from "react";
import { MockedUserProvider } from "../../../../.storybook/helpers";
import HomePageComponent, { HomePageProps } from "./HomePage"; import HomePageComponent, { HomePageProps } from "./HomePage";
const shop = shopFixture(placeholderImage); const shop = shopFixture(placeholderImage);
@ -38,41 +36,48 @@ const HomePage = props => {
); );
}; };
storiesOf("Home", module) export default {
.addDecorator(Decorator) title: "Home / Home",
.add("default", () => <HomePage {...homePageProps} />) };
.add("loading", () => (
<HomePage export const Default = () => <HomePage {...homePageProps} />;
{...homePageProps}
activities={undefined} export const Loading = () => (
orders={undefined} <HomePage
ordersToCapture={undefined} {...homePageProps}
ordersToFulfill={undefined} activities={undefined}
productsOutOfStock={undefined} orders={undefined}
sales={undefined} ordersToCapture={undefined}
topProducts={undefined} ordersToFulfill={undefined}
userName={undefined} productsOutOfStock={undefined}
/> sales={undefined}
)) topProducts={undefined}
.add("no data", () => ( userName={undefined}
<HomePage {...homePageProps} topProducts={[]} activities={[]} /> />
)) );
.add("no permissions", () => (
<HomePage {...homePageProps} customPermissions={[]} /> export const NoData = () => (
)) <HomePage {...homePageProps} topProducts={[]} activities={[]} />
.add("product permissions", () => ( );
<HomePage
{...homePageProps} export const NoPermissions = () => (
customPermissions={adminUserPermissions.filter( <HomePage {...homePageProps} customPermissions={[]} />
perm => perm.code === PermissionEnum.MANAGE_PRODUCTS, );
)}
/> export const ProductPermissions = () => (
)) <HomePage
.add("order permissions", () => ( {...homePageProps}
<HomePage customPermissions={adminUserPermissions.filter(
{...homePageProps} perm => perm.code === PermissionEnum.MANAGE_PRODUCTS,
customPermissions={adminUserPermissions.filter( )}
perm => perm.code === PermissionEnum.MANAGE_ORDERS, />
)} );
/>
)); export const OrderPermissions = () => (
<HomePage
{...homePageProps}
customPermissions={adminUserPermissions.filter(
perm => perm.code === PermissionEnum.MANAGE_ORDERS,
)}
/>
);

View file

@ -1,7 +1,5 @@
import { MenuErrorCode } from "@dashboard/graphql"; import { MenuErrorCode } from "@dashboard/graphql";
import { menu } from "@dashboard/navigation/fixtures"; import { menu } from "@dashboard/navigation/fixtures";
import Decorator from "@dashboard/storybook/Decorator";
import { storiesOf } from "@storybook/react";
import React from "react"; import React from "react";
import MenuDetailsPage, { MenuDetailsPageProps } from "./MenuDetailsPage"; import MenuDetailsPage, { MenuDetailsPageProps } from "./MenuDetailsPage";
@ -18,29 +16,24 @@ const props: MenuDetailsPageProps = {
saveButtonState: "default", saveButtonState: "default",
}; };
storiesOf("Navigation / Menu details", module) export default {
.addDecorator(Decorator) title: "Navigation / Menu details",
.add("default", () => <MenuDetailsPage {...props} />) };
.add("loading", () => (
<MenuDetailsPage {...props} disabled={true} menu={undefined} /> export const Default = () => <MenuDetailsPage {...props} />;
))
.add("no data", () => ( export const Loading = () => (
<MenuDetailsPage <MenuDetailsPage {...props} disabled={true} menu={undefined} />
{...props} );
menu={{
...props.menu, export const FormErrors = () => (
items: [], <MenuDetailsPage
}} {...props}
/> errors={["name"].map(field => ({
)) __typename: "MenuError",
.add("form errors", () => ( code: MenuErrorCode.INVALID,
<MenuDetailsPage field,
{...props} message: "Invalid field",
errors={["name"].map(field => ({ }))}
__typename: "MenuError", />
code: MenuErrorCode.INVALID, );
field,
message: "Invalid field",
}))}
/>
));

View file

@ -5,11 +5,9 @@ import {
} from "@dashboard/fixtures"; } from "@dashboard/fixtures";
import { menuList } from "@dashboard/navigation/fixtures"; import { menuList } from "@dashboard/navigation/fixtures";
import { MenuListUrlSortField } from "@dashboard/navigation/urls"; import { MenuListUrlSortField } from "@dashboard/navigation/urls";
import Decorator from "@dashboard/storybook/Decorator";
import { PaginatorContextDecorator } from "@dashboard/storybook/PaginatorContextDecorator";
import { storiesOf } from "@storybook/react";
import React from "react"; import React from "react";
import { PaginatorContextDecorator } from "../../../../.storybook/decorators";
import MenuListPage, { MenuListPageProps } from "./MenuListPage"; import MenuListPage, { MenuListPageProps } from "./MenuListPage";
const props: MenuListPageProps = { const props: MenuListPageProps = {
@ -24,11 +22,15 @@ const props: MenuListPageProps = {
}, },
}; };
storiesOf("Navigation / Menu list", module) export default {
.addDecorator(Decorator) title: "Navigation / Menu list",
.addDecorator(PaginatorContextDecorator) decorators: [PaginatorContextDecorator],
.add("default", () => <MenuListPage {...props} />) };
.add("loading", () => (
<MenuListPage {...props} disabled={true} menus={undefined} /> export const Default = () => <MenuListPage {...props} />;
))
.add("no data", () => <MenuListPage {...props} menus={[]} />); export const Loading = () => (
<MenuListPage {...props} disabled={true} menus={undefined} />
);
export const NoData = () => <MenuListPage {...props} menus={[]} />;

View file

@ -13,7 +13,7 @@ import MenuDetailsComponent from "./views/MenuDetails";
import MenuListComponent from "./views/MenuList"; import MenuListComponent from "./views/MenuList";
const MenuList: React.FC<RouteComponentProps<{}>> = ({ location }) => { const MenuList: React.FC<RouteComponentProps<{}>> = ({ location }) => {
const qs = parseQs(location.search.substr(1)); const qs = parseQs(location.search.substr(1)) as any;
const params: MenuListUrlQueryParams = asSortParams(qs, MenuListUrlSortField); const params: MenuListUrlQueryParams = asSortParams(qs, MenuListUrlSortField);
return <MenuListComponent params={params} />; return <MenuListComponent params={params} />;

View file

@ -46,13 +46,9 @@ export interface OrderChangeWarehouseDialogProps {
onClose(); onClose();
} }
export const OrderChangeWarehouseDialog: React.FC<OrderChangeWarehouseDialogProps> = ({ export const OrderChangeWarehouseDialog: React.FC<
open, OrderChangeWarehouseDialogProps
line, > = ({ open, line, currentWarehouseId, onConfirm, onClose }) => {
currentWarehouseId,
onConfirm,
onClose,
}) => {
const classes = useStyles(); const classes = useStyles();
const intl = useIntl(); const intl = useIntl();
@ -71,7 +67,11 @@ export const OrderChangeWarehouseDialog: React.FC<OrderChangeWarehouseDialogProp
} }
}, [currentWarehouseId]); }, [currentWarehouseId]);
const { result: warehousesOpts, loadMore, search } = useWarehouseSearch({ const {
result: warehousesOpts,
loadMore,
search,
} = useWarehouseSearch({
variables: { variables: {
after: null, after: null,
first: 20, first: 20,
@ -150,7 +150,7 @@ export const OrderChangeWarehouseDialog: React.FC<OrderChangeWarehouseDialogProp
</DialogContent> </DialogContent>
</ScrollShadow> </ScrollShadow>
<DialogTable ref={setAnchor}> <DialogTable ref={setAnchor} css>
{filteredWarehouses ? ( {filteredWarehouses ? (
<RadioGroup <RadioGroup
value={selectedWarehouseId} value={selectedWarehouseId}
@ -158,10 +158,8 @@ export const OrderChangeWarehouseDialog: React.FC<OrderChangeWarehouseDialogProp
className={classes.tableBody} className={classes.tableBody}
> >
{filteredWarehouses.map(warehouse => { {filteredWarehouses.map(warehouse => {
const lineQuantityInWarehouse = getLineAvailableQuantityInWarehouse( const lineQuantityInWarehouse =
line, getLineAvailableQuantityInWarehouse(line, warehouse);
warehouse,
);
return ( return (
<TableRowLink key={warehouse.id}> <TableRowLink key={warehouse.id}>
<TableCell className={classes.tableCell}> <TableCell className={classes.tableCell}>

View file

@ -1,21 +1,14 @@
import { import {
FulfillmentStatus, FulfillmentStatus,
GiftCardEventsEnum,
OrderDetailsFragment,
OrderStatus, OrderStatus,
PaymentChargeStatusEnum, PaymentChargeStatusEnum,
} from "@dashboard/graphql"; } from "@dashboard/graphql";
import { import {
grantedRefunds,
order, order,
ORDER_AMOUNT,
payments, payments,
prepareMoney, prepareMoney,
shop, shop,
transactions,
} from "@dashboard/orders/fixtures"; } from "@dashboard/orders/fixtures";
import Decorator from "@dashboard/storybook/Decorator";
import { storiesOf } from "@storybook/react";
import React from "react"; import React from "react";
import OrderDetailsPage, { OrderDetailsPageProps } from "./OrderDetailsPage"; import OrderDetailsPage, { OrderDetailsPageProps } from "./OrderDetailsPage";
@ -49,325 +42,159 @@ const props: Omit<OrderDetailsPageProps, "classes"> = {
saveButtonBarState: "default", saveButtonBarState: "default",
}; };
storiesOf("Orders / Order details", module) export default {
.addDecorator(Decorator) title: "Orders / Order details",
.add("pending", () => ( };
<OrderDetailsPage
{...props}
order={{
...props.order,
transactions: [],
paymentStatus: PaymentChargeStatusEnum.NOT_CHARGED,
payments: [payments.pending],
}}
/>
))
.add("authorized", () => (
<OrderDetailsPage
{...props}
order={{
...props.order,
transactions: [],
paymentStatus: PaymentChargeStatusEnum.NOT_CHARGED,
payments: [payments.authorized],
}}
/>
))
.add("completed", () => (
<OrderDetailsPage
{...props}
order={{
...props.order,
transactions: [],
paymentStatus: PaymentChargeStatusEnum.FULLY_CHARGED,
payments: [payments.completed],
}}
/>
))
.add("no payment", () => (
<OrderDetailsPage
{...props}
order={{
...props.order,
transactions: [],
paymentStatus: PaymentChargeStatusEnum.NOT_CHARGED,
payments: [],
totalAuthorized: prepareMoney(0),
}}
/>
))
.add("refunded", () => (
<OrderDetailsPage
{...props}
order={{
...props.order,
transactions: [],
paymentStatus: PaymentChargeStatusEnum.FULLY_REFUNDED,
payments: [payments.refunded],
}}
/>
))
.add("partial refund", () => (
<OrderDetailsPage
{...props}
order={{
...props.order,
transactions: [],
paymentStatus: PaymentChargeStatusEnum.PARTIALLY_REFUNDED,
payments: [payments.partialRefund],
}}
/>
))
.add("rejected", () => (
<OrderDetailsPage
{...props}
order={{
...props.order,
transactions: [],
paymentStatus: PaymentChargeStatusEnum.NOT_CHARGED,
payments: [payments.rejected],
}}
/>
));
storiesOf("Views / Orders / Order details / transactions", module) export const Pending = () => (
.addDecorator(Decorator) <OrderDetailsPage
.add("preauthorized", () => ( {...props}
<OrderDetailsPage order={{
{...props} ...props.order,
order={{ transactions: [],
...props.order, paymentStatus: PaymentChargeStatusEnum.NOT_CHARGED,
isPaid: false, payments: [payments.pending],
totalAuthorized: prepareMoney(), }}
totalCharged: prepareMoney(0), />
paymentStatus: PaymentChargeStatusEnum.NOT_CHARGED, );
transactions: transactions.preauthorized,
}}
/>
))
.add("pending", () => (
<OrderDetailsPage
{...props}
order={{
...props.order,
isPaid: false,
paymentStatus: PaymentChargeStatusEnum.PENDING,
transactions: transactions.pendingCharge,
}}
/>
))
.add("success", () => (
<OrderDetailsPage
{...props}
order={{
...props.order,
isPaid: true,
totalAuthorized: prepareMoney(0),
totalCharged: prepareMoney(),
paymentStatus: PaymentChargeStatusEnum.FULLY_CHARGED,
transactions: transactions.chargeSuccess,
}}
/>
))
.add("partial capture", () => (
<OrderDetailsPage
{...props}
order={{
...props.order,
isPaid: true,
totalAuthorized: prepareMoney(ORDER_AMOUNT - 10),
totalCharged: prepareMoney(10),
paymentStatus: PaymentChargeStatusEnum.PARTIALLY_CHARGED,
transactions: transactions.chargePartial,
}}
/>
))
.add("failed", () => (
<OrderDetailsPage
{...props}
order={{
...props.order,
isPaid: false,
paymentStatus: PaymentChargeStatusEnum.REFUSED,
transactions: transactions.chargeFail,
}}
/>
))
.add("refund requested", () => (
<OrderDetailsPage
{...props}
order={{
...props.order,
isPaid: true,
totalAuthorized: prepareMoney(0),
totalCharged: prepareMoney(),
paymentStatus: PaymentChargeStatusEnum.FULLY_CHARGED,
transactions: transactions.refundRequested,
}}
/>
))
.add("refund granted", () => (
<OrderDetailsPage
{...props}
order={{
...props.order,
isPaid: true,
grantedRefunds,
totalGrantedRefund: prepareMoney(),
totalAuthorized: prepareMoney(0),
totalCharged: prepareMoney(),
paymentStatus: PaymentChargeStatusEnum.FULLY_CHARGED,
transactions: transactions.chargeSuccess,
}}
/>
))
.add("refund completed", () => (
<OrderDetailsPage
{...props}
order={{
...props.order,
isPaid: true,
grantedRefunds,
totalRefunded: prepareMoney(),
totalAuthorized: prepareMoney(0),
totalCharged: prepareMoney(0),
paymentStatus: PaymentChargeStatusEnum.FULLY_REFUNDED,
transactions: transactions.refundCompleted,
}}
/>
))
.add("partial refund completed", () => (
<OrderDetailsPage
{...props}
order={{
...props.order,
isPaid: true,
grantedRefunds,
totalRefunded: prepareMoney(10),
totalAuthorized: prepareMoney(0),
totalCharged: prepareMoney(ORDER_AMOUNT - 10),
paymentStatus: PaymentChargeStatusEnum.PARTIALLY_REFUNDED,
transactions: transactions.refundPartial,
}}
/>
))
.add("paid with giftcard", () => (
<OrderDetailsPage
{...props}
order={
{
...props.order,
isPaid: true,
transactions: [],
paymentStatus: PaymentChargeStatusEnum.FULLY_CHARGED,
// gift cards are treated as dicounts
total: {
net: prepareMoney(0),
gross: prepareMoney(0),
tax: prepareMoney(0),
__typename: "TaxedMoney",
},
giftCards: [
{
__typename: "GiftCard",
id: "R2lmdENhcmQ6Ng==",
last4CodeChars: "43FA",
events: [
{
__typename: "GiftCardEvent",
id: "R2lmdENhcmRFdmVudDo1",
type: GiftCardEventsEnum.ISSUED,
orderId: null,
date: "2022-09-20T13:00:42.676174+00:00",
balance: {
__typename: "GiftCardEventBalance",
initialBalance: prepareMoney(),
currentBalance: prepareMoney(),
oldInitialBalance: null,
oldCurrentBalance: null,
},
},
{
__typename: "GiftCardEvent",
id: "R2lmdENhcmRFdmVudDo2",
type: GiftCardEventsEnum.USED_IN_ORDER,
orderId: props.order.id,
date: "2022-09-20T13:04:20.017419+00:00",
balance: {
__typename: "GiftCardEventBalance",
initialBalance: null,
currentBalance: prepareMoney(0),
oldInitialBalance: null,
oldCurrentBalance: prepareMoney(),
},
},
],
},
],
} as OrderDetailsFragment
}
/>
));
storiesOf("Views / Orders / Order details", module) export const Authorized = () => (
.addDecorator(Decorator) <OrderDetailsPage
.add("default", () => <OrderDetailsPage {...props} />) {...props}
.add("loading", () => <OrderDetailsPage {...props} order={undefined} />) order={{
.add("cancelled", () => ( ...props.order,
<OrderDetailsPage transactions: [],
{...props} paymentStatus: PaymentChargeStatusEnum.NOT_CHARGED,
order={{ payments: [payments.authorized],
...props.order, }}
fulfillments: props.order.fulfillments.map(fulfillment => ({ />
...fulfillment, );
status: FulfillmentStatus.CANCELED,
})), export const Completed = () => (
status: OrderStatus.CANCELED, <OrderDetailsPage
}} {...props}
/> order={{
)) ...props.order,
.add("fulfilled", () => ( transactions: [],
<OrderDetailsPage paymentStatus: PaymentChargeStatusEnum.FULLY_CHARGED,
{...props} payments: [payments.completed],
order={{ }}
...props.order, />
status: OrderStatus.FULFILLED, );
}}
/> export const NoPayment = () => (
)) <OrderDetailsPage
.add("partially fulfilled", () => ( {...props}
<OrderDetailsPage order={{
{...props} ...props.order,
order={{ transactions: [],
...props.order, paymentStatus: PaymentChargeStatusEnum.NOT_CHARGED,
status: OrderStatus.PARTIALLY_FULFILLED, payments: [],
}} totalAuthorized: prepareMoney(0),
/> }}
)) />
.add("unfulfilled", () => ( );
<OrderDetailsPage
{...props} export const Refunded = () => (
order={{ <OrderDetailsPage
...props.order, {...props}
status: OrderStatus.UNFULFILLED, order={{
}} ...props.order,
/> transactions: [],
)) paymentStatus: PaymentChargeStatusEnum.FULLY_REFUNDED,
.add("no shipping address", () => ( payments: [payments.refunded],
<OrderDetailsPage }}
{...props} />
order={{ );
...props.order,
shippingAddress: null, export const PartialRefund = () => (
}} <OrderDetailsPage
/> {...props}
)) order={{
.add("no customer note", () => ( ...props.order,
<OrderDetailsPage transactions: [],
{...props} paymentStatus: PaymentChargeStatusEnum.PARTIALLY_REFUNDED,
order={{ payments: [payments.partialRefund],
...props.order, }}
customerNote: "", />
}} );
/>
)); export const Rejected = () => (
<OrderDetailsPage
{...props}
order={{
...props.order,
transactions: [],
paymentStatus: PaymentChargeStatusEnum.NOT_CHARGED,
payments: [payments.rejected],
}}
/>
);
export const Default = () => <OrderDetailsPage {...props} />;
export const Loading = () => <OrderDetailsPage {...props} order={undefined} />;
export const Cancelled = () => (
<OrderDetailsPage
{...props}
order={{
...props.order,
fulfillments: props.order.fulfillments.map(fulfillment => ({
...fulfillment,
status: FulfillmentStatus.CANCELED,
})),
status: OrderStatus.CANCELED,
}}
/>
);
export const Fulfilled = () => (
<OrderDetailsPage
{...props}
order={{
...props.order,
status: OrderStatus.FULFILLED,
}}
/>
);
export const PartiallyFulfilled = () => (
<OrderDetailsPage
{...props}
order={{
...props.order,
status: OrderStatus.PARTIALLY_FULFILLED,
}}
/>
);
export const Unfulfilled = () => (
<OrderDetailsPage
{...props}
order={{
...props.order,
status: OrderStatus.UNFULFILLED,
}}
/>
);
export const NoShippingAddress = () => (
<OrderDetailsPage
{...props}
order={{
...props.order,
shippingAddress: null,
}}
/>
);
export const NoCustomerNote = () => (
<OrderDetailsPage
{...props}
order={{
...props.order,
customerNote: "",
}}
/>
);

View file

@ -0,0 +1,235 @@
import {
GiftCardEventsEnum,
OrderDetailsFragment,
PaymentChargeStatusEnum,
} from "@dashboard/graphql";
import {
grantedRefunds,
order,
ORDER_AMOUNT,
prepareMoney,
shop,
transactions,
} from "@dashboard/orders/fixtures";
import React from "react";
import OrderDetailsPage, { OrderDetailsPageProps } from "./OrderDetailsPage";
const props: Omit<OrderDetailsPageProps, "classes"> = {
disabled: false,
onBillingAddressEdit: undefined,
onTransactionAction: () => undefined,
onFulfillmentApprove: () => undefined,
onFulfillmentCancel: () => undefined,
onFulfillmentTrackingNumberUpdate: () => undefined,
onInvoiceClick: () => undefined,
onInvoiceGenerate: () => undefined,
onInvoiceSend: () => undefined,
onNoteAdd: undefined,
onOrderCancel: undefined,
onOrderFulfill: undefined,
onOrderReturn: () => undefined,
onPaymentCapture: undefined,
onMarkAsPaid: undefined,
onPaymentVoid: undefined,
onPaymentRefund: undefined,
onProductClick: undefined,
onProfileView: () => undefined,
onShippingAddressEdit: undefined,
onSubmit: () => undefined,
onAddManualTransaction: () => undefined,
order: order(null),
errors: [],
shop,
saveButtonBarState: "default",
};
export default {
title: "Orders / Order details / transactions",
};
export const Preauthorized = () => (
<OrderDetailsPage
{...props}
order={{
...props.order,
isPaid: false,
totalAuthorized: prepareMoney(),
totalCharged: prepareMoney(0),
paymentStatus: PaymentChargeStatusEnum.NOT_CHARGED,
transactions: transactions.preauthorized,
}}
/>
);
export const Pending = () => (
<OrderDetailsPage
{...props}
order={{
...props.order,
isPaid: false,
paymentStatus: PaymentChargeStatusEnum.PENDING,
transactions: transactions.pendingCharge,
}}
/>
);
export const Success = () => (
<OrderDetailsPage
{...props}
order={{
...props.order,
isPaid: true,
totalAuthorized: prepareMoney(0),
totalCharged: prepareMoney(),
paymentStatus: PaymentChargeStatusEnum.FULLY_CHARGED,
transactions: transactions.chargeSuccess,
}}
/>
);
export const PartialCapture = () => (
<OrderDetailsPage
{...props}
order={{
...props.order,
isPaid: true,
totalAuthorized: prepareMoney(ORDER_AMOUNT - 10),
totalCharged: prepareMoney(10),
paymentStatus: PaymentChargeStatusEnum.PARTIALLY_CHARGED,
transactions: transactions.chargePartial,
}}
/>
);
export const Failed = () => (
<OrderDetailsPage
{...props}
order={{
...props.order,
isPaid: false,
paymentStatus: PaymentChargeStatusEnum.REFUSED,
transactions: transactions.chargeFail,
}}
/>
);
export const RefundRequested = () => (
<OrderDetailsPage
{...props}
order={{
...props.order,
isPaid: true,
totalAuthorized: prepareMoney(0),
totalCharged: prepareMoney(),
paymentStatus: PaymentChargeStatusEnum.FULLY_CHARGED,
transactions: transactions.refundRequested,
}}
/>
);
export const RefundGranted = () => (
<OrderDetailsPage
{...props}
order={{
...props.order,
isPaid: true,
grantedRefunds,
totalGrantedRefund: prepareMoney(),
totalAuthorized: prepareMoney(0),
totalCharged: prepareMoney(),
paymentStatus: PaymentChargeStatusEnum.FULLY_CHARGED,
transactions: transactions.chargeSuccess,
}}
/>
);
export const RefundCompleted = () => (
<OrderDetailsPage
{...props}
order={{
...props.order,
isPaid: true,
grantedRefunds,
totalRefunded: prepareMoney(),
totalAuthorized: prepareMoney(0),
totalCharged: prepareMoney(0),
paymentStatus: PaymentChargeStatusEnum.FULLY_REFUNDED,
transactions: transactions.refundCompleted,
}}
/>
);
export const PartialRefundCompleted = () => (
<OrderDetailsPage
{...props}
order={{
...props.order,
isPaid: true,
grantedRefunds,
totalRefunded: prepareMoney(10),
totalAuthorized: prepareMoney(0),
totalCharged: prepareMoney(ORDER_AMOUNT - 10),
paymentStatus: PaymentChargeStatusEnum.PARTIALLY_REFUNDED,
transactions: transactions.refundPartial,
}}
/>
);
export const PaidWithGiftcard = () => (
<OrderDetailsPage
{...props}
order={
{
...props.order,
isPaid: true,
transactions: [],
paymentStatus: PaymentChargeStatusEnum.FULLY_CHARGED,
// gift cards are treated as dicounts
total: {
net: prepareMoney(0),
gross: prepareMoney(0),
tax: prepareMoney(0),
__typename: "TaxedMoney",
},
giftCards: [
{
__typename: "GiftCard",
id: "R2lmdENhcmQ6Ng==",
last4CodeChars: "43FA",
events: [
{
__typename: "GiftCardEvent",
id: "R2lmdENhcmRFdmVudDo1",
type: GiftCardEventsEnum.ISSUED,
orderId: null,
date: "2022-09-20T13:00:42.676174+00:00",
balance: {
__typename: "GiftCardEventBalance",
initialBalance: prepareMoney(),
currentBalance: prepareMoney(),
oldInitialBalance: null,
oldCurrentBalance: null,
},
},
{
__typename: "GiftCardEvent",
id: "R2lmdENhcmRFdmVudDo2",
type: GiftCardEventsEnum.USED_IN_ORDER,
orderId: props.order.id,
date: "2022-09-20T13:04:20.017419+00:00",
balance: {
__typename: "GiftCardEventBalance",
initialBalance: null,
currentBalance: prepareMoney(0),
oldInitialBalance: null,
oldCurrentBalance: prepareMoney(),
},
},
],
},
],
} as OrderDetailsFragment
}
/>
);

View file

@ -9,11 +9,9 @@ import {
tabPageProps, tabPageProps,
} from "@dashboard/fixtures"; } from "@dashboard/fixtures";
import { OrderDraftListUrlSortField } from "@dashboard/orders/urls"; import { OrderDraftListUrlSortField } from "@dashboard/orders/urls";
import Decorator from "@dashboard/storybook/Decorator";
import { PaginatorContextDecorator } from "@dashboard/storybook/PaginatorContextDecorator";
import { storiesOf } from "@storybook/react";
import React from "react"; import React from "react";
import { PaginatorContextDecorator } from "../../../../.storybook/decorators";
import { orders } from "../../fixtures"; import { orders } from "../../fixtures";
import OrderDraftListPage, { import OrderDraftListPage, {
OrderDraftListPageProps, OrderDraftListPageProps,
@ -48,14 +46,19 @@ const props: OrderDraftListPageProps = {
}, },
}; };
storiesOf("Orders / Draft order list", module) export default {
.addDecorator(Decorator) title: "Orders / Draft order list",
.addDecorator(PaginatorContextDecorator) decorators: [PaginatorContextDecorator],
.add("default", () => <OrderDraftListPage {...props} />) };
.add("loading", () => (
<OrderDraftListPage {...props} disabled orders={undefined} /> export const Default = () => <OrderDraftListPage {...props} />;
))
.add("when no data", () => <OrderDraftListPage {...props} orders={[]} />) export const Loading = () => (
.add("limits reached", () => ( <OrderDraftListPage {...props} disabled orders={undefined} />
<OrderDraftListPage {...props} limits={limitsReached} /> );
));
export const WhenNoData = () => <OrderDraftListPage {...props} orders={[]} />;
export const LimitsReached = () => (
<OrderDraftListPage {...props} limits={limitsReached} />
);

View file

@ -6,11 +6,9 @@ import {
clients, clients,
draftOrder, draftOrder,
} from "@dashboard/orders/fixtures"; } from "@dashboard/orders/fixtures";
import Decorator from "@dashboard/storybook/Decorator";
import { MockedUserProvider } from "@dashboard/storybook/MockedUserProvider";
import { storiesOf } from "@storybook/react";
import React from "react"; import React from "react";
import { MockedUserProvider } from "../../../../.storybook/helpers";
import OrderDraftPageComponent, { OrderDraftPageProps } from "./OrderDraftPage"; import OrderDraftPageComponent, { OrderDraftPageProps } from "./OrderDraftPage";
import { getDiscountsProvidersWrapper } from "./storybook.utils"; import { getDiscountsProvidersWrapper } from "./storybook.utils";
@ -79,24 +77,26 @@ const OrderDraftPage = props => {
); );
}; };
storiesOf("Orders / Order draft", module) export default {
.addDecorator(Decorator) title: "Orders / Order draft",
.addDecorator(DiscountsDecorator) decorators: [DiscountsDecorator],
.add("default", () => <OrderDraftPage {...props} />) };
.add("loading", () => (
<OrderDraftPage export const Default = () => <OrderDraftPage {...props} />;
{...props}
disabled={true} export const Loading = () => (
order={undefined} <OrderDraftPage
channelUsabilityData={undefined} {...props}
/> disabled={true}
)) order={undefined}
.add("without lines", () => ( channelUsabilityData={undefined}
<OrderDraftPage {...props} order={{ ...order, lines: [] }} /> />
)) );
.add("no user permissions", () => (
<OrderDraftPage {...props} customPermissions={[]} /> export const NoUserPermissions = () => (
)) <OrderDraftPage {...props} customPermissions={[]} />
.add("with errors", () => ( );
<OrderDraftPage {...props} errors={finalizeErrors} />
)); export const WithErrors = () => (
<OrderDraftPage {...props} errors={finalizeErrors} />
);

View file

@ -1,7 +1,5 @@
import { OrderErrorCode } from "@dashboard/graphql"; import { OrderErrorCode } from "@dashboard/graphql";
import Decorator from "@dashboard/storybook/Decorator";
import { warehouseList } from "@dashboard/warehouses/fixtures"; import { warehouseList } from "@dashboard/warehouses/fixtures";
import { storiesOf } from "@storybook/react";
import React from "react"; import React from "react";
import { orderToFulfill } from "./fixtures"; import { orderToFulfill } from "./fixtures";
@ -18,26 +16,31 @@ const props: OrderFulfillPageProps = {
closeModal: () => undefined, closeModal: () => undefined,
}; };
storiesOf("Orders / Fulfill order", module) export default {
.addDecorator(Decorator) title: "Orders / Fulfill order",
.add("default", () => <OrderFulfillPage {...props} />) };
.add("loading", () => (
<OrderFulfillPage {...props} loading={true} order={undefined} /> export const Default = () => <OrderFulfillPage {...props} />;
))
.add("error", () => ( export const Loading = () => (
<OrderFulfillPage <OrderFulfillPage {...props} loading={true} order={undefined} />
{...props} );
errors={[
{ export const Error = () => (
__typename: "OrderError", <OrderFulfillPage
code: OrderErrorCode.INSUFFICIENT_STOCK, {...props}
field: null, errors={[
orderLines: [orderToFulfill.lines[0].id], {
warehouse: warehouseList[0].id, __typename: "OrderError",
addressType: null, code: OrderErrorCode.INSUFFICIENT_STOCK,
message: "Insufficient stock", field: null,
}, orderLines: [orderToFulfill.lines[0].id],
]} warehouse: warehouseList[0].id,
/> addressType: null,
)) message: "Insufficient stock",
.add("one warehouse", () => <OrderFulfillPage {...props} />); },
]}
/>
);
export const OneWarehouse = () => <OrderFulfillPage {...props} />;

View file

@ -1,7 +1,5 @@
import placeholderImage from "@assets/images/placeholder60x60.png"; import placeholderImage from "@assets/images/placeholder60x60.png";
import { FulfillmentStatus } from "@dashboard/graphql"; import { FulfillmentStatus } from "@dashboard/graphql";
import Decorator from "@dashboard/storybook/Decorator";
import { storiesOf } from "@storybook/react";
import React from "react"; import React from "react";
import OrderGrantRefundPage, { import OrderGrantRefundPage, {
@ -244,14 +242,17 @@ const props: OrderGrantRefundPageProps = {
onSubmit: data => console.log("onSubmit", data), onSubmit: data => console.log("onSubmit", data),
}; };
storiesOf("Views / Orders / Grant refund order", module) export default {
.addDecorator(Decorator) title: "Orders / Grant refund order",
.add("grant refund", () => <OrderGrantRefundPage {...props} />) };
.add("loading", () => (
<OrderGrantRefundPage export const GrantRefund = () => <OrderGrantRefundPage {...props} />;
submitState="loading"
order={null} export const Loading = () => (
loading={true} <OrderGrantRefundPage
onSubmit={() => undefined} submitState="loading"
/> order={null}
)); loading={true}
onSubmit={() => undefined}
/>
);

View file

@ -9,11 +9,9 @@ import {
import { OrderStatusFilter, PaymentChargeStatusEnum } from "@dashboard/graphql"; import { OrderStatusFilter, PaymentChargeStatusEnum } from "@dashboard/graphql";
import { orders } from "@dashboard/orders/fixtures"; import { orders } from "@dashboard/orders/fixtures";
import { OrderListUrlSortField } from "@dashboard/orders/urls"; import { OrderListUrlSortField } from "@dashboard/orders/urls";
import Decorator from "@dashboard/storybook/Decorator";
import { PaginatorContextDecorator } from "@dashboard/storybook/PaginatorContextDecorator";
import { storiesOf } from "@storybook/react";
import React from "react"; import React from "react";
import { PaginatorContextDecorator } from "../../../../.storybook/decorators";
import { OrderFilterGiftCard } from "./filters"; import { OrderFilterGiftCard } from "./filters";
import OrderListPage, { OrderListPageProps } from "./OrderListPage"; import OrderListPage, { OrderListPageProps } from "./OrderListPage";
@ -86,20 +84,26 @@ const props: OrderListPageProps = {
onTabUpdate: () => undefined, onTabUpdate: () => undefined,
}; };
storiesOf("Orders / Order list", module) export default {
.addDecorator(Decorator) title: "Orders / Order list",
.addDecorator(PaginatorContextDecorator) decorators: [PaginatorContextDecorator],
.add("default", () => <OrderListPage {...props} />) };
.add("loading", () => (
<OrderListPage export const Default = () => <OrderListPage {...props} />;
{...props}
orders={undefined} export const Loading = () => (
currentTab={undefined} <OrderListPage
disabled={true} {...props}
/> orders={undefined}
)) currentTab={undefined}
.add("when no data", () => <OrderListPage {...props} orders={[]} />) disabled={true}
.add("no limits", () => <OrderListPage {...props} limits={undefined} />) />
.add("limits reached", () => ( );
<OrderListPage {...props} limits={limitsReached} />
)); export const WhenNoData = () => <OrderListPage {...props} orders={[]} />;
export const NoLimits = () => <OrderListPage {...props} limits={undefined} />;
export const LimitsReached = () => (
<OrderListPage {...props} limits={limitsReached} />
);

View file

@ -1,6 +1,4 @@
import placeholderImage from "@assets/images/placeholder60x60.png"; import placeholderImage from "@assets/images/placeholder60x60.png";
import Decorator from "@dashboard/storybook/Decorator";
import { storiesOf } from "@storybook/react";
import React from "react"; import React from "react";
import { orderToRefund } from "./fixtures"; import { orderToRefund } from "./fixtures";
@ -14,14 +12,18 @@ const props: OrderRefundPageProps = {
order: orderToRefund(placeholderImage), order: orderToRefund(placeholderImage),
}; };
storiesOf("Orders / Refund order", module) export default {
.addDecorator(Decorator) title: "Orders / Refund order",
.add("products", () => ( };
<OrderRefundPage {...props} defaultType={OrderRefundType.PRODUCTS} />
)) export const Products = () => (
.add("miscellaneous", () => ( <OrderRefundPage {...props} defaultType={OrderRefundType.PRODUCTS} />
<OrderRefundPage {...props} defaultType={OrderRefundType.MISCELLANEOUS} /> );
))
.add("loading", () => ( export const Miscellaneous = () => (
<OrderRefundPage {...props} disabled={true} order={undefined} /> <OrderRefundPage {...props} defaultType={OrderRefundType.MISCELLANEOUS} />
)); );
export const Loading = () => (
<OrderRefundPage {...props} disabled={true} order={undefined} />
);

View file

@ -1,5 +1,3 @@
import Decorator from "@dashboard/storybook/Decorator";
import { storiesOf } from "@storybook/react";
import React from "react"; import React from "react";
import { order as orderFixture, prepareMoney } from "../../fixtures"; import { order as orderFixture, prepareMoney } from "../../fixtures";
@ -13,19 +11,23 @@ const props: OrderSendRefundPageProps = {
addManualRefundError: undefined, addManualRefundError: undefined,
}; };
storiesOf("Views / Orders / Send refund order", module) export default {
.addDecorator(Decorator) title: "Orders / Send refund order",
.add("settled", () => <OrderSendRefund {...props} />) };
.add("unsettled", () => (
<OrderSendRefund export const Settled = () => <OrderSendRefund {...props} />;
{...props}
order={{ export const Unsettled = () => (
...orderFixture(null), <OrderSendRefund
totalGrantedRefund: prepareMoney(10), {...props}
totalRemainingGrant: prepareMoney(10), order={{
}} ...orderFixture(null),
/> totalGrantedRefund: prepareMoney(10),
)) totalRemainingGrant: prepareMoney(10),
.add("loading", () => ( }}
<OrderSendRefund {...props} order={null} loading={true} /> />
)); );
export const Loading = () => (
<OrderSendRefund {...props} order={null} loading={true} />
);

View file

@ -2,8 +2,6 @@ import {
orderSettings as orderSettingsFixture, orderSettings as orderSettingsFixture,
shopOrderSettings as shopOrderSettingsFixture, shopOrderSettings as shopOrderSettingsFixture,
} from "@dashboard/orders/fixtures"; } from "@dashboard/orders/fixtures";
import Decorator from "@dashboard/storybook/Decorator";
import { storiesOf } from "@storybook/react";
import React from "react"; import React from "react";
import OrderSettings, { OrderSettingsPageProps } from "./OrderSettingsPage"; import OrderSettings, { OrderSettingsPageProps } from "./OrderSettingsPage";
@ -16,14 +14,17 @@ const props: OrderSettingsPageProps = {
saveButtonBarState: "default", saveButtonBarState: "default",
}; };
storiesOf(" Orders / Order settings", module) export default {
.addDecorator(Decorator) title: " Orders / Order settings",
.add("default", () => <OrderSettings {...props} />) };
.add("loading", () => (
<OrderSettings export const Default = () => <OrderSettings {...props} />;
{...props}
disabled={true} export const Loading = () => (
orderSettings={undefined} <OrderSettings
shop={undefined} {...props}
/> disabled={true}
)); orderSettings={undefined}
shop={undefined}
/>
);

View file

@ -5,8 +5,6 @@ import {
import OrderTransaction, { import OrderTransaction, {
OrderTransactionProps, OrderTransactionProps,
} from "@dashboard/orders/components/OrderTransaction"; } from "@dashboard/orders/components/OrderTransaction";
import Decorator from "@dashboard/storybook/Decorator";
import { storiesOf } from "@storybook/react";
import React from "react"; import React from "react";
import { prepareMoney } from "../fixtures"; import { prepareMoney } from "../fixtures";
@ -150,7 +148,10 @@ const longAmountProps: OrderTransactionProps = {
}, },
}; };
storiesOf("Orders / OrderTransaction", module) export default {
.addDecorator(Decorator) title: "Orders / OrderTransaction",
.add("default", () => <OrderTransaction {...props} />) };
.add("long amounts", () => <OrderTransaction {...longAmountProps} />);
export const Default = () => <OrderTransaction {...props} />;
export const LongAmounts = () => <OrderTransaction {...longAmountProps} />;

View file

@ -36,7 +36,7 @@ import OrderSendRefundComponent from "./views/OrderSendRefund";
import OrderSettings from "./views/OrderSettings"; import OrderSettings from "./views/OrderSettings";
const OrderList: React.FC<RouteComponentProps<any>> = ({ location }) => { const OrderList: React.FC<RouteComponentProps<any>> = ({ location }) => {
const qs = parseQs(location.search.substr(1)); const qs = parseQs(location.search.substr(1)) as any;
const params: OrderListUrlQueryParams = asSortParams( const params: OrderListUrlQueryParams = asSortParams(
qs, qs,
OrderListUrlSortField, OrderListUrlSortField,
@ -46,7 +46,7 @@ const OrderList: React.FC<RouteComponentProps<any>> = ({ location }) => {
return <OrderListComponent params={params} />; return <OrderListComponent params={params} />;
}; };
const OrderDraftList: React.FC<RouteComponentProps<any>> = ({ location }) => { const OrderDraftList: React.FC<RouteComponentProps<any>> = ({ location }) => {
const qs = parseQs(location.search.substr(1)); const qs = parseQs(location.search.substr(1)) as any;
const params: OrderDraftListUrlQueryParams = asSortParams( const params: OrderDraftListUrlQueryParams = asSortParams(
qs, qs,
OrderDraftListUrlSortField, OrderDraftListUrlSortField,
@ -61,7 +61,7 @@ const OrderDetails: React.FC<RouteComponentProps<any>> = ({
location, location,
match, match,
}) => { }) => {
const qs = parseQs(location.search.substr(1)); const qs = parseQs(location.search.substr(1)) as any;
const params: OrderUrlQueryParams = qs; const params: OrderUrlQueryParams = qs;
const id = match.params.id; const id = match.params.id;
@ -72,7 +72,7 @@ const OrderFulfill: React.FC<RouteComponentProps<any>> = ({
location, location,
match, match,
}) => { }) => {
const qs = parseQs(location.search.substr(1)); const qs = parseQs(location.search.substr(1)) as any;
const params: OrderFulfillUrlQueryParams = qs; const params: OrderFulfillUrlQueryParams = qs;
return ( return (
<OrderFulfillComponent <OrderFulfillComponent

View file

@ -1,6 +1,4 @@
import { PageErrorCode } from "@dashboard/graphql"; import { PageErrorCode } from "@dashboard/graphql";
import Decorator from "@dashboard/storybook/Decorator";
import { storiesOf } from "@storybook/react";
import React from "react"; import React from "react";
import PageTypeCreatePage, { import PageTypeCreatePage, {
@ -14,22 +12,26 @@ const props: Omit<PageTypeCreatePageProps, "classes"> = {
saveButtonBarState: "default", saveButtonBarState: "default",
}; };
storiesOf("Page types / Create page type", module) export default {
.addDecorator(Decorator) title: "Page types / Create page type",
.add("default", () => <PageTypeCreatePage {...props} />) };
.add("loading", () => <PageTypeCreatePage {...props} disabled={true} />)
.add("form errors", () => ( export const Default = () => <PageTypeCreatePage {...props} />;
<PageTypeCreatePage
{...props} export const Loading = () => <PageTypeCreatePage {...props} disabled={true} />;
errors={[
{ export const FormErrors = () => (
code: PageErrorCode.REQUIRED, <PageTypeCreatePage
field: "name", {...props}
message: "Field is required", errors={[
}, {
].map(err => ({ code: PageErrorCode.REQUIRED,
__typename: "PageError", field: "name",
...err, message: "Field is required",
}))} },
/> ].map(err => ({
)); __typename: "PageError",
...err,
}))}
/>
);

View file

@ -1,7 +1,5 @@
import { listActionsProps } from "@dashboard/fixtures"; import { listActionsProps } from "@dashboard/fixtures";
import { PageErrorCode } from "@dashboard/graphql"; import { PageErrorCode } from "@dashboard/graphql";
import Decorator from "@dashboard/storybook/Decorator";
import { storiesOf } from "@storybook/react";
import React from "react"; import React from "react";
import { pageType } from "../../fixtures"; import { pageType } from "../../fixtures";
@ -23,38 +21,33 @@ const props: Omit<PageTypeDetailsPageProps, "classes"> = {
saveButtonBarState: "default", saveButtonBarState: "default",
}; };
storiesOf("Page types / Page type details", module) export default {
.addDecorator(Decorator) title: "Page types / Page type details",
.add("default", () => <PageTypeDetailsPage {...props} />) };
.add("loading", () => (
<PageTypeDetailsPage export const Default = () => <PageTypeDetailsPage {...props} />;
{...props}
disabled={true} export const Loading = () => (
pageTitle={undefined} <PageTypeDetailsPage
pageType={undefined} {...props}
/> disabled={true}
)) pageTitle={undefined}
.add("no attributes", () => ( pageType={undefined}
<PageTypeDetailsPage />
{...props} );
pageType={{
...pageType, export const FormErrors = () => (
attributes: [], <PageTypeDetailsPage
}} {...props}
/> errors={[
)) {
.add("form errors", () => ( code: PageErrorCode.REQUIRED,
<PageTypeDetailsPage field: "name",
{...props} message: "Field is required",
errors={[ },
{ ].map(err => ({
code: PageErrorCode.REQUIRED, __typename: "PageError",
field: "name", ...err,
message: "Field is required", }))}
}, />
].map(err => ({ );
__typename: "PageError",
...err,
}))}
/>
));

View file

@ -6,11 +6,9 @@ import {
tabPageProps, tabPageProps,
} from "@dashboard/fixtures"; } from "@dashboard/fixtures";
import { PageTypeListUrlSortField } from "@dashboard/pageTypes/urls"; import { PageTypeListUrlSortField } from "@dashboard/pageTypes/urls";
import Decorator from "@dashboard/storybook/Decorator";
import { PaginatorContextDecorator } from "@dashboard/storybook/PaginatorContextDecorator";
import { storiesOf } from "@storybook/react";
import React from "react"; import React from "react";
import { PaginatorContextDecorator } from "../../../../.storybook/decorators";
import { pageTypes } from "../../fixtures"; import { pageTypes } from "../../fixtures";
import PageTypeListPage, { PageTypeListPageProps } from "./PageTypeListPage"; import PageTypeListPage, { PageTypeListPageProps } from "./PageTypeListPage";
@ -27,11 +25,15 @@ const props: PageTypeListPageProps = {
pageTypes, pageTypes,
}; };
storiesOf("Page types / Page types list", module) export default {
.addDecorator(Decorator) title: "Page types / Page types list",
.addDecorator(PaginatorContextDecorator) decorators: [PaginatorContextDecorator],
.add("default", () => <PageTypeListPage {...props} />) };
.add("loading", () => (
<PageTypeListPage {...props} disabled={true} pageTypes={undefined} /> export const Default = () => <PageTypeListPage {...props} />;
))
.add("no data", () => <PageTypeListPage {...props} pageTypes={[]} />); export const Loading = () => (
<PageTypeListPage {...props} disabled={true} pageTypes={undefined} />
);
export const NoData = () => <PageTypeListPage {...props} pageTypes={[]} />;

View file

@ -19,7 +19,7 @@ import PageTypeDetailsComponent from "./views/PageTypeDetails";
import PageTypeListComponent from "./views/PageTypeList"; import PageTypeListComponent from "./views/PageTypeList";
const PageTypeList: React.FC<RouteComponentProps<{}>> = ({ location }) => { const PageTypeList: React.FC<RouteComponentProps<{}>> = ({ location }) => {
const qs = parseQs(location.search.substr(1)); const qs = parseQs(location.search.substr(1)) as any;
const params: PageTypeListUrlQueryParams = asSortParams( const params: PageTypeListUrlQueryParams = asSortParams(
qs, qs,
PageTypeListUrlSortField, PageTypeListUrlSortField,
@ -30,9 +30,9 @@ const PageTypeList: React.FC<RouteComponentProps<{}>> = ({ location }) => {
interface PageTypeDetailsRouteParams { interface PageTypeDetailsRouteParams {
id: string; id: string;
} }
const PageTypeDetails: React.FC<RouteComponentProps< const PageTypeDetails: React.FC<
PageTypeDetailsRouteParams RouteComponentProps<PageTypeDetailsRouteParams>
>> = ({ match }) => { > = ({ match }) => {
const qs = parseQs(location.search.substr(1)); const qs = parseQs(location.search.substr(1));
const params: PageTypeUrlQueryParams = qs; const params: PageTypeUrlQueryParams = qs;

View file

@ -2,8 +2,6 @@ import { fetchMoreProps } from "@dashboard/fixtures";
import { PageErrorCode } from "@dashboard/graphql"; import { PageErrorCode } from "@dashboard/graphql";
import { PageData } from "@dashboard/pages/components/PageDetailsPage/form"; import { PageData } from "@dashboard/pages/components/PageDetailsPage/form";
import { page } from "@dashboard/pages/fixtures"; import { page } from "@dashboard/pages/fixtures";
import Decorator from "@dashboard/storybook/Decorator";
import { storiesOf } from "@storybook/react";
import React from "react"; import React from "react";
import PageDetailsPage, { PageDetailsPageProps } from "./PageDetailsPage"; import PageDetailsPage, { PageDetailsPageProps } from "./PageDetailsPage";
@ -25,16 +23,21 @@ const props: PageDetailsPageProps = {
fetchMoreAttributeValues: fetchMoreProps, fetchMoreAttributeValues: fetchMoreProps,
}; };
storiesOf("Pages / Page details", module) export default {
.addDecorator(Decorator) title: "Pages / Page details",
.add("default", () => <PageDetailsPage {...props} />) };
.add("loading", () => (
<PageDetailsPage {...props} loading={true} page={undefined} /> export const Default = () => <PageDetailsPage {...props} />;
))
.add("form errors", () => ( export const Loading = () => (
<PageDetailsPage <PageDetailsPage {...props} loading={true} page={undefined} />
{...props} );
errors={([
export const FormErrors = () => (
<PageDetailsPage
{...props}
errors={(
[
"title", "title",
"slug", "slug",
"content", "content",
@ -42,12 +45,13 @@ storiesOf("Pages / Page details", module)
"isPublished", "isPublished",
"seoDescription", "seoDescription",
"seoTitle", "seoTitle",
] as Array<keyof PageData>).map(field => ({ ] as Array<keyof PageData>
__typename: "PageError", ).map(field => ({
attributes: [], __typename: "PageError",
code: PageErrorCode.INVALID, attributes: [],
field, code: PageErrorCode.INVALID,
message: "Page field error", field,
}))} message: "Page field error",
/> }))}
)); />
);

View file

@ -5,11 +5,9 @@ import {
} from "@dashboard/fixtures"; } from "@dashboard/fixtures";
import { pageList } from "@dashboard/pages/fixtures"; import { pageList } from "@dashboard/pages/fixtures";
import { PageListUrlSortField } from "@dashboard/pages/urls"; import { PageListUrlSortField } from "@dashboard/pages/urls";
import Decorator from "@dashboard/storybook/Decorator";
import { PaginatorContextDecorator } from "@dashboard/storybook/PaginatorContextDecorator";
import { storiesOf } from "@storybook/react";
import React from "react"; import React from "react";
import { PaginatorContextDecorator } from "../../../../.storybook/decorators";
import PageListPage, { PageListPageProps } from "./PageListPage"; import PageListPage, { PageListPageProps } from "./PageListPage";
const props: PageListPageProps = { const props: PageListPageProps = {
@ -30,11 +28,15 @@ const props: PageListPageProps = {
}, },
}; };
storiesOf("Pages / Page list", module) export default {
.addDecorator(Decorator) title: "Pages / Page list",
.addDecorator(PaginatorContextDecorator) decorators: [PaginatorContextDecorator],
.add("default", () => <PageListPage {...props} />) };
.add("loading", () => (
<PageListPage {...props} disabled={true} pages={undefined} /> export const Default = () => <PageListPage {...props} />;
))
.add("no data", () => <PageListPage {...props} pages={[]} />); export const Loading = () => (
<PageListPage {...props} disabled={true} pages={undefined} />
);
export const NoData = () => <PageListPage {...props} pages={[]} />;

View file

@ -20,7 +20,7 @@ import PageDetailsComponent from "./views/PageDetails";
import PageListComponent from "./views/PageList"; import PageListComponent from "./views/PageList";
const PageList: React.FC<RouteComponentProps<{}>> = ({ location }) => { const PageList: React.FC<RouteComponentProps<{}>> = ({ location }) => {
const qs = parseQs(location.search.substr(1)); const qs = parseQs(location.search.substr(1)) as any;
const params: PageListUrlQueryParams = asSortParams( const params: PageListUrlQueryParams = asSortParams(
qs, qs,
PageListUrlSortField, PageListUrlSortField,

View file

@ -1,6 +1,4 @@
import { permissions } from "@dashboard/fixtures"; import { permissions } from "@dashboard/fixtures";
import Decorator from "@dashboard/storybook/Decorator";
import { storiesOf } from "@storybook/react";
import React from "react"; import React from "react";
import { errorsOfPermissionGroupCreate } from "../../fixtures"; import { errorsOfPermissionGroupCreate } from "../../fixtures";
@ -16,15 +14,19 @@ const props: PermissionGroupCreatePageProps = {
saveButtonBarState: undefined, saveButtonBarState: undefined,
}; };
storiesOf("Permission Groups / Permission Group Create", module) export default {
.addDecorator(Decorator) title: "Permission Groups / Permission Group Create",
.add("default", () => <PermissionGroupCreatePage {...props} />) };
.add("loading", () => (
<PermissionGroupCreatePage {...props} disabled={true} /> export const Default = () => <PermissionGroupCreatePage {...props} />;
))
.add("errors", () => ( export const Loading = () => (
<PermissionGroupCreatePage <PermissionGroupCreatePage {...props} disabled={true} />
{...props} );
errors={errorsOfPermissionGroupCreate}
/> export const Errors = () => (
)); <PermissionGroupCreatePage
{...props}
errors={errorsOfPermissionGroupCreate}
/>
);

View file

@ -1,6 +1,4 @@
import { permissions } from "@dashboard/fixtures"; import { permissions } from "@dashboard/fixtures";
import Decorator from "@dashboard/storybook/Decorator";
import { storiesOf } from "@storybook/react";
import React from "react"; import React from "react";
import { emptyPermissionGroup, permissionGroup, users } from "../../fixtures"; import { emptyPermissionGroup, permissionGroup, users } from "../../fixtures";
@ -28,21 +26,25 @@ const props: PermissionGroupDetailsPageProps = {
toolbar: null, toolbar: null,
}; };
storiesOf("Permission Groups / Permission Group Details", module) export default {
.addDecorator(Decorator) title: "Permission Groups / Permission Group Details",
.add("default", () => <PermissionGroupDetailsPage {...props} />) };
.add("no members", () => (
<PermissionGroupDetailsPage export const Default = () => <PermissionGroupDetailsPage {...props} />;
{...props}
members={[]} export const NoMembers = () => (
permissionGroup={emptyPermissionGroup} <PermissionGroupDetailsPage
/> {...props}
)) members={[]}
.add("loading", () => ( permissionGroup={emptyPermissionGroup}
<PermissionGroupDetailsPage />
{...props} );
disabled={true}
permissionGroup={undefined} export const Loading = () => (
permissions={undefined} <PermissionGroupDetailsPage
/> {...props}
)); disabled={true}
permissionGroup={undefined}
permissions={undefined}
/>
);

View file

@ -3,11 +3,9 @@ import {
pageListProps, pageListProps,
sortPageProps, sortPageProps,
} from "@dashboard/fixtures"; } from "@dashboard/fixtures";
import Decorator from "@dashboard/storybook/Decorator";
import { PaginatorContextDecorator } from "@dashboard/storybook/PaginatorContextDecorator";
import { storiesOf } from "@storybook/react";
import React from "react"; import React from "react";
import { PaginatorContextDecorator } from "../../../../.storybook/decorators";
import { permissionGroups } from "../../fixtures"; import { permissionGroups } from "../../fixtures";
import { PermissionGroupListUrlSortField } from "../../urls"; import { PermissionGroupListUrlSortField } from "../../urls";
import PermissionGroupListPage, { import PermissionGroupListPage, {
@ -27,17 +25,17 @@ const props: PermissionGroupListPageProps = {
}, },
}; };
storiesOf("Permission Groups / Permission Group List", module) export default {
.addDecorator(Decorator) title: "Permission Groups / Permission Group List",
.addDecorator(PaginatorContextDecorator) decorators: [PaginatorContextDecorator],
.add("default", () => <PermissionGroupListPage {...props} />) };
.add("loading", () => (
<PermissionGroupListPage export const Default = () => <PermissionGroupListPage {...props} />;
{...props}
permissionGroups={undefined} export const Loading = () => (
disabled={true} <PermissionGroupListPage
/> {...props}
)) permissionGroups={undefined}
.add("no data", () => ( disabled={true}
<PermissionGroupListPage {...props} permissionGroups={[]} disabled={true} /> />
)); );

View file

@ -1,4 +1,4 @@
import * as avatarImg from "@assets/images/avatars/avatar1.png"; import avatarImg from "@assets/images/avatars/avatar.png";
import { import {
PermissionEnum, PermissionEnum,
PermissionGroupDetailsFragment, PermissionGroupDetailsFragment,
@ -90,20 +90,21 @@ export const permissionGroups: PermissionGroupFragment[] = [
}, },
].map(edge => edge.node); ].map(edge => edge.node);
export const userPermissionGroups: StaffMemberDetailsFragment["permissionGroups"] = [ export const userPermissionGroups: StaffMemberDetailsFragment["permissionGroups"] =
{ [
id: "R3JvdXA6MQ==", {
name: "Full Access", id: "R3JvdXA6MQ==",
userCanManage: false, name: "Full Access",
__typename: "Group", userCanManage: false,
}, __typename: "Group",
{ },
id: "R3JvdXA6Mg==", {
name: "Customer Support", id: "R3JvdXA6Mg==",
userCanManage: true, name: "Customer Support",
__typename: "Group", userCanManage: true,
}, __typename: "Group",
]; },
];
export const emptyPermissionGroup: PermissionGroupDetailsFragment = { export const emptyPermissionGroup: PermissionGroupDetailsFragment = {
id: "R3JvdXA6Mw==", id: "R3JvdXA6Mw==",

View file

@ -22,7 +22,7 @@ import PermissionGroupListComponent from "./views/PermissionGroupList";
const permissionGroupList: React.FC<RouteComponentProps<{}>> = ({ const permissionGroupList: React.FC<RouteComponentProps<{}>> = ({
location, location,
}) => { }) => {
const qs = parseQs(location.search.substr(1)); const qs = parseQs(location.search.substr(1)) as any;
const params: PermissionGroupListUrlQueryParams = asSortParams( const params: PermissionGroupListUrlQueryParams = asSortParams(
qs, qs,
PermissionGroupListUrlSortField, PermissionGroupListUrlSortField,
@ -34,10 +34,10 @@ const permissionGroupList: React.FC<RouteComponentProps<{}>> = ({
interface PermissionGroupDetailsRouteProps { interface PermissionGroupDetailsRouteProps {
id: string; id: string;
} }
const PermissionGroupDetails: React.FC<RouteComponentProps< const PermissionGroupDetails: React.FC<
PermissionGroupDetailsRouteProps RouteComponentProps<PermissionGroupDetailsRouteProps>
>> = ({ match }) => { > = ({ match }) => {
const qs = parseQs(location.search.substr(1)); const qs = parseQs(location.search.substr(1)) as any;
const params: PermissionGroupDetailsUrlQueryParams = asSortParams( const params: PermissionGroupDetailsUrlQueryParams = asSortParams(
qs, qs,
MembersListUrlSortField, MembersListUrlSortField,

View file

@ -1,6 +1,4 @@
import { PluginErrorCode } from "@dashboard/graphql"; import { PluginErrorCode } from "@dashboard/graphql";
import Decorator from "@dashboard/storybook/Decorator";
import { storiesOf } from "@storybook/react";
import React from "react"; import React from "react";
import { plugin } from "../../fixtures"; import { plugin } from "../../fixtures";
@ -20,38 +18,45 @@ const props: PluginsDetailsPageProps = {
setSelectedChannelId: () => undefined, setSelectedChannelId: () => undefined,
}; };
storiesOf("Plugins / Plugin details", module) export default {
.addDecorator(Decorator) title: "Plugins / Plugin details",
.add("default", () => <PluginsDetailsPage {...props} />) };
.add("loading", () => (
<PluginsDetailsPage {...props} disabled={true} plugin={undefined} /> export const Default = () => <PluginsDetailsPage {...props} />;
))
.add("form errors", () => ( export const Loading = () => (
<PluginsDetailsPage <PluginsDetailsPage {...props} disabled={true} plugin={undefined} />
{...props} );
errors={[
...(["active", "Username or account", "Password or license"] as Array< export const FormErrors = () => (
<PluginsDetailsPage
{...props}
errors={[
...(
["active", "Username or account", "Password or license"] as Array<
keyof PluginDetailsPageFormData keyof PluginDetailsPageFormData
>).map(field => ({ >
__typename: "PluginError" as "PluginError", ).map(field => ({
code: PluginErrorCode.INVALID, __typename: "PluginError" as "PluginError",
field, code: PluginErrorCode.INVALID,
message: "Plugin invalid", field,
})), message: "Plugin invalid",
{ })),
__typename: "PluginError" as "PluginError", {
code: PluginErrorCode.PLUGIN_MISCONFIGURED, __typename: "PluginError" as "PluginError",
field: null, code: PluginErrorCode.PLUGIN_MISCONFIGURED,
message: "Plugin missconfigured", field: null,
}, message: "Plugin missconfigured",
]} },
/> ]}
)) />
.add("not configurable", () => ( );
<PluginsDetailsPage
{...props} export const NotConfigurable = () => (
plugin={{ <PluginsDetailsPage
...plugin, {...props}
}} plugin={{
/> ...plugin,
)); }}
/>
);

Some files were not shown because too many files have changed in this diff Show more