├── apps
├── .gitkeep
├── machines-validator
│ ├── public
│ │ ├── .gitkeep
│ │ └── logo.png
│ ├── index.d.ts
│ ├── next-env.d.ts
│ ├── specs
│ │ └── index.spec.tsx
│ ├── jest.config.ts
│ ├── next.config.js
│ ├── tsconfig.spec.json
│ ├── tsconfig.json
│ ├── .eslintrc.json
│ ├── pages
│ │ ├── _document.tsx
│ │ ├── _app.tsx
│ │ └── index.tsx
│ ├── styles
│ │ └── global.scss
│ └── project.json
└── machines-validator-e2e
│ ├── src
│ ├── support
│ │ ├── app.po.ts
│ │ ├── index.ts
│ │ └── commands.ts
│ ├── fixtures
│ │ └── example.json
│ └── integration
│ │ └── app.spec.ts
│ ├── .eslintrc.json
│ ├── tsconfig.json
│ ├── cypress.json
│ └── project.json
├── libs
├── .gitkeep
├── shared-utilities
│ ├── src
│ │ ├── index.ts
│ │ └── lib
│ │ │ └── customers.ts
│ ├── .babelrc
│ ├── README.md
│ ├── .eslintrc.json
│ ├── jest.config.ts
│ ├── tsconfig.spec.json
│ ├── tsconfig.json
│ ├── tsconfig.lib.json
│ └── project.json
├── design-system
│ ├── src
│ │ ├── index.ts
│ │ └── lib
│ │ │ ├── variables.scss
│ │ │ └── mixins.scss
│ ├── .babelrc
│ ├── README.md
│ ├── .eslintrc.json
│ ├── jest.config.ts
│ ├── tsconfig.spec.json
│ ├── tsconfig.json
│ ├── tsconfig.lib.json
│ └── project.json
├── common-layout
│ ├── .babelrc
│ ├── README.md
│ ├── src
│ │ ├── index.ts
│ │ └── lib
│ │ │ ├── form-container
│ │ │ ├── form-container.module.scss
│ │ │ ├── form-container.spec.tsx
│ │ │ └── form-container.tsx
│ │ │ ├── form-field
│ │ │ ├── form-field.spec.tsx
│ │ │ ├── form-field.module.scss
│ │ │ └── form-field.tsx
│ │ │ └── navbar
│ │ │ ├── navbar.tsx
│ │ │ ├── navbar.module.scss
│ │ │ └── navbar.spec.tsx
│ ├── .eslintrc.json
│ ├── jest.config.ts
│ ├── tsconfig.spec.json
│ ├── tsconfig.json
│ ├── tsconfig.lib.json
│ └── project.json
├── shared-components
│ ├── .babelrc
│ ├── .storybook
│ │ ├── preview.js
│ │ ├── tsconfig.json
│ │ └── main.js
│ ├── README.md
│ ├── src
│ │ ├── index.ts
│ │ └── lib
│ │ │ ├── button
│ │ │ ├── button.spec.tsx
│ │ │ ├── button.stories.tsx
│ │ │ ├── button.tsx
│ │ │ └── button.module.scss
│ │ │ ├── table
│ │ │ ├── table.spec.tsx
│ │ │ ├── table.module.scss
│ │ │ └── table.tsx
│ │ │ ├── checkbox
│ │ │ ├── checkbox.spec.tsx
│ │ │ ├── checkbox.tsx
│ │ │ └── checkbox.module.scss
│ │ │ └── dropdown
│ │ │ ├── dropdown.stories.tsx
│ │ │ ├── dropdown.module.scss
│ │ │ ├── __snapshots__
│ │ │ └── dropdown.spec.tsx.snap
│ │ │ ├── dropdown.spec.tsx
│ │ │ └── dropdown.tsx
│ ├── .eslintrc.json
│ ├── jest.config.ts
│ ├── tsconfig.spec.json
│ ├── tsconfig.json
│ ├── tsconfig.lib.json
│ └── project.json
└── shared-models
│ ├── package.json
│ ├── src
│ ├── button.model.ts
│ ├── index.ts
│ ├── table.model.ts
│ ├── dropdown.model.ts
│ ├── navbar.model.ts
│ └── customers.model.ts
│ ├── .babelrc
│ ├── tsconfig.lib.json
│ ├── tsconfig.spec.json
│ ├── README.md
│ ├── .eslintrc.json
│ ├── jest.config.ts
│ ├── tsconfig.json
│ └── project.json
├── tools
├── generators
│ └── .gitkeep
└── tsconfig.tools.json
├── .prettierrc
├── babel.config.json
├── .prettierignore
├── jest.preset.js
├── jest.config.ts
├── .vscode
└── extensions.json
├── .editorconfig
├── .storybook
├── tsconfig.json
└── main.js
├── README.md
├── zlab.code-workspace
├── workspace.json
├── .eslintrc.json
├── .gitignore
├── tsconfig.base.json
├── nx.json
└── package.json
/apps/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/libs/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tools/generators/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/apps/machines-validator/public/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "singleQuote": true
3 | }
4 |
--------------------------------------------------------------------------------
/babel.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "babelrcRoots": ["*"]
3 | }
4 |
--------------------------------------------------------------------------------
/libs/shared-utilities/src/index.ts:
--------------------------------------------------------------------------------
1 | export * from './lib/customers'
--------------------------------------------------------------------------------
/libs/design-system/src/index.ts:
--------------------------------------------------------------------------------
1 | export * from './lib/design-system';
2 |
--------------------------------------------------------------------------------
/apps/machines-validator-e2e/src/support/app.po.ts:
--------------------------------------------------------------------------------
1 | export const getGreeting = () => cy.get('h1');
2 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | # Add files here to ignore them from prettier formatting
2 |
3 | /dist
4 | /coverage
5 |
--------------------------------------------------------------------------------
/jest.preset.js:
--------------------------------------------------------------------------------
1 | const nxPreset = require('@nrwl/jest/preset').default;
2 |
3 | module.exports = { ...nxPreset };
4 |
--------------------------------------------------------------------------------
/libs/common-layout/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | "@nrwl/next/babel"
4 | ],
5 | "plugins": []
6 | }
7 |
--------------------------------------------------------------------------------
/libs/design-system/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | "@nrwl/next/babel"
4 | ],
5 | "plugins": []
6 | }
7 |
--------------------------------------------------------------------------------
/libs/shared-components/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | "@nrwl/next/babel"
4 | ],
5 | "plugins": []
6 | }
7 |
--------------------------------------------------------------------------------
/libs/shared-utilities/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | "@nrwl/next/babel"
4 | ],
5 | "plugins": []
6 | }
7 |
--------------------------------------------------------------------------------
/jest.config.ts:
--------------------------------------------------------------------------------
1 | import { getJestProjects } from '@nrwl/jest';
2 |
3 | export default {
4 | projects: getJestProjects(),
5 | };
6 |
--------------------------------------------------------------------------------
/libs/shared-models/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@zlab/shared-models",
3 | "version": "0.0.1",
4 | "type": "commonjs"
5 | }
6 |
--------------------------------------------------------------------------------
/libs/shared-models/src/button.model.ts:
--------------------------------------------------------------------------------
1 | type ButtonType = 'primary' | 'secondary' | 'mute';
2 |
3 | export type { ButtonType };
4 |
--------------------------------------------------------------------------------
/apps/machines-validator/public/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MRezaSafari/zlab-dashboard/HEAD/apps/machines-validator/public/logo.png
--------------------------------------------------------------------------------
/apps/machines-validator-e2e/src/fixtures/example.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Using fixtures to represent data",
3 | "email": "hello@cypress.io"
4 | }
5 |
--------------------------------------------------------------------------------
/libs/shared-models/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | [
4 | "@nrwl/web/babel",
5 | {
6 | "useBuiltIns": "usage"
7 | }
8 | ]
9 | ]
10 | }
11 |
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | "recommendations": [
3 | "nrwl.angular-console",
4 | "esbenp.prettier-vscode",
5 | "firsttris.vscode-jest-runner",
6 | "dbaeumer.vscode-eslint"
7 | ]
8 | }
9 |
--------------------------------------------------------------------------------
/libs/shared-models/src/index.ts:
--------------------------------------------------------------------------------
1 | export * from './navbar.model';
2 | export * from './dropdown.model';
3 | export * from './button.model';
4 | export * from './table.model';
5 | export * from './customers.model';
--------------------------------------------------------------------------------
/apps/machines-validator/index.d.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/no-explicit-any */
2 | declare module '*.svg' {
3 | const content: any;
4 | export const ReactComponent: any;
5 | export default content;
6 | }
7 |
--------------------------------------------------------------------------------
/libs/common-layout/README.md:
--------------------------------------------------------------------------------
1 | # common-layout
2 |
3 | This library was generated with [Nx](https://nx.dev).
4 |
5 | ## Running unit tests
6 |
7 | Run `nx test common-layout` to execute the unit tests via [Jest](https://jestjs.io).
8 |
--------------------------------------------------------------------------------
/libs/design-system/README.md:
--------------------------------------------------------------------------------
1 | # design-system
2 |
3 | This library was generated with [Nx](https://nx.dev).
4 |
5 | ## Running unit tests
6 |
7 | Run `nx test design-system` to execute the unit tests via [Jest](https://jestjs.io).
8 |
--------------------------------------------------------------------------------
/libs/shared-components/.storybook/preview.js:
--------------------------------------------------------------------------------
1 | // eslint-disable-next-line import/no-webpack-loader-syntax
2 | // eslint-disable-next-line @nrwl/nx/enforce-module-boundaries
3 | import '../../../apps/machines-validator/styles/global.scss';
4 |
--------------------------------------------------------------------------------
/libs/common-layout/src/index.ts:
--------------------------------------------------------------------------------
1 | export { default as Navbar } from './lib/navbar/navbar';
2 | export { default as FormField } from './lib/form-field/form-field';
3 | export { default as FormContainer } from './lib/form-container/form-container';
4 |
--------------------------------------------------------------------------------
/libs/shared-components/README.md:
--------------------------------------------------------------------------------
1 | # shared-components
2 |
3 | This library was generated with [Nx](https://nx.dev).
4 |
5 | ## Running unit tests
6 |
7 | Run `nx test shared-components` to execute the unit tests via [Jest](https://jestjs.io).
8 |
--------------------------------------------------------------------------------
/libs/shared-utilities/README.md:
--------------------------------------------------------------------------------
1 | # shared-utilities
2 |
3 | This library was generated with [Nx](https://nx.dev).
4 |
5 | ## Running unit tests
6 |
7 | Run `nx test shared-utilities` to execute the unit tests via [Jest](https://jestjs.io).
8 |
--------------------------------------------------------------------------------
/apps/machines-validator/next-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 | ///
3 |
4 | // NOTE: This file should not be edited
5 | // see https://nextjs.org/docs/basic-features/typescript for more information.
6 |
--------------------------------------------------------------------------------
/libs/shared-components/src/index.ts:
--------------------------------------------------------------------------------
1 | export { default as Button } from './lib/button/button';
2 | export { default as Dropdown } from './lib/dropdown/dropdown';
3 | export { default as Checkbox } from './lib/checkbox/checkbox';
4 | export { default as Table } from './lib/table/table';
5 |
--------------------------------------------------------------------------------
/apps/machines-validator-e2e/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": ["plugin:cypress/recommended", "../../.eslintrc.json"],
3 | "ignorePatterns": ["!**/*"],
4 | "overrides": [
5 | {
6 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
7 | "rules": {}
8 | }
9 | ]
10 | }
11 |
--------------------------------------------------------------------------------
/libs/shared-models/src/table.model.ts:
--------------------------------------------------------------------------------
1 | type ColumnType = 'string' | 'boolean';
2 |
3 | interface ColumnTemplate {
4 | title: string;
5 | width: string;
6 | type: ColumnType;
7 | valueKey: string;
8 | sortable: boolean;
9 | }
10 |
11 | export type { ColumnTemplate, ColumnType };
12 |
--------------------------------------------------------------------------------
/libs/common-layout/src/lib/form-container/form-container.module.scss:
--------------------------------------------------------------------------------
1 | @import '/libs/design-system/src/lib/mixins.scss';
2 |
3 |
4 | .container {
5 | display: flex;
6 | gap: 2.5rem;
7 | flex-wrap: wrap;
8 |
9 | @include mobile(){
10 | flex-direction: column;
11 | }
12 | }
--------------------------------------------------------------------------------
/libs/shared-models/tsconfig.lib.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "../../dist/out-tsc",
5 | "declaration": true,
6 | "types": []
7 | },
8 | "include": ["**/*.ts"],
9 | "exclude": ["jest.config.ts", "**/*.spec.ts", "**/*.test.ts"]
10 | }
11 |
--------------------------------------------------------------------------------
/libs/shared-models/tsconfig.spec.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "../../dist/out-tsc",
5 | "module": "commonjs",
6 | "types": ["jest", "node"]
7 | },
8 | "include": ["jest.config.ts", "**/*.test.ts", "**/*.spec.ts", "**/*.d.ts"]
9 | }
10 |
--------------------------------------------------------------------------------
/apps/machines-validator-e2e/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.base.json",
3 | "compilerOptions": {
4 | "sourceMap": false,
5 | "outDir": "../../dist/out-tsc",
6 | "allowJs": true,
7 | "types": ["cypress", "node"]
8 | },
9 | "include": ["src/**/*.ts", "src/**/*.js"]
10 | }
11 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # Editor configuration, see http://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | charset = utf-8
6 | indent_style = space
7 | indent_size = 2
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
11 | [*.md]
12 | max_line_length = off
13 | trim_trailing_whitespace = false
14 |
--------------------------------------------------------------------------------
/libs/design-system/src/lib/variables.scss:
--------------------------------------------------------------------------------
1 | $font_primary: Roboto;
2 | $color_primary: #ffcf54;
3 | $color_secondary: #ff7433;
4 | $color_background: #1b1724;
5 | $color_title: #ecd8bd;
6 | $color_text: #fff;
7 | $color_danger: #ee5749;
8 | $color_warning: #fbc654;
9 | $color_info: #6abfed;
10 | $color_success: #03996e;
11 |
--------------------------------------------------------------------------------
/libs/shared-models/README.md:
--------------------------------------------------------------------------------
1 | # shared-models
2 |
3 | This library was generated with [Nx](https://nx.dev).
4 |
5 | ## Building
6 |
7 | Run `nx build shared-models` to build the library.
8 |
9 | ## Running unit tests
10 |
11 | Run `nx test shared-models` to execute the unit tests via [Jest](https://jestjs.io).
12 |
--------------------------------------------------------------------------------
/tools/tsconfig.tools.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.base.json",
3 | "compilerOptions": {
4 | "outDir": "../dist/out-tsc/tools",
5 | "rootDir": ".",
6 | "module": "commonjs",
7 | "target": "es5",
8 | "types": ["node"],
9 | "importHelpers": false
10 | },
11 | "include": ["**/*.ts"]
12 | }
13 |
--------------------------------------------------------------------------------
/.storybook/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.base.json",
3 | "exclude": [
4 | "../**/*.spec.js",
5 | "../**/*.test.js",
6 | "../**/*.spec.ts",
7 | "../**/*.test.ts",
8 | "../**/*.spec.tsx",
9 | "../**/*.test.tsx",
10 | "../**/*.spec.jsx",
11 | "../**/*.test.jsx"
12 | ],
13 | "include": ["../**/*"]
14 | }
15 |
--------------------------------------------------------------------------------
/libs/shared-components/src/lib/button/button.spec.tsx:
--------------------------------------------------------------------------------
1 | import { render } from '@testing-library/react';
2 |
3 | import Button from './button';
4 |
5 | describe('Button', () => {
6 | it('should render successfully', () => {
7 | const { baseElement } = render();
8 | expect(baseElement).toBeTruthy();
9 | });
10 | });
11 |
--------------------------------------------------------------------------------
/libs/shared-components/src/lib/table/table.spec.tsx:
--------------------------------------------------------------------------------
1 | import { render } from '@testing-library/react';
2 |
3 | import Table from './table';
4 |
5 | describe('Table', () => {
6 | it('should render successfully', () => {
7 | const { baseElement } = render(
);
8 | expect(baseElement).toBeTruthy();
9 | });
10 | });
11 |
--------------------------------------------------------------------------------
/libs/design-system/src/lib/mixins.scss:
--------------------------------------------------------------------------------
1 | @mixin mobile() {
2 | @media (max-width: 767px) {
3 | @content;
4 | }
5 | }
6 |
7 | @mixin tablet() {
8 | @media (min-width: 768px) and (max-width: 1319px) {
9 | @content;
10 | }
11 | }
12 |
13 | @mixin desktop() {
14 | @media (min-width: 1320px) {
15 | @content;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/libs/shared-models/src/dropdown.model.ts:
--------------------------------------------------------------------------------
1 | interface IDropdownProps {
2 | initialValue?: string;
3 | options: IDropdownOption[];
4 | minimumSearchLength?: number;
5 | onChange: (value: string) => void;
6 | }
7 |
8 | interface IDropdownOption {
9 | id: number;
10 | label: string;
11 | value: string;
12 | }
13 |
14 | export type { IDropdownOption, IDropdownProps };
15 |
--------------------------------------------------------------------------------
/libs/common-layout/src/lib/form-field/form-field.spec.tsx:
--------------------------------------------------------------------------------
1 | import { render } from '@testing-library/react';
2 |
3 | import FormField from './form-field';
4 |
5 | describe('FormField', () => {
6 | it('should render successfully', () => {
7 | const { baseElement } = render();
8 | expect(baseElement).toBeTruthy();
9 | });
10 | });
11 |
--------------------------------------------------------------------------------
/libs/common-layout/src/lib/form-container/form-container.spec.tsx:
--------------------------------------------------------------------------------
1 | import { render } from '@testing-library/react';
2 |
3 | import FormContainer from './form-container';
4 |
5 | describe('FormContainer', () => {
6 | it('should render successfully', () => {
7 | const { baseElement } = render();
8 | expect(baseElement).toBeTruthy();
9 | });
10 | });
11 |
--------------------------------------------------------------------------------
/libs/shared-components/src/lib/checkbox/checkbox.spec.tsx:
--------------------------------------------------------------------------------
1 | import { render } from '@testing-library/react';
2 |
3 | import Checkbox from './checkbox';
4 |
5 | describe('Checkbox', () => {
6 | it('should render successfully', () => {
7 | const { baseElement } = render( {console.log(v)}} title="checkbox" />);
8 | expect(baseElement).toBeTruthy();
9 | });
10 | });
11 |
--------------------------------------------------------------------------------
/libs/shared-models/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": ["../../.eslintrc.json"],
3 | "ignorePatterns": ["!**/*"],
4 | "overrides": [
5 | {
6 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
7 | "rules": {}
8 | },
9 | {
10 | "files": ["*.ts", "*.tsx"],
11 | "rules": {}
12 | },
13 | {
14 | "files": ["*.js", "*.jsx"],
15 | "rules": {}
16 | }
17 | ]
18 | }
19 |
--------------------------------------------------------------------------------
/apps/machines-validator/specs/index.spec.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import { render } from '@testing-library/react';
4 |
5 | import Index from '../pages/index';
6 |
7 | describe('Index', () => {
8 | it('should render successfully', () => {
9 | const { baseElement } = render();
10 | expect(baseElement).toBeTruthy();
11 | });
12 | });
13 |
--------------------------------------------------------------------------------
/libs/common-layout/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": ["plugin:@nrwl/nx/react", "../../.eslintrc.json"],
3 | "ignorePatterns": ["!**/*"],
4 | "overrides": [
5 | {
6 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
7 | "rules": {}
8 | },
9 | {
10 | "files": ["*.ts", "*.tsx"],
11 | "rules": {}
12 | },
13 | {
14 | "files": ["*.js", "*.jsx"],
15 | "rules": {}
16 | }
17 | ]
18 | }
19 |
--------------------------------------------------------------------------------
/libs/design-system/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": ["plugin:@nrwl/nx/react", "../../.eslintrc.json"],
3 | "ignorePatterns": ["!**/*"],
4 | "overrides": [
5 | {
6 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
7 | "rules": {}
8 | },
9 | {
10 | "files": ["*.ts", "*.tsx"],
11 | "rules": {}
12 | },
13 | {
14 | "files": ["*.js", "*.jsx"],
15 | "rules": {}
16 | }
17 | ]
18 | }
19 |
--------------------------------------------------------------------------------
/libs/shared-utilities/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": ["plugin:@nrwl/nx/react", "../../.eslintrc.json"],
3 | "ignorePatterns": ["!**/*"],
4 | "overrides": [
5 | {
6 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
7 | "rules": {}
8 | },
9 | {
10 | "files": ["*.ts", "*.tsx"],
11 | "rules": {}
12 | },
13 | {
14 | "files": ["*.js", "*.jsx"],
15 | "rules": {}
16 | }
17 | ]
18 | }
19 |
--------------------------------------------------------------------------------
/.storybook/main.js:
--------------------------------------------------------------------------------
1 |
2 | module.exports = {
3 | stories: [],
4 | addons: ['@storybook/addon-essentials'],
5 | // uncomment the property below if you want to apply some webpack config globally
6 | // webpackFinal: async (config, { configType }) => {
7 | // // Make whatever fine-grained changes you need that should apply to all storybook configs
8 |
9 | // // Return the altered config
10 | // return config;
11 | // },
12 | };
13 |
--------------------------------------------------------------------------------
/libs/shared-components/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": ["plugin:@nrwl/nx/react", "../../.eslintrc.json"],
3 | "ignorePatterns": ["!**/*"],
4 | "overrides": [
5 | {
6 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
7 | "rules": {}
8 | },
9 | {
10 | "files": ["*.ts", "*.tsx"],
11 | "rules": {}
12 | },
13 | {
14 | "files": ["*.js", "*.jsx"],
15 | "rules": {}
16 | }
17 | ]
18 | }
19 |
--------------------------------------------------------------------------------
/libs/shared-models/jest.config.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | export default {
3 | displayName: 'shared-models',
4 | preset: '../../jest.preset.js',
5 | globals: {
6 | 'ts-jest': {
7 | tsconfig: '/tsconfig.spec.json',
8 | },
9 | },
10 | transform: {
11 | '^.+\\.[tj]s$': 'ts-jest',
12 | },
13 | moduleFileExtensions: ['ts', 'js', 'html'],
14 | coverageDirectory: '../../coverage/libs/shared-models',
15 | };
16 |
--------------------------------------------------------------------------------
/libs/shared-models/src/navbar.model.ts:
--------------------------------------------------------------------------------
1 | enum AnchorTagTarget {
2 | BLANK = '_blank',
3 | SELF = '_self',
4 | PARENT = '_parent',
5 | TOP = '_top',
6 | }
7 |
8 | interface INavbarProps {
9 | navbarItems: INavbar[];
10 | }
11 |
12 | interface INavbar {
13 | id: number;
14 | title: string;
15 | href: string;
16 | target: AnchorTagTarget;
17 | }
18 |
19 | export { AnchorTagTarget };
20 |
21 | export type { INavbar, INavbarProps };
22 |
--------------------------------------------------------------------------------
/libs/common-layout/jest.config.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | export default {
3 | displayName: 'common-layout',
4 | preset: '../../jest.preset.js',
5 | globals: {
6 | 'ts-jest': {
7 | tsconfig: '/tsconfig.spec.json',
8 | },
9 | },
10 | transform: {
11 | '^.+\\.[tj]sx?$': 'ts-jest',
12 | },
13 | moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
14 | coverageDirectory: '../../coverage/libs/common-layout',
15 | };
16 |
--------------------------------------------------------------------------------
/libs/design-system/jest.config.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | export default {
3 | displayName: 'design-system',
4 | preset: '../../jest.preset.js',
5 | globals: {
6 | 'ts-jest': {
7 | tsconfig: '/tsconfig.spec.json',
8 | },
9 | },
10 | transform: {
11 | '^.+\\.[tj]sx?$': 'ts-jest',
12 | },
13 | moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
14 | coverageDirectory: '../../coverage/libs/design-system',
15 | };
16 |
--------------------------------------------------------------------------------
/libs/shared-utilities/jest.config.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | export default {
3 | displayName: 'shared-utilities',
4 | preset: '../../jest.preset.js',
5 | globals: {
6 | 'ts-jest': {
7 | tsconfig: '/tsconfig.spec.json',
8 | },
9 | },
10 | transform: {
11 | '^.+\\.[tj]sx?$': 'ts-jest',
12 | },
13 | moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
14 | coverageDirectory: '../../coverage/libs/shared-utilities',
15 | };
16 |
--------------------------------------------------------------------------------
/libs/shared-components/jest.config.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | export default {
3 | displayName: 'shared-components',
4 | preset: '../../jest.preset.js',
5 | globals: {
6 | 'ts-jest': {
7 | tsconfig: '/tsconfig.spec.json',
8 | },
9 | },
10 | transform: {
11 | '^.+\\.[tj]sx?$': 'ts-jest',
12 | },
13 | moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
14 | coverageDirectory: '../../coverage/libs/shared-components',
15 | };
16 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ## Z-Lab Machines Validator Dashboard
4 | dashboard for validating machines and serial numbers
5 |
6 | eveything in UI part made from scratch by myself.
7 | I created this as an interview assignment for zlab but they didn't even bother to check the code and started asking stupid questions.
8 |
9 | ## Techs:
10 |
11 | * NX Mono Repo
12 | * Nextjs 12
13 | * Jest
14 | * React-Testing-Library
15 |
16 | ## Live Demo
17 | https://zlab.vercel.app
18 |
19 |
--------------------------------------------------------------------------------
/apps/machines-validator/jest.config.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | export default {
3 | displayName: 'machines-validator',
4 | preset: '../../jest.preset.js',
5 | transform: {
6 | '^(?!.*\\.(js|jsx|ts|tsx|css|json)$)': '@nrwl/react/plugins/jest',
7 | '^.+\\.[tj]sx?$': ['babel-jest', { presets: ['@nrwl/next/babel'] }],
8 | },
9 | moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
10 | coverageDirectory: '../../coverage/apps/machines-validator',
11 | };
12 |
--------------------------------------------------------------------------------
/apps/machines-validator/next.config.js:
--------------------------------------------------------------------------------
1 | // eslint-disable-next-line @typescript-eslint/no-var-requires
2 | const withNx = require('@nrwl/next/plugins/with-nx');
3 |
4 | /**
5 | * @type {import('@nrwl/next/plugins/with-nx').WithNxOptions}
6 | **/
7 | const nextConfig = {
8 | nx: {
9 | // Set this to true if you would like to to use SVGR
10 | // See: https://github.com/gregberge/svgr
11 | svgr: false,
12 | },
13 | };
14 |
15 | module.exports = withNx(nextConfig);
16 |
--------------------------------------------------------------------------------
/libs/common-layout/src/lib/form-field/form-field.module.scss:
--------------------------------------------------------------------------------
1 | @import '/libs/design-system/src/lib/variables.scss';
2 | @import '/libs/design-system/src/lib/mixins.scss';
3 |
4 | .container {
5 | display: flex;
6 | flex-direction: column;
7 | justify-content: space-between;
8 | gap: 1.5rem;
9 | > p {
10 | color: $color_title;
11 | font-size: 1.8rem;
12 | font-weight: 400;
13 | letter-spacing: .1rem;
14 | }
15 | }
16 |
17 | .field-container {
18 | }
19 |
--------------------------------------------------------------------------------
/libs/shared-components/src/lib/button/button.stories.tsx:
--------------------------------------------------------------------------------
1 | import {
2 | Meta,
3 | Story,
4 | } from '@storybook/react/types-6-0';
5 |
6 | import Button from './button';
7 |
8 | export default {
9 | title: 'UI Components',
10 | component: Button,
11 | } as Meta;
12 |
13 | const Template: Story = ({ children }) => ;
14 |
15 | export const primary = Template.bind({});
16 | primary.args = { children: 'Custom Button' };
17 | primary.storyName = 'Button';
18 |
--------------------------------------------------------------------------------
/libs/common-layout/src/lib/form-container/form-container.tsx:
--------------------------------------------------------------------------------
1 | import { ReactNode } from 'react';
2 |
3 | import styles from './form-container.module.scss';
4 |
5 | /* eslint-disable-next-line */
6 | export interface FormContainerProps {
7 | children: ReactNode;
8 | }
9 |
10 | export function FormContainer(props: FormContainerProps) {
11 | return (
12 |
13 | {props.children}
14 |
15 | );
16 | }
17 |
18 | export default FormContainer;
19 |
--------------------------------------------------------------------------------
/libs/shared-models/src/customers.model.ts:
--------------------------------------------------------------------------------
1 | interface ICustomer {
2 |
3 | id: number;
4 | guid: string;
5 | customer: string;
6 | asset_type: string;
7 | serial_number: string;
8 | service_contract: boolean;
9 | warranty: boolean;
10 |
11 | }
12 |
13 | interface IFilters {
14 | customer: string;
15 | asset_type: string;
16 | service_contract: boolean;
17 | warranty: boolean;
18 | serial_number: string;
19 | }
20 |
21 | export type { ICustomer, IFilters };
22 |
--------------------------------------------------------------------------------
/libs/shared-utilities/tsconfig.spec.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "../../dist/out-tsc",
5 | "module": "commonjs",
6 | "types": ["jest", "node"]
7 | },
8 | "include": [
9 | "jest.config.ts",
10 | "**/*.test.ts",
11 | "**/*.spec.ts",
12 | "**/*.test.tsx",
13 | "**/*.spec.tsx",
14 | "**/*.test.js",
15 | "**/*.spec.js",
16 | "**/*.test.jsx",
17 | "**/*.spec.jsx",
18 | "**/*.d.ts"
19 | ]
20 | }
21 |
--------------------------------------------------------------------------------
/apps/machines-validator-e2e/cypress.json:
--------------------------------------------------------------------------------
1 | {
2 | "fileServerFolder": ".",
3 | "fixturesFolder": "./src/fixtures",
4 | "integrationFolder": "./src/integration",
5 | "modifyObstructiveCode": false,
6 | "supportFile": "./src/support/index.ts",
7 | "pluginsFile": false,
8 | "video": true,
9 | "videosFolder": "../../dist/cypress/apps/machines-validator-e2e/videos",
10 | "screenshotsFolder": "../../dist/cypress/apps/machines-validator-e2e/screenshots",
11 | "chromeWebSecurity": false
12 | }
13 |
--------------------------------------------------------------------------------
/zlab.code-workspace:
--------------------------------------------------------------------------------
1 | {
2 | "folders": [
3 | {
4 | "path": "."
5 | }
6 | ],
7 | "settings": {
8 | "files.exclude": {
9 | "**/.git": true,
10 | "**/.svn": true,
11 | "**/.hg": true,
12 | "**/CVS": true,
13 | "**/.DS_Store": true,
14 | "**/Thumbs.db": true,
15 | "**/node_modules": true,
16 | "node_modules": true,
17 | "**/dist": true,
18 | "dist": true
19 | },
20 | "explorerExclude.backup": null,
21 | "typescript.tsdk": "node_modules/typescript/lib"
22 | }
23 | }
--------------------------------------------------------------------------------
/workspace.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "./node_modules/nx/schemas/workspace-schema.json",
3 | "version": 2,
4 | "projects": {
5 | "common-layout": "libs/common-layout",
6 | "design-system": "libs/design-system",
7 | "machines-validator": "apps/machines-validator",
8 | "machines-validator-e2e": "apps/machines-validator-e2e",
9 | "shared-components": "libs/shared-components",
10 | "shared-models": "libs/shared-models",
11 | "shared-utilities": "libs/shared-utilities"
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/apps/machines-validator-e2e/src/integration/app.spec.ts:
--------------------------------------------------------------------------------
1 | import { getGreeting } from '../support/app.po';
2 |
3 | describe('machines-validator', () => {
4 | beforeEach(() => cy.visit('/'));
5 |
6 | it('should display welcome message', () => {
7 | // Custom command example, see `../support/commands.ts` file
8 | cy.login('my-email@something.com', 'myPassword');
9 |
10 | // Function helper example, see `../support/app.po.ts` file
11 | getGreeting().contains('Welcome machines-validator');
12 | });
13 | });
14 |
--------------------------------------------------------------------------------
/apps/machines-validator/tsconfig.spec.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "../../dist/out-tsc",
5 | "module": "commonjs",
6 | "types": ["jest", "node"],
7 | "jsx": "react"
8 | },
9 | "include": [
10 | "jest.config.ts",
11 | "**/*.test.ts",
12 | "**/*.spec.ts",
13 | "**/*.test.tsx",
14 | "**/*.spec.tsx",
15 | "**/*.test.js",
16 | "**/*.spec.js",
17 | "**/*.test.jsx",
18 | "**/*.spec.jsx",
19 | "**/*.d.ts"
20 | ]
21 | }
22 |
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "root": true,
3 | "ignorePatterns": ["**/*"],
4 | "plugins": ["@nrwl/nx"],
5 | "overrides": [
6 | {
7 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"]
8 | },
9 | {
10 | "files": ["*.ts", "*.tsx"],
11 | "extends": ["plugin:@nrwl/nx/typescript"],
12 | "rules": {
13 | "@typescript-eslint/ban-ts-comment": "off"
14 | }
15 | },
16 | {
17 | "files": ["*.js", "*.jsx"],
18 | "extends": ["plugin:@nrwl/nx/javascript"],
19 | "rules": {}
20 | }
21 | ]
22 | }
23 |
--------------------------------------------------------------------------------
/libs/common-layout/src/lib/form-field/form-field.tsx:
--------------------------------------------------------------------------------
1 | import { ReactNode } from 'react';
2 |
3 | import styles from './form-field.module.scss';
4 |
5 | /* eslint-disable-next-line */
6 | export interface FormFieldProps {
7 | children: ReactNode;
8 | title: string;
9 | }
10 |
11 | export function FormField(props: FormFieldProps) {
12 | return (
13 |
14 |
{props.title}
15 |
{props.children}
16 |
17 | );
18 | }
19 |
20 | export default FormField;
21 |
--------------------------------------------------------------------------------
/libs/shared-models/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.base.json",
3 | "compilerOptions": {
4 | "module": "commonjs",
5 | "forceConsistentCasingInFileNames": true,
6 | "strict": true,
7 | "noImplicitOverride": true,
8 | "noPropertyAccessFromIndexSignature": true,
9 | "noImplicitReturns": true,
10 | "noFallthroughCasesInSwitch": true
11 | },
12 | "files": [],
13 | "include": [],
14 | "references": [
15 | {
16 | "path": "./tsconfig.lib.json"
17 | },
18 | {
19 | "path": "./tsconfig.spec.json"
20 | }
21 | ]
22 | }
23 |
--------------------------------------------------------------------------------
/libs/shared-components/.storybook/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.json",
3 | "compilerOptions": {
4 | "emitDecoratorMetadata": true,
5 | "outDir": ""
6 | },
7 | "files": [
8 | "../../../node_modules/@nrwl/react/typings/styled-jsx.d.ts",
9 | "../../../node_modules/@nrwl/react/typings/cssmodule.d.ts",
10 | "../../../node_modules/@nrwl/react/typings/image.d.ts"
11 | ],
12 | "exclude": [
13 | "../**/*.spec.ts",
14 | "../**/*.spec.js",
15 | "../**/*.spec.tsx",
16 | "../**/*.spec.jsx"
17 | ],
18 | "include": ["../src/**/*", "*.js"]
19 | }
20 |
--------------------------------------------------------------------------------
/apps/machines-validator/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.base.json",
3 | "compilerOptions": {
4 | "jsx": "preserve",
5 | "allowJs": true,
6 | "esModuleInterop": true,
7 | "allowSyntheticDefaultImports": true,
8 | "strict": false,
9 | "forceConsistentCasingInFileNames": true,
10 | "noEmit": true,
11 | "resolveJsonModule": true,
12 | "isolatedModules": true,
13 | "incremental": true,
14 | "types": ["jest", "node"]
15 | },
16 | "include": ["**/*.ts", "**/*.tsx", "**/*.js", "**/*.jsx", "next-env.d.ts"],
17 | "exclude": ["node_modules", "jest.config.ts"]
18 | }
19 |
--------------------------------------------------------------------------------
/libs/common-layout/tsconfig.spec.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "../../dist/out-tsc",
5 | "module": "commonjs",
6 | "types": ["jest", "node"]
7 | },
8 | "files": [
9 | "../../node_modules/@nrwl/react/typings/cssmodule.d.ts",
10 | "../../node_modules/@nrwl/next/typings/image.d.ts"
11 | ],
12 | "include": [
13 | "jest.config.ts",
14 | "**/*.test.ts",
15 | "**/*.spec.ts",
16 | "**/*.test.tsx",
17 | "**/*.spec.tsx",
18 | "**/*.test.js",
19 | "**/*.spec.js",
20 | "**/*.test.jsx",
21 | "**/*.spec.jsx",
22 | "**/*.d.ts"
23 | ]
24 | }
25 |
--------------------------------------------------------------------------------
/libs/design-system/tsconfig.spec.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "../../dist/out-tsc",
5 | "module": "commonjs",
6 | "types": ["jest", "node"]
7 | },
8 | "files": [
9 | "../../node_modules/@nrwl/react/typings/cssmodule.d.ts",
10 | "../../node_modules/@nrwl/next/typings/image.d.ts"
11 | ],
12 | "include": [
13 | "jest.config.ts",
14 | "**/*.test.ts",
15 | "**/*.spec.ts",
16 | "**/*.test.tsx",
17 | "**/*.spec.tsx",
18 | "**/*.test.js",
19 | "**/*.spec.js",
20 | "**/*.test.jsx",
21 | "**/*.spec.jsx",
22 | "**/*.d.ts"
23 | ]
24 | }
25 |
--------------------------------------------------------------------------------
/libs/shared-components/src/lib/button/button.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import { ButtonType } from '@zlab/shared-models';
4 |
5 | import styles from './button.module.scss';
6 |
7 | export interface ButtonProps {
8 | children: React.ReactNode;
9 | onClick?: () => void;
10 | type?: ButtonType;
11 | }
12 |
13 | export function Button({ children, onClick, type = 'primary' }: ButtonProps) {
14 | return (
15 |
21 | );
22 | }
23 |
24 | export default Button;
25 |
--------------------------------------------------------------------------------
/libs/shared-components/tsconfig.spec.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "../../dist/out-tsc",
5 | "module": "commonjs",
6 | "types": ["jest", "node", "testing-library__jest-dom"]
7 | },
8 | "files": [
9 | "../../node_modules/@nrwl/react/typings/cssmodule.d.ts",
10 | "../../node_modules/@nrwl/next/typings/image.d.ts"
11 | ],
12 | "include": [
13 | "jest.config.ts",
14 | "**/*.test.ts",
15 | "**/*.spec.ts",
16 | "**/*.test.tsx",
17 | "**/*.spec.tsx",
18 | "**/*.test.js",
19 | "**/*.spec.js",
20 | "**/*.test.jsx",
21 | "**/*.spec.jsx",
22 | "**/*.d.ts"
23 | ]
24 | }
25 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See http://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # compiled output
4 | /dist
5 | /tmp
6 | /out-tsc
7 |
8 | # dependencies
9 | node_modules
10 |
11 | # IDEs and editors
12 | /.idea
13 | .project
14 | .classpath
15 | .c9/
16 | *.launch
17 | .settings/
18 | *.sublime-workspace
19 |
20 | # IDE - VSCode
21 | .vscode/*
22 | !.vscode/settings.json
23 | !.vscode/tasks.json
24 | !.vscode/launch.json
25 | !.vscode/extensions.json
26 |
27 | # misc
28 | /.sass-cache
29 | /connect.lock
30 | /coverage
31 | /libpeerconnection.log
32 | npm-debug.log
33 | yarn-error.log
34 | testem.log
35 | /typings
36 |
37 | # System Files
38 | .DS_Store
39 | Thumbs.db
40 |
--------------------------------------------------------------------------------
/libs/common-layout/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.base.json",
3 | "compilerOptions": {
4 | "jsx": "react-jsx",
5 | "allowJs": true,
6 | "esModuleInterop": true,
7 | "allowSyntheticDefaultImports": true,
8 | "forceConsistentCasingInFileNames": true,
9 | "strict": true,
10 | "noImplicitOverride": true,
11 | "noPropertyAccessFromIndexSignature": true,
12 | "noImplicitReturns": true,
13 | "noFallthroughCasesInSwitch": true
14 | },
15 | "files": [],
16 | "include": [],
17 | "references": [
18 | {
19 | "path": "./tsconfig.lib.json"
20 | },
21 | {
22 | "path": "./tsconfig.spec.json"
23 | }
24 | ]
25 | }
26 |
--------------------------------------------------------------------------------
/libs/design-system/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.base.json",
3 | "compilerOptions": {
4 | "jsx": "react-jsx",
5 | "allowJs": true,
6 | "esModuleInterop": true,
7 | "allowSyntheticDefaultImports": true,
8 | "forceConsistentCasingInFileNames": true,
9 | "strict": true,
10 | "noImplicitOverride": true,
11 | "noPropertyAccessFromIndexSignature": true,
12 | "noImplicitReturns": true,
13 | "noFallthroughCasesInSwitch": true
14 | },
15 | "files": [],
16 | "include": [],
17 | "references": [
18 | {
19 | "path": "./tsconfig.lib.json"
20 | },
21 | {
22 | "path": "./tsconfig.spec.json"
23 | }
24 | ]
25 | }
26 |
--------------------------------------------------------------------------------
/libs/shared-utilities/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.base.json",
3 | "compilerOptions": {
4 | "jsx": "react-jsx",
5 | "allowJs": true,
6 | "esModuleInterop": true,
7 | "allowSyntheticDefaultImports": true,
8 | "forceConsistentCasingInFileNames": true,
9 | "strict": true,
10 | "noImplicitOverride": true,
11 | "noPropertyAccessFromIndexSignature": true,
12 | "noImplicitReturns": true,
13 | "noFallthroughCasesInSwitch": true
14 | },
15 | "files": [],
16 | "include": [],
17 | "references": [
18 | {
19 | "path": "./tsconfig.lib.json"
20 | },
21 | {
22 | "path": "./tsconfig.spec.json"
23 | }
24 | ]
25 | }
26 |
--------------------------------------------------------------------------------
/apps/machines-validator-e2e/src/support/index.ts:
--------------------------------------------------------------------------------
1 | // ***********************************************************
2 | // This example support/index.js is processed and
3 | // loaded automatically before your test files.
4 | //
5 | // This is a great place to put global configuration and
6 | // behavior that modifies Cypress.
7 | //
8 | // You can change the location of this file or turn off
9 | // automatically serving support files with the
10 | // 'supportFile' configuration option.
11 | //
12 | // You can read more here:
13 | // https://on.cypress.io/configuration
14 | // ***********************************************************
15 |
16 | // Import commands.js using ES2015 syntax:
17 | import './commands';
18 |
--------------------------------------------------------------------------------
/libs/common-layout/tsconfig.lib.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "../../dist/out-tsc",
5 | "types": [
6 | "node"
7 | ]
8 | },
9 | "files": [
10 | "../../node_modules/@nrwl/react/typings/cssmodule.d.ts",
11 | "../../node_modules/@nrwl/next/typings/image.d.ts",
12 | ],
13 | "exclude": [
14 | "jest.config.ts",
15 | "**/*.spec.ts",
16 | "**/*.test.ts",
17 | "**/*.spec.tsx",
18 | "**/*.test.tsx",
19 | "**/*.spec.js",
20 | "**/*.test.js",
21 | "**/*.spec.jsx",
22 | "**/*.test.jsx"
23 | ],
24 | "include": [
25 | "**/*.js",
26 | "**/*.jsx",
27 | "**/*.ts",
28 | "**/*.tsx"
29 | ]
30 | }
31 |
--------------------------------------------------------------------------------
/libs/design-system/tsconfig.lib.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "../../dist/out-tsc",
5 | "types": [
6 | "node"
7 | ]
8 | },
9 | "files": [
10 | "../../node_modules/@nrwl/react/typings/cssmodule.d.ts",
11 | "../../node_modules/@nrwl/next/typings/image.d.ts"
12 | ],
13 | "exclude": [
14 | "jest.config.ts",
15 | "**/*.spec.ts",
16 | "**/*.test.ts",
17 | "**/*.spec.tsx",
18 | "**/*.test.tsx",
19 | "**/*.spec.js",
20 | "**/*.test.js",
21 | "**/*.spec.jsx",
22 | "**/*.test.jsx"
23 | ],
24 | "include": [
25 | "**/*.js",
26 | "**/*.jsx",
27 | "**/*.ts",
28 | "**/*.tsx"
29 | ]
30 | }
31 |
--------------------------------------------------------------------------------
/libs/shared-utilities/tsconfig.lib.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "../../dist/out-tsc",
5 | "types": [
6 | "node"
7 | ]
8 | },
9 | "files": [
10 | "../../node_modules/@nrwl/react/typings/cssmodule.d.ts",
11 | "../../node_modules/@nrwl/next/typings/image.d.ts"
12 | ],
13 | "exclude": [
14 | "jest.config.ts",
15 | "**/*.spec.ts",
16 | "**/*.test.ts",
17 | "**/*.spec.tsx",
18 | "**/*.test.tsx",
19 | "**/*.spec.js",
20 | "**/*.test.js",
21 | "**/*.spec.jsx",
22 | "**/*.test.jsx"
23 | ],
24 | "include": [
25 | "**/*.js",
26 | "**/*.jsx",
27 | "**/*.ts",
28 | "**/*.tsx"
29 | ]
30 | }
31 |
--------------------------------------------------------------------------------
/apps/machines-validator/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": [
3 | "plugin:@nrwl/nx/react-typescript",
4 | "../../.eslintrc.json",
5 | "next",
6 | "next/core-web-vitals"
7 | ],
8 | "ignorePatterns": ["!**/*"],
9 | "overrides": [
10 | {
11 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
12 | "rules": {
13 | "@next/next/no-html-link-for-pages": [
14 | "error",
15 | "apps/machines-validator/pages"
16 | ]
17 | }
18 | },
19 | {
20 | "files": ["*.ts", "*.tsx"],
21 | "rules": {}
22 | },
23 | {
24 | "files": ["*.js", "*.jsx"],
25 | "rules": {}
26 | }
27 | ],
28 | "env": {
29 | "jest": true
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/libs/common-layout/project.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "../../node_modules/nx/schemas/project-schema.json",
3 | "sourceRoot": "libs/common-layout/src",
4 | "projectType": "library",
5 | "tags": [],
6 | "targets": {
7 | "lint": {
8 | "executor": "@nrwl/linter:eslint",
9 | "outputs": ["{options.outputFile}"],
10 | "options": {
11 | "lintFilePatterns": ["libs/common-layout/**/*.{ts,tsx,js,jsx}"]
12 | }
13 | },
14 | "test": {
15 | "executor": "@nrwl/jest:jest",
16 | "outputs": ["coverage/libs/common-layout"],
17 | "options": {
18 | "jestConfig": "libs/common-layout/jest.config.ts",
19 | "passWithNoTests": true
20 | }
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/libs/design-system/project.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "../../node_modules/nx/schemas/project-schema.json",
3 | "sourceRoot": "libs/design-system/src",
4 | "projectType": "library",
5 | "tags": [],
6 | "targets": {
7 | "lint": {
8 | "executor": "@nrwl/linter:eslint",
9 | "outputs": ["{options.outputFile}"],
10 | "options": {
11 | "lintFilePatterns": ["libs/design-system/**/*.{ts,tsx,js,jsx}"]
12 | }
13 | },
14 | "test": {
15 | "executor": "@nrwl/jest:jest",
16 | "outputs": ["coverage/libs/design-system"],
17 | "options": {
18 | "jestConfig": "libs/design-system/jest.config.ts",
19 | "passWithNoTests": true
20 | }
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/libs/shared-utilities/project.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "../../node_modules/nx/schemas/project-schema.json",
3 | "sourceRoot": "libs/shared-utilities/src",
4 | "projectType": "library",
5 | "tags": [],
6 | "targets": {
7 | "lint": {
8 | "executor": "@nrwl/linter:eslint",
9 | "outputs": ["{options.outputFile}"],
10 | "options": {
11 | "lintFilePatterns": ["libs/shared-utilities/**/*.{ts,tsx,js,jsx}"]
12 | }
13 | },
14 | "test": {
15 | "executor": "@nrwl/jest:jest",
16 | "outputs": ["coverage/libs/shared-utilities"],
17 | "options": {
18 | "jestConfig": "libs/shared-utilities/jest.config.ts",
19 | "passWithNoTests": true
20 | }
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/libs/shared-components/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.base.json",
3 | "compilerOptions": {
4 | "jsx": "react-jsx",
5 | "allowJs": true,
6 | "esModuleInterop": true,
7 | "allowSyntheticDefaultImports": true,
8 | "forceConsistentCasingInFileNames": true,
9 | "strict": true,
10 | "noImplicitOverride": true,
11 | "noPropertyAccessFromIndexSignature": true,
12 | "noImplicitReturns": true,
13 | "noFallthroughCasesInSwitch": true
14 | },
15 | "files": [],
16 | "include": [],
17 | "references": [
18 | {
19 | "path": "./tsconfig.lib.json"
20 | },
21 | {
22 | "path": "./tsconfig.spec.json"
23 | },
24 | {
25 | "path": "./.storybook/tsconfig.json"
26 | }
27 | ]
28 | }
29 |
--------------------------------------------------------------------------------
/libs/shared-components/tsconfig.lib.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "../../dist/out-tsc",
5 | "types": ["node"]
6 | },
7 | "files": [
8 | "../../node_modules/@nrwl/react/typings/cssmodule.d.ts",
9 | "../../node_modules/@nrwl/next/typings/image.d.ts"
10 | ],
11 | "exclude": [
12 | "jest.config.ts",
13 | "**/*.spec.ts",
14 | "**/*.test.ts",
15 | "**/*.spec.tsx",
16 | "**/*.test.tsx",
17 | "**/*.spec.js",
18 | "**/*.test.js",
19 | "**/*.spec.jsx",
20 | "**/*.test.jsx",
21 | "**/*.stories.ts",
22 | "**/*.stories.js",
23 | "**/*.stories.jsx",
24 | "**/*.stories.tsx"
25 | ],
26 | "include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"]
27 | }
28 |
--------------------------------------------------------------------------------
/libs/shared-components/.storybook/main.js:
--------------------------------------------------------------------------------
1 | const rootMain = require('../../../.storybook/main');
2 |
3 | module.exports = {
4 | ...rootMain,
5 |
6 | core: { ...rootMain.core, builder: 'webpack5' },
7 |
8 | stories: [
9 | ...rootMain.stories,
10 | '../src/lib/**/*.stories.mdx',
11 | '../src/lib/**/*.stories.@(js|jsx|ts|tsx)',
12 | ],
13 | addons: [...rootMain.addons, '@nrwl/react/plugins/storybook'],
14 | webpackFinal: async (config, { configType }) => {
15 | // apply any global webpack configs that might have been specified in .storybook/main.js
16 | if (rootMain.webpackFinal) {
17 | config = await rootMain.webpackFinal(config, { configType });
18 | }
19 |
20 | // add your own webpack tweaks if needed
21 |
22 | return config;
23 | },
24 | };
25 |
--------------------------------------------------------------------------------
/libs/shared-components/src/lib/checkbox/checkbox.tsx:
--------------------------------------------------------------------------------
1 | import styles from './checkbox.module.scss';
2 |
3 | /* eslint-disable-next-line */
4 | export interface CheckboxProps {
5 | initialValue?: boolean;
6 | title: string;
7 | id: string;
8 | onChange: (checked: boolean) => void;
9 | }
10 |
11 | export function Checkbox({ id, initialValue, onChange, title }: CheckboxProps) {
12 | return (
13 |
14 | onChange(e.target.checked)}
19 | className={styles['switch']}
20 | />
21 |
22 |
23 | );
24 | }
25 |
26 | export default Checkbox;
27 |
--------------------------------------------------------------------------------
/apps/machines-validator/pages/_document.tsx:
--------------------------------------------------------------------------------
1 | import Document, {
2 | Head,
3 | Html,
4 | Main,
5 | NextScript,
6 | } from 'next/document';
7 |
8 | export default class CustomDocument extends Document {
9 | render() {
10 | return (
11 |
12 |
13 |
14 |
19 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | );
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/apps/machines-validator-e2e/project.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "../../node_modules/nx/schemas/project-schema.json",
3 | "sourceRoot": "apps/machines-validator-e2e/src",
4 | "projectType": "application",
5 | "targets": {
6 | "e2e": {
7 | "executor": "@nrwl/cypress:cypress",
8 | "options": {
9 | "cypressConfig": "apps/machines-validator-e2e/cypress.json",
10 | "devServerTarget": "machines-validator:serve:development"
11 | },
12 | "configurations": {
13 | "production": {
14 | "devServerTarget": "machines-validator:serve:production"
15 | }
16 | }
17 | },
18 | "lint": {
19 | "executor": "@nrwl/linter:eslint",
20 | "outputs": ["{options.outputFile}"],
21 | "options": {
22 | "lintFilePatterns": ["apps/machines-validator-e2e/**/*.{js,ts}"]
23 | }
24 | }
25 | },
26 | "tags": [],
27 | "implicitDependencies": ["machines-validator"]
28 | }
29 |
--------------------------------------------------------------------------------
/tsconfig.base.json:
--------------------------------------------------------------------------------
1 | {
2 | "compileOnSave": false,
3 | "compilerOptions": {
4 | "rootDir": ".",
5 | "sourceMap": true,
6 | "declaration": false,
7 | "moduleResolution": "node",
8 | "emitDecoratorMetadata": true,
9 | "experimentalDecorators": true,
10 | "importHelpers": true,
11 | "target": "es2015",
12 | "module": "esnext",
13 | "lib": ["es2017", "dom"],
14 | "skipLibCheck": true,
15 | "skipDefaultLibCheck": true,
16 | "baseUrl": ".",
17 | "paths": {
18 | "@zlab/common-layout": ["libs/common-layout/src/index.ts"],
19 | "@zlab/design-system": ["libs/design-system/src/index.ts"],
20 | "@zlab/shared-components": ["libs/shared-components/src/index.ts"],
21 | "@zlab/shared-models": ["libs/shared-models/src/index.ts"],
22 | "@zlab/shared-utilities": ["libs/shared-utilities/src/index.ts"],
23 | "@zlab/ui": ["libs/ui/src/index.ts"]
24 | }
25 | },
26 | "exclude": ["node_modules", "tmp"]
27 | }
28 |
--------------------------------------------------------------------------------
/libs/shared-components/src/lib/dropdown/dropdown.stories.tsx:
--------------------------------------------------------------------------------
1 | import {
2 | Meta,
3 | Story,
4 | } from '@storybook/react/types-6-0';
5 | import { IDropdownProps } from '@zlab/shared-models';
6 |
7 | import Dropdown from './dropdown';
8 |
9 | export default {
10 | title: 'UI Components',
11 | component: Dropdown,
12 | } as Meta;
13 |
14 | const Template: Story = ({ options, onChange, minimumSearchLength }: IDropdownProps) => (
15 |
20 | );
21 |
22 | export const primary = Template.bind({});
23 | primary.args = {
24 | options: [
25 | { id: 1, label: 'Kassulke & Sohn', value: 'Kassulke & Sohn' },
26 | { id: 2, label: 'Bayer-Bergnaum', value: 'Bayer-Bergnaum' },
27 | { id: 3, label: 'Schinner Group', value: 'Schinner Group' },
28 | ],
29 | onChange: (value: string) => {
30 | console.log(value);
31 | },
32 | minimumSearchLength: 0,
33 | };
34 | primary.storyName = 'Dropdown';
35 |
--------------------------------------------------------------------------------
/libs/shared-utilities/src/lib/customers.ts:
--------------------------------------------------------------------------------
1 | import {
2 | ICustomer,
3 | IDropdownOption,
4 | IFilters,
5 | } from '@zlab/shared-models';
6 |
7 | const extractUniqueValues = (
8 | customers: ICustomer[],
9 | key: keyof ICustomer
10 | ): string[] => {
11 | return [...new Set(customers.map((c) => c[key]))] as string[];
12 | };
13 |
14 | const generateOptionsByKey = (
15 | customers: ICustomer[],
16 | key: keyof ICustomer
17 | ): IDropdownOption[] => {
18 | const uniqueValues = extractUniqueValues(customers, key);
19 |
20 | return uniqueValues.map((u, i) => {
21 | return {
22 | id: i,
23 | label: u,
24 | value: u,
25 | };
26 | });
27 | };
28 |
29 | const filterCustomers = (customers: ICustomer[], filters: IFilters) => {
30 |
31 |
32 | return customers.filter(customer => {
33 | return Object.keys(filters).every((filter: string) => {
34 | // @ts-ignore
35 | return filters[filter] === customer[filter]
36 | })
37 | })
38 | };
39 |
40 | export { filterCustomers, generateOptionsByKey };
41 |
--------------------------------------------------------------------------------
/libs/shared-models/project.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "../../node_modules/nx/schemas/project-schema.json",
3 | "sourceRoot": "libs/shared-models/src",
4 | "projectType": "library",
5 | "targets": {
6 | "build": {
7 | "executor": "@nrwl/js:tsc",
8 | "outputs": ["{options.outputPath}"],
9 | "options": {
10 | "outputPath": "dist/libs/shared-models",
11 | "main": "libs/shared-models/src/index.ts",
12 | "tsConfig": "libs/shared-models/tsconfig.lib.json",
13 | "assets": ["libs/shared-models/*.md"]
14 | }
15 | },
16 | "lint": {
17 | "executor": "@nrwl/linter:eslint",
18 | "outputs": ["{options.outputFile}"],
19 | "options": {
20 | "lintFilePatterns": ["libs/shared-models/**/*.ts"]
21 | }
22 | },
23 | "test": {
24 | "executor": "@nrwl/jest:jest",
25 | "outputs": ["coverage/libs/shared-models"],
26 | "options": {
27 | "jestConfig": "libs/shared-models/jest.config.ts",
28 | "passWithNoTests": true
29 | }
30 | }
31 | },
32 | "tags": []
33 | }
34 |
--------------------------------------------------------------------------------
/nx.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "./node_modules/nx/schemas/nx-schema.json",
3 | "npmScope": "zlab",
4 | "affected": {
5 | "defaultBase": "main"
6 | },
7 | "implicitDependencies": {
8 | "package.json": {
9 | "dependencies": "*",
10 | "devDependencies": "*"
11 | },
12 | ".eslintrc.json": "*"
13 | },
14 | "tasksRunnerOptions": {
15 | "default": {
16 | "runner": "nx/tasks-runners/default",
17 | "options": {
18 | "cacheableOperations": [
19 | "build",
20 | "lint",
21 | "test",
22 | "e2e",
23 | "build-storybook"
24 | ]
25 | }
26 | }
27 | },
28 | "targetDefaults": {
29 | "build": {
30 | "dependsOn": ["^build"]
31 | }
32 | },
33 | "generators": {
34 | "@nrwl/react": {
35 | "application": {
36 | "babel": true
37 | }
38 | },
39 | "@nrwl/next": {
40 | "application": {
41 | "style": "scss",
42 | "linter": "eslint"
43 | }
44 | }
45 | },
46 | "defaultProject": "machines-validator"
47 | }
48 |
--------------------------------------------------------------------------------
/libs/shared-components/src/lib/button/button.module.scss:
--------------------------------------------------------------------------------
1 | @import '/libs/design-system/src/lib/variables.scss';
2 | @import '/libs/design-system/src/lib/mixins.scss';
3 |
4 | .button-container {
5 | background: #e0fbed;
6 | border: 0.1rem solid #bcf3d4;
7 | border-radius: 0.8rem;
8 | padding: 0.6rem 0.8rem;
9 | display: flex;
10 | align-items: center;
11 | justify-content: center;
12 | gap: .4rem;
13 |
14 | &.type-primary {
15 | background-color: $color_primary;
16 | border: none;
17 | padding: 1.2rem 2rem;
18 | border-radius: 3rem;
19 | transition: all ease 400ms;
20 | cursor: pointer;
21 | &:hover {
22 | background-color: lighten($color_primary, 20%);
23 | }
24 | }
25 |
26 | &.type-secondary {
27 | @extend .type-primary;
28 | background-color: $color_secondary;
29 |
30 | &:hover {
31 | background-color: lighten($color_secondary, 20%);
32 | }
33 | }
34 |
35 | &.type-mute {
36 | @extend .type-primary;
37 | border: 1px solid lighten($color_title, 20%);
38 | background-color: transparent;
39 | color: $color_title;
40 |
41 | &:hover {
42 | background-color: $color_title;
43 | color: $color_background;
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/libs/common-layout/src/lib/navbar/navbar.tsx:
--------------------------------------------------------------------------------
1 | import { memo } from 'react';
2 |
3 | import Image from 'next/image';
4 | import Link from 'next/link';
5 |
6 | import {
7 | INavbar,
8 | INavbarProps,
9 | } from '@zlab/shared-models';
10 |
11 | import styles from './navbar.module.scss';
12 |
13 | export function Navbar(props: INavbarProps) {
14 | const { navbarItems } = props;
15 |
16 | const renderItem = (item: INavbar) => (
17 |
18 |
19 | {item.title}
20 |
21 |
22 | );
23 |
24 | const renderNavbarItems = () => navbarItems?.map((item) => renderItem(item));
25 |
26 | return (
27 |
39 | );
40 | }
41 |
42 | function propsAreEqual(prev: INavbarProps, next: INavbarProps) {
43 | return prev.navbarItems === next.navbarItems;
44 | }
45 |
46 | export default memo(Navbar, propsAreEqual);
47 |
--------------------------------------------------------------------------------
/apps/machines-validator-e2e/src/support/commands.ts:
--------------------------------------------------------------------------------
1 | // ***********************************************
2 | // This example commands.js shows you how to
3 | // create various custom commands and overwrite
4 | // existing commands.
5 | //
6 | // For more comprehensive examples of custom
7 | // commands please read more here:
8 | // https://on.cypress.io/custom-commands
9 | // ***********************************************
10 |
11 | // eslint-disable-next-line @typescript-eslint/no-namespace
12 | declare namespace Cypress {
13 | // eslint-disable-next-line @typescript-eslint/no-unused-vars
14 | interface Chainable {
15 | login(email: string, password: string): void;
16 | }
17 | }
18 | //
19 | // -- This is a parent command --
20 | Cypress.Commands.add('login', (email, password) => {
21 | console.log('Custom command example: Login', email, password);
22 | });
23 | //
24 | // -- This is a child command --
25 | // Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... })
26 | //
27 | //
28 | // -- This is a dual command --
29 | // Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... })
30 | //
31 | //
32 | // -- This will overwrite an existing command --
33 | // Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... })
34 |
--------------------------------------------------------------------------------
/libs/common-layout/src/lib/navbar/navbar.module.scss:
--------------------------------------------------------------------------------
1 | @import '/libs/design-system/src/lib/variables.scss';
2 | @import '/libs/design-system/src/lib/mixins.scss';
3 |
4 | .navbar {
5 | padding: 1.6rem 0;
6 | background-color: rgba(0, 0, 0, 0.1);
7 | display: flex;
8 | align-items: center;
9 | margin-bottom: 3rem;
10 |
11 |
12 |
13 | :global(.container) {
14 | display: flex;
15 | align-items: center;
16 | justify-content: space-between;
17 |
18 | @include mobile(){
19 | flex-direction: column;
20 | gap: 1rem;
21 | }
22 |
23 | @include tablet(){
24 | flex-direction: column;
25 | gap: 1rem;
26 | }
27 | }
28 | }
29 |
30 | .navigation-container {
31 | display: flex;
32 | gap: 2.4rem;
33 | @include mobile(){
34 | gap: 1.2rem;
35 | width: 100%;
36 | overflow: scroll;
37 | white-space: nowrap;
38 | padding: 2rem 0;
39 | }
40 |
41 | @include tablet(){
42 | padding: 2rem 0;
43 | }
44 |
45 | a {
46 | color: $color_title;
47 |
48 | @include mobile(){
49 | color: $color_background;
50 | display: block;
51 | background-color: $color_primary;
52 | border-radius: 10rem;
53 | padding: .5rem 1.2rem;
54 | font-size: 1.3rem;
55 | }
56 |
57 | @include mobile(){
58 | color: $color_background;
59 | display: block;
60 | background-color: $color_primary;
61 | border-radius: 10rem;
62 | padding: .5rem 1.2rem;
63 | font-size: 1.3rem;
64 | }
65 |
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/apps/machines-validator/styles/global.scss:
--------------------------------------------------------------------------------
1 | @import '/libs/design-system/src/lib/variables.scss';
2 |
3 | html {
4 | font-size: 10px;
5 | }
6 | body {
7 | font-family: $font_primary;
8 | background-color: $color_background;
9 | color: $color_text;
10 | scroll-behavior: smooth;
11 | overflow-x: hidden;
12 | font-size: 1.6rem;
13 |
14 | &::-webkit-scrollbar {
15 | width: 7px;
16 | }
17 |
18 | /* Track */
19 | &::-webkit-scrollbar-track {
20 | box-shadow: inset 0 0 5px #f5f5f5;
21 | border-radius: 10px;
22 | }
23 |
24 | /* Handle */
25 | &::-webkit-scrollbar-thumb {
26 | background: #716e6e;
27 | border-radius: 10px;
28 | }
29 |
30 | /* Handle on hover */
31 | &::-webkit-scrollbar-thumb:hover {
32 | background: #333;
33 | }
34 | }
35 |
36 | h1,
37 | h2,
38 | h3,
39 | h4,
40 | h5,
41 | h6 {
42 | margin: 1rem 0;
43 | }
44 |
45 | p,
46 | ul,
47 | li {
48 | margin: 0;
49 | }
50 |
51 | li {
52 | list-style: none;
53 | }
54 |
55 | ul {
56 | padding: 0;
57 | }
58 |
59 | * {
60 | box-sizing: border-box;
61 | }
62 |
63 | .container {
64 | width: 100%;
65 | padding-right: 15px;
66 | padding-left: 15px;
67 | margin-right: auto;
68 | margin-left: auto;
69 | }
70 |
71 | // Mobile
72 | @media (max-width: 767px) {
73 | .container {
74 | max-width: 767px;
75 | }
76 | }
77 |
78 | // Tablet
79 | @media (min-width: 768px) and (max-width: 1319) {
80 | .container {
81 | max-width: 1319;
82 | }
83 | }
84 |
85 | // Desktop
86 | @media (min-width: 1320px) {
87 | .container {
88 | max-width: 1320px;
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/libs/shared-components/project.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "../../node_modules/nx/schemas/project-schema.json",
3 | "sourceRoot": "libs/shared-components/src",
4 | "projectType": "library",
5 | "tags": [],
6 | "targets": {
7 | "lint": {
8 | "executor": "@nrwl/linter:eslint",
9 | "outputs": ["{options.outputFile}"],
10 | "options": {
11 | "lintFilePatterns": ["libs/shared-components/**/*.{ts,tsx,js,jsx}"]
12 | }
13 | },
14 | "test": {
15 | "executor": "@nrwl/jest:jest",
16 | "outputs": ["coverage/libs/shared-components"],
17 | "options": {
18 | "jestConfig": "libs/shared-components/jest.config.ts",
19 | "passWithNoTests": true
20 | }
21 | },
22 | "storybook": {
23 | "executor": "@nrwl/storybook:storybook",
24 | "options": {
25 | "uiFramework": "@storybook/react",
26 | "port": 4400,
27 | "config": {
28 | "configFolder": "libs/shared-components/.storybook"
29 | }
30 | },
31 | "configurations": {
32 | "ci": {
33 | "quiet": true
34 | }
35 | }
36 | },
37 | "build-storybook": {
38 | "executor": "@nrwl/storybook:build",
39 | "outputs": ["{options.outputPath}"],
40 | "options": {
41 | "uiFramework": "@storybook/react",
42 | "outputPath": "dist/storybook/shared-components",
43 | "config": {
44 | "configFolder": "libs/shared-components/.storybook"
45 | }
46 | },
47 | "configurations": {
48 | "ci": {
49 | "quiet": true
50 | }
51 | }
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/libs/shared-components/src/lib/dropdown/dropdown.module.scss:
--------------------------------------------------------------------------------
1 | @import '/libs/design-system/src/lib/variables.scss';
2 | @import '/libs/design-system/src/lib/mixins.scss';
3 |
4 | .container {
5 | position: relative;
6 | background-color: $color_primary;
7 | min-width: 22rem;
8 | border-radius: 10rem;
9 | color: $color_background;
10 | }
11 |
12 | .inner-container {
13 | position: absolute;
14 | background-color: $color_primary;
15 | border-radius: 2rem;
16 | width: 100%;
17 | left: 0;
18 | top: 100%;
19 | margin-top: 0.3rem;
20 | visibility: hidden;
21 | opacity: 0;
22 | transition: all ease 400ms;
23 | z-index: 1000;
24 |
25 | &.active {
26 | visibility: visible;
27 | opacity: 1;
28 | }
29 | }
30 |
31 | .selected-option-container {
32 | padding: 1.2rem 2rem;
33 | cursor: pointer;
34 | }
35 |
36 | .selection-option {
37 | letter-spacing: 0.05rem;
38 | min-height: 1.9rem;
39 | user-select: none;
40 | display: flex;
41 | justify-content: space-between;
42 | align-items: center;
43 | }
44 |
45 | .search-input {
46 | width: calc(100% - 2rem);
47 | border: none;
48 | padding: 1rem 1.5rem;
49 | border-radius: 2rem;
50 | background-color: $color_text;
51 | margin-bottom: 1.5rem;
52 | margin: 1rem;
53 | }
54 |
55 | .options-list {
56 | margin: 1rem;
57 | display: flex;
58 | flex-direction: column;
59 | max-height: 250px;
60 | overflow: auto;
61 | li {
62 | padding: 1rem 0.5rem;
63 | border-radius: 0.5rem;
64 | text-transform: capitalize;
65 | cursor: pointer;
66 | transition: all ease 400ms;
67 |
68 | &:hover {
69 | background-color: $color_text;
70 | }
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/libs/shared-components/src/lib/dropdown/__snapshots__/dropdown.spec.tsx.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`Dropdown should match the snapshot 1`] = `
4 |
5 |
6 |
9 |
13 |
16 | Select option
17 |
18 |
19 |
23 |
24 |
25 |
26 | `;
27 |
28 | exports[`Dropdown should match the snapshot when its open 1`] = `
29 |
30 |
31 |
34 |
38 |
41 | Select option
42 |
43 |
44 |
48 |
54 |
57 | -
58 | Kassulke & Sohn
59 |
60 | -
61 | Bayer-Bergnaum
62 |
63 | -
64 | Schinner Group
65 |
66 |
67 |
68 |
69 |
70 |
71 | `;
72 |
--------------------------------------------------------------------------------
/apps/machines-validator/pages/_app.tsx:
--------------------------------------------------------------------------------
1 | import '../styles/global.scss';
2 |
3 | import { AppProps } from 'next/app';
4 | import dynamic from 'next/dynamic';
5 | import Head from 'next/head';
6 |
7 | import {
8 | AnchorTagTarget,
9 | INavbar,
10 | INavbarProps,
11 | } from '@zlab/shared-models';
12 |
13 | const Navbar = dynamic(() =>
14 | import('@zlab/common-layout').then((layout) => layout.Navbar)
15 | );
16 |
17 | interface PageProps extends AppProps {
18 | navbarItems: INavbar[];
19 | }
20 |
21 | function CustomApp({ Component, pageProps, navbarItems }: PageProps) {
22 | return (
23 | <>
24 |
25 | zLab Internal Utilities
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | >
34 | );
35 | }
36 |
37 | CustomApp.getInitialProps = () => {
38 | //Todo: Fetch data from server
39 | const navbarItems: INavbar[] = [
40 | {
41 | id: 1,
42 | title: 'Machines Validator',
43 | href: '/',
44 | target: AnchorTagTarget.SELF,
45 | },
46 | {
47 | id: 2,
48 | title: 'Service Center',
49 | href: '/service-center',
50 | target: AnchorTagTarget.SELF,
51 | },
52 | {
53 | id: 3,
54 | title: 'Customers',
55 | href: '/customers',
56 | target: AnchorTagTarget.SELF,
57 | },
58 | {
59 | id: 4,
60 | title: 'Profile',
61 | href: '/profile',
62 | target: AnchorTagTarget.SELF,
63 | },
64 | {
65 | id: 5,
66 | title: 'Sign out',
67 | href: '/sign-out',
68 | target: AnchorTagTarget.SELF,
69 | },
70 | ];
71 |
72 | return {
73 | navbarItems,
74 | };
75 | };
76 |
77 | export default CustomApp;
78 |
--------------------------------------------------------------------------------
/apps/machines-validator/project.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "../../node_modules/nx/schemas/project-schema.json",
3 | "sourceRoot": "apps/machines-validator",
4 | "projectType": "application",
5 | "targets": {
6 | "build": {
7 | "executor": "@nrwl/next:build",
8 | "outputs": ["{options.outputPath}"],
9 | "defaultConfiguration": "production",
10 | "options": {
11 | "root": "apps/machines-validator",
12 | "outputPath": "dist/apps/machines-validator"
13 | },
14 | "configurations": {
15 | "development": {},
16 | "production": {}
17 | }
18 | },
19 | "serve": {
20 | "executor": "@nrwl/next:server",
21 | "defaultConfiguration": "development",
22 | "options": {
23 | "buildTarget": "machines-validator:build",
24 | "dev": true
25 | },
26 | "configurations": {
27 | "development": {
28 | "buildTarget": "machines-validator:build:development",
29 | "dev": true
30 | },
31 | "production": {
32 | "buildTarget": "machines-validator:build:production",
33 | "dev": false
34 | }
35 | }
36 | },
37 | "export": {
38 | "executor": "@nrwl/next:export",
39 | "options": {
40 | "buildTarget": "machines-validator:build:production"
41 | }
42 | },
43 | "test": {
44 | "executor": "@nrwl/jest:jest",
45 | "outputs": ["coverage/apps/machines-validator"],
46 | "options": {
47 | "jestConfig": "apps/machines-validator/jest.config.ts",
48 | "passWithNoTests": true
49 | }
50 | },
51 | "lint": {
52 | "executor": "@nrwl/linter:eslint",
53 | "outputs": ["{options.outputFile}"],
54 | "options": {
55 | "lintFilePatterns": ["apps/machines-validator/**/*.{ts,tsx,js,jsx}"]
56 | }
57 | }
58 | },
59 | "tags": []
60 | }
61 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "zlab",
3 | "version": "0.0.0",
4 | "license": "MIT",
5 | "scripts": {
6 | "start": "nx serve",
7 | "build": "nx build",
8 | "test": "nx run-many --all --target=test",
9 | "coverage": "nx run-many --all --target=test --codeCoverage"
10 | },
11 | "private": true,
12 | "dependencies": {
13 | "@nrwl/next": "14.3.6",
14 | "axios": "^0.27.2",
15 | "core-js": "^3.6.5",
16 | "next": "12.1.6",
17 | "react": "18.2.0",
18 | "react-dom": "18.2.0",
19 | "react-feather": "^2.0.10",
20 | "react-is": "18.2.0",
21 | "regenerator-runtime": "0.13.7",
22 | "styled-components": "5.3.5",
23 | "tslib": "^2.3.0"
24 | },
25 | "devDependencies": {
26 | "@babel/core": "7.12.13",
27 | "@babel/preset-typescript": "7.12.13",
28 | "@nrwl/cli": "14.3.6",
29 | "@nrwl/cypress": "14.3.6",
30 | "@nrwl/eslint-plugin-nx": "14.3.6",
31 | "@nrwl/jest": "14.3.6",
32 | "@nrwl/linter": "14.3.6",
33 | "@nrwl/react": "14.3.6",
34 | "@nrwl/storybook": "14.3.6",
35 | "@nrwl/web": "14.3.6",
36 | "@nrwl/workspace": "14.3.6",
37 | "@storybook/addon-essentials": "~6.5.9",
38 | "@storybook/builder-webpack5": "~6.5.9",
39 | "@storybook/core-server": "~6.5.9",
40 | "@storybook/manager-webpack5": "~6.5.9",
41 | "@storybook/react": "~6.5.9",
42 | "@svgr/webpack": "^5.4.0",
43 | "@testing-library/jest-dom": "^5.16.4",
44 | "@testing-library/react": "13.3.0",
45 | "@types/jest": "27.4.1",
46 | "@types/node": "16.11.7",
47 | "@types/react": "18.0.13",
48 | "@types/react-dom": "18.0.5",
49 | "@types/react-is": "17.0.3",
50 | "@types/styled-components": "5.1.25",
51 | "@typescript-eslint/eslint-plugin": "~5.24.0",
52 | "@typescript-eslint/parser": "~5.24.0",
53 | "babel-jest": "27.5.1",
54 | "babel-loader": "8.1.0",
55 | "babel-plugin-styled-components": "1.10.7",
56 | "cypress": "^9.1.0",
57 | "eslint": "~8.15.0",
58 | "eslint-config-next": "12.1.6",
59 | "eslint-config-prettier": "8.1.0",
60 | "eslint-plugin-cypress": "^2.10.3",
61 | "eslint-plugin-import": "2.26.0",
62 | "eslint-plugin-jsx-a11y": "6.5.1",
63 | "eslint-plugin-react": "7.30.0",
64 | "eslint-plugin-react-hooks": "4.6.0",
65 | "jest": "27.5.1",
66 | "nx": "14.3.6",
67 | "prettier": "^2.6.2",
68 | "react-test-renderer": "18.2.0",
69 | "sass": "1.52.3",
70 | "ts-jest": "27.1.4",
71 | "ts-node": "~10.8.0",
72 | "typescript": "~4.7.2",
73 | "url-loader": "^3.0.0"
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/libs/common-layout/src/lib/navbar/navbar.spec.tsx:
--------------------------------------------------------------------------------
1 | import { render } from '@testing-library/react';
2 | import {
3 | AnchorTagTarget,
4 | INavbar,
5 | } from '@zlab/shared-models';
6 |
7 | import Navbar from './navbar';
8 |
9 | const dummyItems: INavbar[] = [
10 | {
11 | id: 1,
12 | title: 'Home',
13 | href: '/',
14 | target: AnchorTagTarget.SELF,
15 | },
16 | {
17 | id: 2,
18 | title: 'Work Approach',
19 | href: '/work-approach',
20 | target: AnchorTagTarget.SELF,
21 | },
22 | {
23 | id: 3,
24 | title: 'Jobs',
25 | href: '/jobs',
26 | target: AnchorTagTarget.SELF,
27 | },
28 | {
29 | id: 4,
30 | title: 'About us',
31 | href: '/about-us',
32 | target: AnchorTagTarget.SELF,
33 | },
34 | {
35 | id: 5,
36 | title: 'Contact us',
37 | href: '/contact-us',
38 | target: AnchorTagTarget.SELF,
39 | },
40 | ];
41 |
42 | describe('Navbar', () => {
43 | it('image should render properly', () => {
44 | const { getByTestId } = render();
45 | expect('src' in getByTestId('logo-image').attributes).toBeTruthy();
46 | });
47 |
48 | it('should render successfully', () => {
49 | const { baseElement } = render();
50 | expect(baseElement).toBeTruthy();
51 | });
52 |
53 | it('should not crash if we provide a zero length data', () => {
54 | const { baseElement } = render();
55 | expect(baseElement).toBeTruthy();
56 | });
57 |
58 | it('should render the exact numbers that we provide', () => {
59 | const expectedLength = dummyItems.length;
60 | const { getAllByRole } = render();
61 |
62 | expect(getAllByRole('listitem').length).toEqual(expectedLength);
63 | });
64 |
65 | it('items should have the same href as provided', () => {
66 | const { getAllByRole } = render();
67 |
68 | const listItems = getAllByRole('link');
69 |
70 | expect(
71 | listItems.every(
72 | (item, index) => item.getAttribute('href') === dummyItems[index].href
73 | )
74 | ).toBeTruthy();
75 | });
76 |
77 | it('items should have the same target as provided', () => {
78 | const { getAllByRole } = render();
79 |
80 | const listItems = getAllByRole('link');
81 |
82 | expect(
83 | listItems.every(
84 | (item, index) =>
85 | item.getAttribute('target') === dummyItems[index].target
86 | )
87 | ).toBeTruthy();
88 | });
89 | });
90 |
--------------------------------------------------------------------------------
/libs/shared-components/src/lib/table/table.module.scss:
--------------------------------------------------------------------------------
1 | @import '/libs/design-system/src/lib/variables.scss';
2 | @import '/libs/design-system/src/lib/mixins.scss';
3 |
4 | .container {
5 | margin: 4rem 0;
6 |
7 | @include mobile(){
8 | width: 100%;
9 | overflow: scroll;
10 | }
11 |
12 | @include tablet(){
13 | width: 100%;
14 | overflow: scroll;
15 | }
16 |
17 | table {
18 | width: 100%;
19 |
20 | @include mobile(){
21 | td{
22 | min-width: 200px;
23 |
24 | &:first-of-type{
25 | min-width: 70px;
26 | }
27 | }
28 | }
29 |
30 | @include tablet(){
31 | td{
32 | min-width: 200px;
33 |
34 | &:first-of-type{
35 | min-width: 70px;
36 | }
37 | }
38 | }
39 |
40 | thead {
41 | tr:first-of-type {
42 | td:first-of-type {
43 | border-top-left-radius: 1rem;
44 | }
45 | td:last-of-type {
46 | border-top-right-radius: 1rem;
47 | }
48 | }
49 | td {
50 | font-weight: bold;
51 | color: $color_primary;
52 | }
53 | }
54 |
55 | tbody {
56 | tr:last-of-type {
57 | td:first-of-type {
58 | border-bottom-left-radius: 10px;
59 | }
60 | td:last-of-type {
61 | border-bottom-right-radius: 10px;
62 | }
63 | }
64 | }
65 |
66 | td {
67 | padding: 1.5rem 0;
68 | text-align: center;
69 | transition: all ease 400ms;
70 | }
71 |
72 | tr:nth-child(odd) td {
73 | background-color: lighten($color_background, 7%);
74 | }
75 |
76 | tr:nth-child(even) td {
77 | background-color: lighten($color_background, 3%);
78 | }
79 |
80 | tr:hover td {
81 | background-color: $color_secondary !important;
82 | }
83 | }
84 | }
85 |
86 | .table-header-item {
87 | display: flex;
88 | gap: 2rem;
89 | justify-content: center;
90 | align-items: center;
91 |
92 | ul {
93 | display: flex;
94 | flex-direction: column;
95 | align-items: center;
96 | justify-content: center;
97 |
98 | li{
99 | cursor: pointer;
100 | }
101 | }
102 | }
103 |
104 | .state {
105 | padding: 0.4rem 1.2rem;
106 | font-size: 1.3rem;
107 | border-radius: 10rem;
108 | display: inline-block;
109 |
110 | &.true {
111 | background-color: $color_success;
112 | }
113 |
114 | &.false {
115 | background-color: $color_danger;
116 | }
117 | }
118 |
119 | .empty-state{
120 | height: 200px;
121 | display: flex;
122 | justify-content: center;
123 | align-items: center;
124 | font-size: 2rem;
125 | }
--------------------------------------------------------------------------------
/libs/shared-components/src/lib/table/table.tsx:
--------------------------------------------------------------------------------
1 | import {
2 | useEffect,
3 | useState,
4 | } from 'react';
5 |
6 | import {
7 | ChevronDown,
8 | ChevronUp,
9 | } from 'react-feather';
10 |
11 | import { ColumnTemplate } from '@zlab/shared-models';
12 |
13 | import styles from './table.module.scss';
14 |
15 | export interface TableProps {
16 | columns: ColumnTemplate[];
17 | data: T[];
18 | }
19 |
20 | export const Table = ({ columns, data }: TableProps) => {
21 | const [sortedData, setSortedData] = useState(data);
22 |
23 | useEffect(() => {
24 | setSortedData(data);
25 | }, [data]);
26 |
27 | const handleSort = (key: string, order: 'ASC' | 'DESC') => {
28 | const newData = Object.assign([], data);
29 |
30 | if (order === 'ASC') newData.sort((a, b) => (a[key] > b[key] ? 1 : -1));
31 | if (order === 'DESC') newData.sort((a, b) => (a[key] < b[key] ? 1 : -1));
32 |
33 | setSortedData(newData);
34 | };
35 |
36 | const renderBoolean = (state: boolean) => {
37 | if (state)
38 | return (
39 | Active
40 | );
41 |
42 | return (
43 | Not Active
44 | );
45 | };
46 |
47 | const renderHeaders = () =>
48 | columns.map((r) => (
49 |
50 |
51 | {r.title}
52 | {r.sortable && (
53 |
54 | -
55 | handleSort(r.valueKey, 'ASC')}
59 | />
60 |
61 | -
62 | handleSort(r.valueKey, 'DESC')}
66 | />
67 |
68 |
69 | )}
70 |
71 | |
72 | ));
73 |
74 | const renderRows = () =>
75 | [...Array(sortedData.length).keys()].map((row: number) => (
76 |
77 | {columns.map((r: ColumnTemplate) => (
78 | |
79 | {r.type === 'boolean' &&
80 | renderBoolean((sortedData as [])[row][r.valueKey] as boolean)}
81 | {r.type === 'string' && (sortedData as [])[row][r.valueKey]}
82 | |
83 | ))}
84 |
85 | ));
86 |
87 | return (
88 |
89 |
90 |
91 | {renderHeaders()}
92 |
93 | {data.length > 0 && {renderRows()}}
94 |
95 | {data.length === 0 && (
96 |
No Data!
97 | )}
98 |
99 | );
100 | };
101 |
102 | export default Table;
103 |
--------------------------------------------------------------------------------
/libs/shared-components/src/lib/checkbox/checkbox.module.scss:
--------------------------------------------------------------------------------
1 | @import '/libs/design-system/src/lib/variables.scss';
2 | @import '/libs/design-system/src/lib/mixins.scss';
3 |
4 | .container {
5 | input[type='checkbox'] {
6 | --active: #ffcf54;
7 | --active-inner: #1b1724;
8 | --focus: 2px transparent;
9 | --border: #ffcf54;
10 | --border-hover: #ffcf54;
11 | --background: transparent;
12 | --disabled: #ffcf54;
13 | --disabled-inner: #e1e6f9;
14 | -webkit-appearance: none;
15 | -moz-appearance: none;
16 | height: 21px;
17 | outline: none;
18 | display: inline-block;
19 | vertical-align: top;
20 | position: relative;
21 | margin: 0;
22 | cursor: pointer;
23 | border: 1px solid var(--bc, var(--border));
24 | background: var(--b, var(--background));
25 | transition: background 0.3s, border-color 0.3s, box-shadow 0.2s;
26 | &:after {
27 | content: '';
28 | display: block;
29 | left: 0;
30 | top: 0;
31 | position: absolute;
32 | transition: transform var(--d-t, 0.3s) var(--d-t-e, ease),
33 | opacity var(--d-o, 0.2s);
34 | }
35 | &:checked {
36 | --b: var(--active);
37 | --bc: var(--active);
38 | --d-o: 0.3s;
39 | --d-t: 0.6s;
40 | --d-t-e: cubic-bezier(0.2, 0.85, 0.32, 1.2);
41 | }
42 | &:disabled {
43 | --b: var(--disabled);
44 | cursor: not-allowed;
45 | opacity: 0.9;
46 | &:checked {
47 | --b: var(--disabled-inner);
48 | --bc: var(--border);
49 | }
50 | & + label {
51 | cursor: not-allowed;
52 | }
53 | }
54 | &:hover {
55 | &:not(:checked) {
56 | &:not(:disabled) {
57 | --bc: var(--border-hover);
58 | }
59 | }
60 | }
61 | &:focus {
62 | box-shadow: 0 0 0 var(--focus);
63 | }
64 | &:not(.switch) {
65 | width: 21px;
66 | &:after {
67 | opacity: var(--o, 0);
68 | }
69 | &:checked {
70 | --o: 1;
71 | }
72 | }
73 | & + label {
74 | font-size: 14px;
75 | line-height: 21px;
76 | display: inline-block;
77 | vertical-align: top;
78 | cursor: pointer;
79 | margin-left: 4px;
80 | }
81 | }
82 | input[type='checkbox'] {
83 | &:not(.switch) {
84 | border-radius: 7px;
85 | &:after {
86 | width: 5px;
87 | height: 9px;
88 | border: 2px solid var(--active-inner);
89 | border-top: 0;
90 | border-left: 0;
91 | left: 7px;
92 | top: 4px;
93 | transform: rotate(var(--r, 20deg));
94 | }
95 | &:checked {
96 | --r: 43deg;
97 | }
98 | }
99 | &.switch {
100 | width: 38px;
101 | border-radius: 11px;
102 | &:after {
103 | left: 2px;
104 | top: 2px;
105 | border-radius: 50%;
106 | width: 15px;
107 | height: 15px;
108 | background: var(--ab, var(--border));
109 | transform: translateX(var(--x, 0));
110 | }
111 | &:checked {
112 | --ab: var(--active-inner);
113 | --x: 17px;
114 | }
115 | &:disabled {
116 | &:not(:checked) {
117 | &:after {
118 | opacity: 0.6;
119 | }
120 | }
121 | }
122 | }
123 | }
124 | }
125 |
--------------------------------------------------------------------------------
/libs/shared-components/src/lib/dropdown/dropdown.spec.tsx:
--------------------------------------------------------------------------------
1 | import {
2 | fireEvent,
3 | render,
4 | } from '@testing-library/react';
5 |
6 | import Dropdown from './dropdown';
7 |
8 | const dummyData = [
9 | { id: 1, label: 'Kassulke & Sohn', value: 'Kassulke & Sohn' },
10 | { id: 2, label: 'Bayer-Bergnaum', value: 'Bayer-Bergnaum' },
11 | { id: 3, label: 'Schinner Group', value: 'Schinner Group' },
12 | ];
13 |
14 | describe('Dropdown', () => {
15 | it('should render successfully', () => {
16 | const { baseElement } = render(
17 | {
19 | console.log(v);
20 | }}
21 | options={dummyData}
22 | />
23 | );
24 | expect(baseElement).toBeTruthy();
25 | });
26 |
27 | it('should match the snapshot', () => {
28 | const { baseElement } = render(
29 | {
31 | console.log(v);
32 | }}
33 | options={dummyData}
34 | />
35 | );
36 | expect(baseElement).toMatchSnapshot();
37 | });
38 |
39 | it('Inner container should not have children at start', () => {
40 | const { getByTestId } = render(
41 | {
43 | console.log(v);
44 | }}
45 | options={dummyData}
46 | />
47 | );
48 |
49 | expect(getByTestId('dropdown-inner-container').hasChildNodes()).toBeFalsy();
50 | });
51 |
52 | it("Start Selected Option text should be equal to 'Select option'", () => {
53 | const { getByText } = render(
54 | {
56 | console.log(v);
57 | }}
58 | options={dummyData}
59 | />
60 | );
61 | const expectingText = 'Select option';
62 | expect(getByText(expectingText)).toBeTruthy();
63 | });
64 |
65 | it('Clicking on dropdown should expose its values', async () => {
66 | const { findByTestId, getByTestId } = render(
67 | {
69 | console.log(v);
70 | }}
71 | options={dummyData}
72 | />
73 | );
74 |
75 | fireEvent(
76 | getByTestId('parent-container'),
77 | new MouseEvent('click', {
78 | bubbles: true,
79 | cancelable: true,
80 | })
81 | );
82 |
83 | const innerContainer = await findByTestId('dropdown-inner-container');
84 | expect(
85 | innerContainer.querySelector('ul')?.childElementCount
86 | ).toBeGreaterThan(0);
87 | });
88 |
89 | it('Selected item should change after clicking on an item', async () => {
90 | const { findByTestId, getByTestId, getByText } = render(
91 | {
93 | console.log(v);
94 | }}
95 | options={dummyData}
96 | />
97 | );
98 |
99 | fireEvent(
100 | getByTestId('parent-container'),
101 | new MouseEvent('click', {
102 | bubbles: true,
103 | cancelable: true,
104 | })
105 | );
106 |
107 | const firstItemValue = dummyData[0].label;
108 |
109 | const innerContainer = await findByTestId('dropdown-inner-container');
110 |
111 | fireEvent(
112 | innerContainer.querySelectorAll('ul li')[0],
113 | new MouseEvent('click', {
114 | bubbles: true,
115 | cancelable: true,
116 | })
117 | );
118 |
119 | expect(getByText(firstItemValue)).toBeTruthy();
120 | });
121 |
122 | it('should match the snapshot when its open', () => {
123 | const { baseElement, getByTestId } = render(
124 | {
126 | console.log(v);
127 | }}
128 | options={dummyData}
129 | />
130 | );
131 |
132 | fireEvent(
133 | getByTestId('parent-container'),
134 | new MouseEvent('click', {
135 | bubbles: true,
136 | cancelable: true,
137 | })
138 | );
139 |
140 | expect(baseElement).toMatchSnapshot();
141 | });
142 | });
143 |
--------------------------------------------------------------------------------
/libs/shared-components/src/lib/dropdown/dropdown.tsx:
--------------------------------------------------------------------------------
1 | import {
2 | ChangeEvent,
3 | useEffect,
4 | useRef,
5 | useState,
6 | } from 'react';
7 |
8 | import { ChevronDown } from 'react-feather';
9 |
10 | import {
11 | IDropdownOption,
12 | IDropdownProps,
13 | } from '@zlab/shared-models';
14 |
15 | import styles from './dropdown.module.scss';
16 |
17 | export function Dropdown(props: IDropdownProps) {
18 | const { onChange, options, initialValue, minimumSearchLength = 0 } = props;
19 |
20 | const INITIAL_TEXT = 'Select option';
21 |
22 | const [selectedOption, setSelectedOption] = useState(
23 | initialValue ? initialValue : INITIAL_TEXT
24 | );
25 | const [optionsList, setOptionsList] = useState([]);
26 | const [searchTerm, setSearchTerm] = useState('');
27 | const [listOpenState, setListOpenState] = useState(false);
28 |
29 | const SearchInputRef = useRef(null);
30 | const ContainerRef = useRef(null);
31 |
32 | useEffect(() => {
33 | if (initialValue) {
34 | setSelectedOption(initialValue);
35 | } else {
36 | setSelectedOption(INITIAL_TEXT);
37 | }
38 | }, [initialValue]);
39 |
40 | const handleFillingOptions = () => {
41 | setOptionsList(options);
42 | };
43 |
44 | const toggleListState = () => {
45 | setListOpenState(!listOpenState);
46 | };
47 |
48 | const handleSelectOption = (option: IDropdownOption) => {
49 | onChange(option.value);
50 | setSelectedOption(option.label);
51 | toggleListState();
52 | };
53 |
54 | const handleSearch = (term: string) => {
55 | if (term.length === 0) setOptionsList(options);
56 |
57 | if (term.length <= minimumSearchLength) return;
58 |
59 | const filteredList = optionsList.filter(
60 | (item) => item.value.toLowerCase().indexOf(term.toLowerCase()) > -1
61 | );
62 | setOptionsList(filteredList);
63 | };
64 |
65 | const handleInputFocus = (state: boolean) => {
66 | if (state) {
67 | // we use timeout because the state open have some animation that took 400ms
68 | setTimeout(() => {
69 | SearchInputRef?.current?.focus();
70 | }, 100);
71 | }
72 | };
73 |
74 | const handleOutSideClick = () => {
75 | const onClickOutside = (e: any) => {
76 | if (ContainerRef.current && !ContainerRef.current.contains(e.target))
77 | setListOpenState(false);
78 | };
79 |
80 | document.addEventListener('click', onClickOutside);
81 |
82 | return () => {
83 | document.removeEventListener('click', onClickOutside);
84 | };
85 | };
86 |
87 | useEffect(handleOutSideClick, []);
88 |
89 | useEffect(() => {
90 | handleInputFocus(listOpenState);
91 | }, [listOpenState]);
92 | useEffect(handleFillingOptions, [options]);
93 | useEffect(() => {
94 | handleSearch(searchTerm);
95 | }, [searchTerm]);
96 |
97 | const handleSearchInputChange = (event: ChangeEvent) => {
98 | const value = event.target.value;
99 | setSearchTerm(value.trim());
100 | };
101 |
102 | const renderOptions = () =>
103 | optionsList.map((option: IDropdownOption) => (
104 | handleSelectOption(option)}>
105 | {option.label}
106 |
107 | ));
108 |
109 | return (
110 |
111 |
116 |
117 | {selectedOption}
118 |
119 |
120 |
121 |
127 | {listOpenState && (
128 | <>
129 |
137 |
138 | >
139 | )}
140 |
141 |
142 | );
143 | }
144 |
145 | export default Dropdown;
146 |
--------------------------------------------------------------------------------
/apps/machines-validator/pages/index.tsx:
--------------------------------------------------------------------------------
1 | import {
2 | FC,
3 | useState,
4 | } from 'react';
5 |
6 | import axios from 'axios';
7 | import { Filter } from 'react-feather';
8 |
9 | import {
10 | FormContainer,
11 | FormField,
12 | } from '@zlab/common-layout';
13 | import {
14 | Button,
15 | Checkbox,
16 | Dropdown,
17 | Table,
18 | } from '@zlab/shared-components';
19 | import {
20 | ColumnTemplate,
21 | ICustomer,
22 | IDropdownOption,
23 | IFilters,
24 | } from '@zlab/shared-models';
25 | import {
26 | filterCustomers,
27 | generateOptionsByKey,
28 | } from '@zlab/shared-utilities';
29 |
30 | const tableHeaders: ColumnTemplate[] = [
31 | {
32 | title: 'ID',
33 | width: '5%',
34 | type: 'string',
35 | valueKey: 'id',
36 | sortable: true,
37 | },
38 | {
39 | title: 'Customer',
40 | width: '20%',
41 | type: 'string',
42 | valueKey: 'customer',
43 | sortable: false,
44 | },
45 | {
46 | title: 'Serial Number',
47 | width: '20%',
48 | type: 'string',
49 | valueKey: 'serial_number',
50 | sortable: false,
51 | },
52 | {
53 | title: 'Asset Type',
54 | width: '20%',
55 | type: 'string',
56 | valueKey: 'asset_type',
57 | sortable: true,
58 | },
59 | {
60 | title: 'Service Contract Status',
61 | width: '20%',
62 | type: 'boolean',
63 | valueKey: 'service_contract',
64 | sortable: true,
65 | },
66 | {
67 | title: 'Warranty Status',
68 | width: '20%',
69 | type: 'boolean',
70 | valueKey: 'warranty',
71 | sortable: true,
72 | },
73 | ];
74 |
75 | interface Props {
76 | customers: ICustomer[];
77 | assetTypesList: IDropdownOption[];
78 | customersList: IDropdownOption[];
79 | serialNumbersList: IDropdownOption[];
80 | }
81 |
82 | const Index: FC = ({ customers, assetTypesList, customersList, serialNumbersList }) => {
83 | const [filteredData, setFilteredData] = useState(customers);
84 |
85 | const [filters, setFilters] = useState();
86 |
87 | const handleFiltersChange = (
88 | key: keyof IFilters,
89 | newValue: string | boolean
90 | ) => {
91 | const newFilters = Object.assign({}, filters);
92 | newFilters[key as string] = newValue;
93 | setFilters(newFilters);
94 | };
95 |
96 | const handleApplyFilter = () => {
97 | const filteredCustomers = filterCustomers(customers, filters);
98 | setFilteredData(filteredCustomers);
99 | };
100 |
101 | const handleResetFilters = () => {
102 | setFilters(null);
103 | setFilteredData(customers);
104 | };
105 |
106 | return (
107 |
108 |
Customers Overview
109 |
110 |
111 |
112 | {
115 | handleFiltersChange('serial_number', v);
116 | }}
117 | options={serialNumbersList}
118 | />
119 |
120 |
121 | {
125 | handleFiltersChange('customer', v);
126 | }}
127 | options={customersList}
128 | />
129 |
130 |
131 | {
135 | handleFiltersChange('asset_type', v);
136 | }}
137 | options={assetTypesList}
138 | />
139 |
140 |
141 |
142 | handleFiltersChange('warranty', v)}
145 | id="Warranty-Status"
146 | title=""
147 | />
148 |
149 |
150 |
151 | handleFiltersChange('service_contract', v)}
154 | id="Service-Contract-Status"
155 | title=""
156 | />
157 |
158 |
159 |
160 |
164 |
165 |
166 |
169 |
170 |
171 |
172 |
173 |
174 | );
175 | };
176 |
177 | export async function getServerSideProps(context) {
178 | const { data } = await axios.get(
179 | 'https://api.jsonbin.io/v3/b/62b9da24192a674d291c921b'
180 | );
181 |
182 | const records = data.record as ICustomer[];
183 |
184 | const assetTypesList = generateOptionsByKey(records, 'asset_type');
185 | const customersList = generateOptionsByKey(records, 'customer');
186 | const serialNumbersList = generateOptionsByKey(records, 'serial_number');
187 |
188 | return {
189 | props: {
190 | customers: records,
191 | assetTypesList,
192 | customersList,
193 | serialNumbersList,
194 | },
195 | };
196 | }
197 |
198 | export default Index;
199 |
--------------------------------------------------------------------------------