├── packages ├── ssr │ ├── .nvmrc │ ├── .prettierignore │ ├── .commitlintrc.json │ ├── .prettierrc │ ├── tests │ │ ├── setupTests.ts │ │ ├── mocks │ │ │ ├── fileTransformer.js │ │ │ └── image.tsx │ │ └── snapshotResolver.ts │ ├── tsconfig.jest.json │ ├── .babelrc │ ├── src │ │ ├── modules │ │ │ └── home │ │ │ │ └── screens │ │ │ │ └── Main │ │ │ │ └── index.tsx │ │ ├── config │ │ │ └── routes │ │ │ │ ├── types.ts │ │ │ │ └── index.ts │ │ └── pages │ │ │ ├── home │ │ │ └── index.tsx │ │ │ └── index.tsx │ ├── .editorconfig │ ├── next-env.d.ts │ ├── .vscode │ │ └── settings.json │ ├── next.config.js │ ├── tsconfig.json │ ├── jest.config.js │ ├── package.json │ └── .eslintrc.js ├── mobile │ ├── .watchmanconfig │ ├── .gitattributes │ ├── app.json │ ├── babel.config.js │ ├── android │ │ ├── app │ │ │ ├── src │ │ │ │ ├── main │ │ │ │ │ ├── res │ │ │ │ │ │ ├── values │ │ │ │ │ │ │ ├── strings.xml │ │ │ │ │ │ │ └── styles.xml │ │ │ │ │ │ ├── mipmap-hdpi │ │ │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ │ │ └── ic_launcher_round.png │ │ │ │ │ │ ├── mipmap-mdpi │ │ │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ │ │ └── ic_launcher_round.png │ │ │ │ │ │ ├── mipmap-xhdpi │ │ │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ │ │ └── ic_launcher_round.png │ │ │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ │ │ └── ic_launcher_round.png │ │ │ │ │ │ └── mipmap-xxxhdpi │ │ │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ │ │ └── ic_launcher_round.png │ │ │ │ │ ├── java │ │ │ │ │ │ └── com │ │ │ │ │ │ │ └── mobile │ │ │ │ │ │ │ ├── MainActivity.java │ │ │ │ │ │ │ └── MainApplication.java │ │ │ │ │ └── AndroidManifest.xml │ │ │ │ └── debug │ │ │ │ │ └── AndroidManifest.xml │ │ │ ├── debug.keystore │ │ │ ├── proguard-rules.pro │ │ │ ├── build_defs.bzl │ │ │ └── _BUCK │ │ ├── gradle │ │ │ └── wrapper │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ ├── settings.gradle │ │ ├── build.gradle │ │ └── gradle.properties │ ├── ios │ │ ├── mobile │ │ │ ├── Images.xcassets │ │ │ │ ├── Contents.json │ │ │ │ └── AppIcon.appiconset │ │ │ │ │ └── Contents.json │ │ │ ├── AppDelegate.h │ │ │ ├── main.m │ │ │ ├── Info.plist │ │ │ └── AppDelegate.m │ │ ├── mobile.xcworkspace │ │ │ └── contents.xcworkspacedata │ │ ├── Podfile │ │ ├── mobileTests │ │ │ ├── Info.plist │ │ │ └── mobileTests.m │ │ ├── mobile-tvOSTests │ │ │ └── Info.plist │ │ └── mobile-tvOS │ │ │ └── Info.plist │ ├── src │ │ ├── index.spec.tsx │ │ └── index.tsx │ ├── .buckconfig │ ├── .prettierrc.js │ ├── index.js │ ├── tsconfig.json │ ├── App.tsx │ ├── .eslintrc.js │ ├── metro.config.js │ ├── .gitignore │ └── package.json ├── design-system │ ├── src │ │ ├── web │ │ │ ├── Typography │ │ │ │ └── index.tsx │ │ │ ├── index.ts │ │ │ ├── Button │ │ │ │ ├── index.tsx │ │ │ │ ├── OutlinedButton │ │ │ │ │ ├── interface.ts │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.tsx │ │ │ │ ├── story │ │ │ │ │ ├── Button.story.mdx │ │ │ │ │ ├── OutlinedButton.story.tsx │ │ │ │ │ └── Button.story.tsx │ │ │ │ └── DefaultButton │ │ │ │ │ ├── styles.tsx │ │ │ │ │ ├── interface.ts │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── __tests__ │ │ │ │ │ ├── __snapshots__ │ │ │ │ │ └── index.spec.tsx.snap │ │ │ │ │ └── index.spec.tsx │ │ │ └── Grid │ │ │ │ ├── styles.tsx │ │ │ │ ├── index.tsx │ │ │ │ └── interface.ts │ │ ├── index.ts │ │ ├── interfaces │ │ │ ├── index.ts │ │ │ ├── colors.ts │ │ │ ├── align.ts │ │ │ └── units.ts │ │ ├── theme │ │ │ ├── fonts.ts │ │ │ ├── globalStyle.tsx │ │ │ ├── colors.ts │ │ │ ├── units.ts │ │ │ └── index.ts │ │ ├── provider │ │ │ └── index.tsx │ │ └── utils │ │ │ └── config │ │ │ └── setupEnzyme.ts │ ├── lib │ │ ├── utils │ │ │ ├── config │ │ │ │ ├── setupEnzyme.d.ts │ │ │ │ └── setupEnzyme.js │ │ │ └── theme │ │ │ │ ├── globalStyle.d.ts │ │ │ │ ├── globalStyle.js │ │ │ │ ├── index.d.ts │ │ │ │ └── index.js │ │ ├── Button │ │ │ ├── index.d.ts │ │ │ ├── index.js │ │ │ └── web │ │ │ │ ├── StyledButton.d.ts │ │ │ │ ├── OutlinedButton.d.ts │ │ │ │ ├── DefaultButton.d.ts │ │ │ │ ├── Button.d.ts │ │ │ │ ├── Button.js │ │ │ │ ├── StyledButton.js │ │ │ │ ├── DefaultButton.js │ │ │ │ └── OutlinedButton.js │ │ ├── web │ │ │ ├── Button │ │ │ │ ├── index.d.ts │ │ │ │ ├── index.js │ │ │ │ ├── StyledButton.d.ts │ │ │ │ ├── OutlinedButton.d.ts │ │ │ │ ├── DefaultButton.d.ts │ │ │ │ ├── Button.d.ts │ │ │ │ ├── Button.js │ │ │ │ ├── StyledButton.js │ │ │ │ ├── DefaultButton.js │ │ │ │ └── OutlinedButton.js │ │ │ ├── index.d.ts │ │ │ ├── Grid │ │ │ │ ├── Container.d.ts │ │ │ │ ├── index.d.ts │ │ │ │ ├── Flex.d.ts │ │ │ │ ├── Container.js │ │ │ │ ├── Flex.js │ │ │ │ └── index.js │ │ │ └── index.js │ │ ├── Grid │ │ │ ├── index.d.ts │ │ │ ├── web │ │ │ │ ├── Container.d.ts │ │ │ │ ├── Flex.d.ts │ │ │ │ ├── Container.js │ │ │ │ └── Flex.js │ │ │ └── index.js │ │ ├── index.d.ts │ │ ├── theme │ │ │ ├── globalStyle.d.ts │ │ │ ├── index.d.ts │ │ │ ├── globalStyle.js │ │ │ └── index.js │ │ └── index.js │ ├── lib-esm │ │ ├── Button │ │ │ ├── index.js │ │ │ └── web │ │ │ │ ├── StyledButton.js │ │ │ │ ├── Button.js │ │ │ │ ├── DefaultButton.js │ │ │ │ └── OutlinedButton.js │ │ ├── Grid │ │ │ ├── index.js │ │ │ └── web │ │ │ │ └── Container.js │ │ ├── index.js │ │ └── theme │ │ │ ├── globalStyle.js │ │ │ └── index.js │ ├── .storybook │ │ ├── presets.js │ │ ├── addons.js │ │ ├── themeDecorator.js │ │ ├── config.js │ │ └── webpack.config.js │ ├── .prettierrc │ ├── .editorconfig │ ├── tsconfig.json │ ├── tsconfig.esm.json │ ├── jest.config.js │ ├── __tests__ │ │ └── helpers │ │ │ └── index.tsx │ ├── .eslintrc.js │ └── package.json ├── web │ ├── src │ │ ├── react-app-env.d.ts │ │ ├── store │ │ │ ├── reducers.ts │ │ │ ├── sagas.ts │ │ │ └── index.ts │ │ ├── index.tsx │ │ ├── root │ │ │ └── index.tsx │ │ └── modules │ │ │ └── views │ │ │ └── home │ │ │ └── index.tsx │ ├── public │ │ ├── favicon.ico │ │ ├── manifest.json │ │ └── index.html │ ├── .prettierrc │ ├── .editorconfig │ ├── tsconfig.json │ ├── .eslintrc.js │ └── package.json ├── sdk │ ├── lib │ │ ├── utils │ │ │ ├── global.interface.js │ │ │ ├── global.interface.d.ts │ │ │ ├── httpClient.d.ts │ │ │ ├── routes.constants.d.ts │ │ │ └── routes.constants.js │ │ ├── index.d.ts │ │ ├── products │ │ │ ├── product.interface.js │ │ │ ├── product.provider.d.ts │ │ │ ├── product.interface.d.ts │ │ │ ├── product.schema.d.ts │ │ │ ├── product.schema.js │ │ │ └── product.provider.js │ │ └── index.js │ ├── src │ │ ├── index.ts │ │ ├── utils │ │ │ ├── global.interface.ts │ │ │ ├── routes.constants.ts │ │ │ └── httpClient.ts │ │ └── products │ │ │ ├── product.interface.ts │ │ │ ├── product.schema.ts │ │ │ └── product.provider.ts │ ├── .prettierrc │ ├── .editorconfig │ ├── tsconfig.json │ ├── tsconfig.esm.json │ ├── babel.config.js │ ├── __tests__ │ │ └── products │ │ │ └── products.spec.ts │ ├── package.json │ └── .eslintrc.js └── server │ ├── src │ ├── user │ │ ├── dto │ │ │ ├── index.ts │ │ │ └── create-user.dto.ts │ │ ├── user.module.ts │ │ ├── user.decorator.ts │ │ ├── user.interface.ts │ │ ├── user.resolver.ts │ │ ├── user.entity.ts │ │ └── user.service.ts │ ├── store │ │ ├── dto │ │ │ ├── index.ts │ │ │ ├── link-employee.dto.ts │ │ │ ├── link-product.dto.ts │ │ │ └── create-store.dto.ts │ │ ├── store.module.ts │ │ ├── store.resolver.ts │ │ └── store.entity.ts │ ├── app.controller.ts │ ├── product │ │ ├── dto │ │ │ ├── index.ts │ │ │ ├── link-attribute.dto.ts │ │ │ ├── link-category.dto.ts │ │ │ └── create-product.dto.ts │ │ ├── product.module.ts │ │ ├── product.resolver.ts │ │ └── product.entity.ts │ ├── attribute │ │ ├── attribute.interface.ts │ │ ├── attribute.module.ts │ │ ├── dto │ │ │ └── create-attribute.dto.ts │ │ ├── attribute.entity.ts │ │ ├── attribute.resolver.ts │ │ └── attribute.service.ts │ ├── auth │ │ ├── dto │ │ │ ├── auth.interface.ts │ │ │ └── auth.input.ts │ │ ├── auth.guard.ts │ │ ├── auth.resolver.ts │ │ ├── auth.module.ts │ │ ├── jwt.strategy.ts │ │ └── auth.service.ts │ ├── main.ts │ ├── shared │ │ ├── base.controller.ts │ │ └── pipes │ │ │ └── validation.pipe.ts │ ├── category │ │ ├── dto │ │ │ └── create-category.dto.ts │ │ ├── category.module.ts │ │ ├── category.entity.ts │ │ ├── category.resolver.ts │ │ └── category.service.ts │ ├── utils │ │ └── helpers.ts │ └── app.module.ts │ ├── .env.example │ ├── tsconfig.build.json │ ├── nest-cli.json │ ├── .prettierrc │ ├── test │ ├── jest-e2e.json │ └── app.e2e-spec.ts │ ├── .gitignore │ ├── docker-compose.yml │ ├── tsconfig.json │ ├── .eslintrc.js │ └── package.json ├── tsconfig.json ├── commitlint.config.js ├── typings.d.ts ├── lerna.json ├── .github ├── ISSUE_TEMPLATE │ ├── question.md │ ├── feature_request.md │ └── bug_report.md ├── stale.yml └── PULL_REQUEST_TEMPLATE.md ├── tsconfig.base.json ├── .gitignore ├── LICENSE ├── package.json └── README.md /packages/ssr/.nvmrc: -------------------------------------------------------------------------------- 1 | v14.15.4 -------------------------------------------------------------------------------- /packages/mobile/.watchmanconfig: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /packages/ssr/.prettierignore: -------------------------------------------------------------------------------- 1 | README.md 2 | -------------------------------------------------------------------------------- /packages/design-system/src/web/Typography/index.tsx: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/mobile/.gitattributes: -------------------------------------------------------------------------------- 1 | *.pbxproj -text 2 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.base.json" 3 | } 4 | -------------------------------------------------------------------------------- /packages/design-system/lib/utils/config/setupEnzyme.d.ts: -------------------------------------------------------------------------------- 1 | import 'jest-enzyme'; 2 | -------------------------------------------------------------------------------- /packages/web/src/react-app-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /packages/design-system/lib/Button/index.d.ts: -------------------------------------------------------------------------------- 1 | export { Button } from './web/Button'; 2 | -------------------------------------------------------------------------------- /packages/mobile/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mobile", 3 | "displayName": "mobile" 4 | } -------------------------------------------------------------------------------- /commitlint.config.js: -------------------------------------------------------------------------------- 1 | module.exports = {extends: ['@commitlint/config-conventional']}; 2 | -------------------------------------------------------------------------------- /packages/design-system/lib-esm/Button/index.js: -------------------------------------------------------------------------------- 1 | export { Button } from './web/Button'; 2 | -------------------------------------------------------------------------------- /packages/sdk/lib/utils/global.interface.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | exports.__esModule = true; 3 | -------------------------------------------------------------------------------- /packages/sdk/src/index.ts: -------------------------------------------------------------------------------- 1 | export { ProductProvider } from './products/product.provider'; 2 | -------------------------------------------------------------------------------- /packages/server/src/user/dto/index.ts: -------------------------------------------------------------------------------- 1 | export { CreateUserDto } from './create-user.dto'; 2 | -------------------------------------------------------------------------------- /packages/sdk/lib/index.d.ts: -------------------------------------------------------------------------------- 1 | export { ProductProvider } from './products/product.provider'; 2 | -------------------------------------------------------------------------------- /packages/sdk/lib/products/product.interface.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | exports.__esModule = true; 3 | -------------------------------------------------------------------------------- /packages/sdk/src/utils/global.interface.ts: -------------------------------------------------------------------------------- 1 | export interface IApiResponse { 2 | data: T; 3 | } -------------------------------------------------------------------------------- /packages/ssr/.commitlintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["@commitlint/config-conventional"] 3 | } 4 | -------------------------------------------------------------------------------- /typings.d.ts: -------------------------------------------------------------------------------- 1 | 2 | declare module "*.json" { 3 | const value: any; 4 | export default value; 5 | } 6 | -------------------------------------------------------------------------------- /packages/design-system/.storybook/presets.js: -------------------------------------------------------------------------------- 1 | module.exports = ['@storybook/addon-docs/react/preset']; 2 | -------------------------------------------------------------------------------- /packages/sdk/lib/utils/global.interface.d.ts: -------------------------------------------------------------------------------- 1 | export interface IApiResponse { 2 | data: T; 3 | } 4 | -------------------------------------------------------------------------------- /packages/design-system/lib/web/Button/index.d.ts: -------------------------------------------------------------------------------- 1 | export { default as DefaultButton } from './DefaultButton'; 2 | -------------------------------------------------------------------------------- /packages/mobile/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: ['module:metro-react-native-babel-preset'], 3 | }; 4 | -------------------------------------------------------------------------------- /packages/web/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/react-shop/react-ecommerce/HEAD/packages/web/public/favicon.ico -------------------------------------------------------------------------------- /packages/design-system/lib-esm/Grid/index.js: -------------------------------------------------------------------------------- 1 | export { Container } from './web/Container'; 2 | export { Flex } from './web/Flex'; 3 | -------------------------------------------------------------------------------- /packages/design-system/lib-esm/index.js: -------------------------------------------------------------------------------- 1 | export * from './web'; 2 | export { default as GlobalStyles } from './theme/globalStyle'; 3 | -------------------------------------------------------------------------------- /packages/design-system/lib/Grid/index.d.ts: -------------------------------------------------------------------------------- 1 | export { Container } from './web/Container'; 2 | export { Flex } from './web/Flex'; 3 | -------------------------------------------------------------------------------- /packages/design-system/lib/web/index.d.ts: -------------------------------------------------------------------------------- 1 | export { DefaultButton } from './Button'; 2 | export { default as Grid } from './Grid'; 3 | -------------------------------------------------------------------------------- /packages/design-system/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './web'; 2 | export { default as GlobalStyles } from './theme/globalStyle'; 3 | -------------------------------------------------------------------------------- /packages/design-system/src/web/index.ts: -------------------------------------------------------------------------------- 1 | export { DefaultButton } from './Button'; 2 | export { default as Grid } from './Grid'; 3 | -------------------------------------------------------------------------------- /packages/web/src/store/reducers.ts: -------------------------------------------------------------------------------- 1 | import { combineReducers } from 'redux'; 2 | 3 | export default () => combineReducers({}); 4 | -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "packages": ["packages/*"], 3 | "version": "0.0.0", 4 | "npmClient": "yarn", 5 | "useWorkspaces": true 6 | } 7 | -------------------------------------------------------------------------------- /packages/design-system/src/interfaces/index.ts: -------------------------------------------------------------------------------- 1 | export * from './colors'; 2 | export * from './units'; 3 | export * from './align'; 4 | -------------------------------------------------------------------------------- /packages/ssr/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "all", 3 | "singleQuote": true, 4 | "printWidth": 100, 5 | "tabWidth": 2 6 | } 7 | -------------------------------------------------------------------------------- /packages/mobile/android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | mobile 3 | 4 | -------------------------------------------------------------------------------- /packages/mobile/ios/mobile/Images.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /packages/server/.env.example: -------------------------------------------------------------------------------- 1 | DATABASE_HOST= 2 | DATABASE_NAME= 3 | DATABASE_USER= 4 | DATABASE_PASSWORD= 5 | DATABASE_PORT= 6 | 7 | SECRET= -------------------------------------------------------------------------------- /packages/ssr/tests/setupTests.ts: -------------------------------------------------------------------------------- 1 | import '@testing-library/jest-dom'; 2 | import 'jest-styled-components'; 3 | import '@tests/mocks/image'; 4 | -------------------------------------------------------------------------------- /packages/mobile/android/app/debug.keystore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/react-shop/react-ecommerce/HEAD/packages/mobile/android/app/debug.keystore -------------------------------------------------------------------------------- /packages/server/tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "exclude": ["node_modules", "test", "dist", "**/*spec.ts"] 4 | } 5 | -------------------------------------------------------------------------------- /packages/ssr/tsconfig.jest.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "jsx": "react-jsx" 5 | } 6 | } -------------------------------------------------------------------------------- /packages/design-system/lib/index.d.ts: -------------------------------------------------------------------------------- 1 | export { DefaultButton, Grid } from './web'; 2 | export { default as GlobalStyles } from './theme/globalStyle'; 3 | -------------------------------------------------------------------------------- /packages/web/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "bracketSpacing": false, 3 | "jsxBracketSameLine": true, 4 | "singleQuote": true, 5 | "trailingComma": "es5" 6 | } -------------------------------------------------------------------------------- /packages/web/src/store/sagas.ts: -------------------------------------------------------------------------------- 1 | import { all } from 'redux-saga/effects'; 2 | 3 | export default function* rootSaga() { 4 | yield all([]); 5 | } 6 | -------------------------------------------------------------------------------- /packages/design-system/lib/Grid/web/Container.d.ts: -------------------------------------------------------------------------------- 1 | export declare const Container: import("styled-components").StyledComponent<"div", any, {}, never>; 2 | -------------------------------------------------------------------------------- /packages/design-system/lib/web/Grid/Container.d.ts: -------------------------------------------------------------------------------- 1 | export declare const Container: import("styled-components").StyledComponent<"div", any, {}, never>; 2 | -------------------------------------------------------------------------------- /packages/mobile/src/index.spec.tsx: -------------------------------------------------------------------------------- 1 | describe('When sum 2 numbers', () => { 2 | it('should be 5', () => { 3 | expect(4 + 1).toBe(5); 4 | }); 5 | }); 6 | -------------------------------------------------------------------------------- /packages/sdk/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "bracketSpacing": false, 3 | "jsxBracketSameLine": true, 4 | "singleQuote": true, 5 | "trailingComma": "es5" 6 | } 7 | -------------------------------------------------------------------------------- /packages/design-system/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "bracketSpacing": false, 3 | "jsxBracketSameLine": true, 4 | "singleQuote": true, 5 | "trailingComma": "es5" 6 | } -------------------------------------------------------------------------------- /packages/design-system/src/web/Button/index.tsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable import/prefer-default-export */ 2 | export { default as DefaultButton } from './DefaultButton'; 3 | -------------------------------------------------------------------------------- /packages/mobile/.buckconfig: -------------------------------------------------------------------------------- 1 | 2 | [android] 3 | target = Google Inc.:Google APIs:23 4 | 5 | [maven_repositories] 6 | central = https://repo1.maven.org/maven2 7 | -------------------------------------------------------------------------------- /packages/mobile/.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | bracketSpacing: true, 3 | jsxBracketSameLine: true, 4 | singleQuote: true, 5 | trailingComma: 'all', 6 | }; -------------------------------------------------------------------------------- /packages/sdk/lib/utils/httpClient.d.ts: -------------------------------------------------------------------------------- 1 | export declare const http: import("axios").AxiosInstance; 2 | export interface IAccessUser { 3 | token: string; 4 | } 5 | -------------------------------------------------------------------------------- /packages/ssr/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["next/babel"], 3 | "plugins": [["styled-components", { "ssr": true, "displayName": true, "preprocess": false }]] 4 | } -------------------------------------------------------------------------------- /packages/design-system/lib/Button/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | exports.__esModule = true; 3 | var Button_1 = require("./web/Button"); 4 | exports.Button = Button_1.Button; 5 | -------------------------------------------------------------------------------- /packages/mobile/android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/react-shop/react-ecommerce/HEAD/packages/mobile/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /packages/sdk/lib/utils/routes.constants.d.ts: -------------------------------------------------------------------------------- 1 | export declare const api: { 2 | BASE_URL: string; 3 | }; 4 | export declare const ENDPOINTS: { 5 | PRODUCTS: string; 6 | }; 7 | -------------------------------------------------------------------------------- /packages/server/nest-cli.json: -------------------------------------------------------------------------------- 1 | { 2 | "collection": "@nestjs/schematics", 3 | "sourceRoot": "src", 4 | "compilerOptions": { 5 | "plugins": ["@nestjs/graphql"] 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /packages/ssr/src/modules/home/screens/Main/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const Home = () => { 4 | return
Home screen
5 | } 6 | 7 | export default Home; 8 | -------------------------------------------------------------------------------- /packages/mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/react-shop/react-ecommerce/HEAD/packages/mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /packages/mobile/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/react-shop/react-ecommerce/HEAD/packages/mobile/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /packages/design-system/src/theme/fonts.ts: -------------------------------------------------------------------------------- 1 | const weights = { 2 | light: 300, 3 | regular: 500, 4 | bold: 700, 5 | black: 900, 6 | }; 7 | 8 | export default { 9 | weights, 10 | }; 11 | -------------------------------------------------------------------------------- /packages/mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/react-shop/react-ecommerce/HEAD/packages/mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /packages/mobile/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/react-shop/react-ecommerce/HEAD/packages/mobile/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /packages/ssr/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | charset = utf-8 7 | end_of_line = lf 8 | trim_trailing_whitespace = true 9 | insert_final_newline = tr -------------------------------------------------------------------------------- /packages/design-system/lib/theme/globalStyle.d.ts: -------------------------------------------------------------------------------- 1 | declare const GlobalStyle: import("styled-components").GlobalStyleComponent<{}, import("styled-components").DefaultTheme>; 2 | export default GlobalStyle; 3 | -------------------------------------------------------------------------------- /packages/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/react-shop/react-ecommerce/HEAD/packages/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /packages/sdk/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | indent_style = space 6 | indent_size = 2 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true -------------------------------------------------------------------------------- /packages/web/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | indent_style = space 6 | indent_size = 2 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true -------------------------------------------------------------------------------- /packages/mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/react-shop/react-ecommerce/HEAD/packages/mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /packages/mobile/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/react-shop/react-ecommerce/HEAD/packages/mobile/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /packages/mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/react-shop/react-ecommerce/HEAD/packages/mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /packages/sdk/lib/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | exports.__esModule = true; 3 | var product_provider_1 = require("./products/product.provider"); 4 | exports.ProductProvider = product_provider_1.ProductProvider; 5 | -------------------------------------------------------------------------------- /packages/ssr/src/config/routes/types.ts: -------------------------------------------------------------------------------- 1 | export type Route = (...args: string[]) => string; 2 | 3 | export interface Routes { 4 | PUBLIC: Record; 5 | PRIVATE: Record; 6 | } 7 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/question.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 💬 Question 3 | about: You need help with the project. 4 | labels: "question" 5 | --- 6 | 7 | ## Ask your Question 8 | 9 | 10 | -------------------------------------------------------------------------------- /packages/design-system/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | indent_style = space 6 | indent_size = 2 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true -------------------------------------------------------------------------------- /packages/design-system/lib/utils/theme/globalStyle.d.ts: -------------------------------------------------------------------------------- 1 | declare const GlobalStyle: import("styled-components").GlobalStyleComponent<{}, import("styled-components").DefaultTheme>; 2 | export default GlobalStyle; 3 | -------------------------------------------------------------------------------- /packages/mobile/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/react-shop/react-ecommerce/HEAD/packages/mobile/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /packages/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/react-shop/react-ecommerce/HEAD/packages/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /packages/design-system/lib/web/Grid/index.d.ts: -------------------------------------------------------------------------------- 1 | import { FunctionComponent } from 'react'; 2 | import { TGridProps } from './interface'; 3 | declare const Grid: FunctionComponent; 4 | export default Grid; 5 | -------------------------------------------------------------------------------- /packages/design-system/.storybook/addons.js: -------------------------------------------------------------------------------- 1 | import '@storybook/addon-knobs/register'; 2 | import '@storybook/addon-a11y/register'; 3 | import '@storybook/addon-docs/register'; 4 | import '@storybook/addon-actions/register'; 5 | -------------------------------------------------------------------------------- /packages/design-system/lib/Button/web/StyledButton.d.ts: -------------------------------------------------------------------------------- 1 | declare const StyledButton: import("styled-components").StyledComponent<"button", any, import("./DefaultButton").IButtonProps, never>; 2 | export default StyledButton; 3 | -------------------------------------------------------------------------------- /packages/server/src/store/dto/index.ts: -------------------------------------------------------------------------------- 1 | export { CreateStoreDto } from './create-store.dto'; 2 | export { LinkEmployeeToStoreDto } from './link-employee.dto'; 3 | export { LinkProductToStoreDto } from './link-product.dto'; 4 | -------------------------------------------------------------------------------- /packages/ssr/tests/mocks/fileTransformer.js: -------------------------------------------------------------------------------- 1 | const path = require(`path`); 2 | 3 | module.exports = { 4 | process(_, filename) { 5 | return `module.exports = ${JSON.stringify(path.basename(filename))};`; 6 | }, 7 | }; -------------------------------------------------------------------------------- /packages/design-system/lib/Button/web/OutlinedButton.d.ts: -------------------------------------------------------------------------------- 1 | declare const OutlinedButton: import("styled-components").StyledComponent<"button", any, import("./DefaultButton").IButtonProps, never>; 2 | export default OutlinedButton; 3 | -------------------------------------------------------------------------------- /tsconfig.base.json: -------------------------------------------------------------------------------- 1 | { 2 | "exclude": ["node_modules"], 3 | "files": ["./typings.d.ts"], 4 | "compilerOptions": { 5 | "jsx": "react", 6 | "esModuleInterop": true, 7 | "skipLibCheck": true 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /packages/server/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "all", 3 | "singleQuote": true, 4 | "printWidth": 100, 5 | "tabWidth": 2, 6 | "prettier/prettier": ["error",{ 7 | "endOfLine": "auto" 8 | } 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /packages/server/src/app.controller.ts: -------------------------------------------------------------------------------- 1 | import { Get, Controller } from '@nestjs/common'; 2 | 3 | @Controller() 4 | export class AppController { 5 | @Get() 6 | root(): string { 7 | return 'Health check ok!'; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /packages/server/src/product/dto/index.ts: -------------------------------------------------------------------------------- 1 | export { CreateProductDto } from './create-product.dto'; 2 | export { LinkAttributeToProductDto } from './link-attribute.dto'; 3 | export { LinkCategoryToProductDto } from './link-category.dto'; 4 | -------------------------------------------------------------------------------- /packages/mobile/android/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'mobile' 2 | apply from: file("../../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings) 3 | include ':app' 4 | -------------------------------------------------------------------------------- /packages/sdk/lib/products/product.provider.d.ts: -------------------------------------------------------------------------------- 1 | import { TGetProducts } from './product.interface'; 2 | 3 | export interface IProductProvider { 4 | getProducts: TGetProducts; 5 | } 6 | export declare const ProductProvider: IProductProvider; 7 | -------------------------------------------------------------------------------- /packages/ssr/tests/mocks/image.tsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable @next/next/no-img-element */ 2 | 3 | jest.mock(`next/image`, () => ({ src, alt }: Pick) => ( 4 | {alt} 5 | )); 6 | 7 | export {}; -------------------------------------------------------------------------------- /packages/mobile/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @format 3 | */ 4 | 5 | import {AppRegistry} from 'react-native'; 6 | import App from './App'; 7 | import {name as appName} from './app.json'; 8 | 9 | AppRegistry.registerComponent(appName, () => App); 10 | -------------------------------------------------------------------------------- /packages/sdk/lib/products/product.interface.d.ts: -------------------------------------------------------------------------------- 1 | import { IApiResponse } from '../utils/global.interface'; 2 | export interface IProduct { 3 | name: string; 4 | } 5 | export declare type TGetProducts = () => Promise>; 6 | -------------------------------------------------------------------------------- /packages/sdk/src/products/product.interface.ts: -------------------------------------------------------------------------------- 1 | import { IApiResponse } from '../utils/global.interface'; 2 | 3 | export interface IProduct { 4 | name: string; 5 | } 6 | 7 | export type TGetProducts = ( 8 | ) => Promise>; 9 | -------------------------------------------------------------------------------- /packages/design-system/lib/Grid/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | exports.__esModule = true; 3 | var Container_1 = require("./web/Container"); 4 | exports.Container = Container_1.Container; 5 | var Flex_1 = require("./web/Flex"); 6 | exports.Flex = Flex_1.Flex; 7 | -------------------------------------------------------------------------------- /packages/design-system/lib/web/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | exports.__esModule = true; 3 | var Button_1 = require("./Button"); 4 | exports.DefaultButton = Button_1.DefaultButton; 5 | var Grid_1 = require("./Grid"); 6 | exports.Grid = Grid_1["default"]; 7 | -------------------------------------------------------------------------------- /packages/design-system/lib-esm/Grid/web/Container.js: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | export const Container = styled.div ` 3 | width: 100%; 4 | height: 100%; 5 | display: flex; 6 | justify-content: center; 7 | align-items: center; 8 | `; 9 | -------------------------------------------------------------------------------- /packages/design-system/lib/web/Button/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | exports.__esModule = true; 3 | /* eslint-disable import/prefer-default-export */ 4 | var DefaultButton_1 = require("./DefaultButton"); 5 | exports.DefaultButton = DefaultButton_1["default"]; 6 | -------------------------------------------------------------------------------- /packages/sdk/src/utils/routes.constants.ts: -------------------------------------------------------------------------------- 1 | export const api = { 2 | BASE_URL: 'https://api.github.com/users/viniarruda', 3 | }; 4 | 5 | const ROOT_PRODUCTS = '/repos'; 6 | 7 | export const ENDPOINTS = { 8 | PRODUCTS: `${ROOT_PRODUCTS}`, 9 | }; 10 | -------------------------------------------------------------------------------- /packages/server/test/jest-e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "moduleFileExtensions": ["js", "json", "ts"], 3 | "rootDir": ".", 4 | "testEnvironment": "node", 5 | "testRegex": ".e2e-spec.ts$", 6 | "transform": { 7 | "^.+\\.(t|j)s$": "ts-jest" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /packages/design-system/.storybook/themeDecorator.js: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import ThemeProvider from "../src/provider" 3 | 4 | const ThemeDecorator = storyFn => ( 5 | {storyFn()} 6 | ) 7 | 8 | export default ThemeDecorator 9 | -------------------------------------------------------------------------------- /packages/design-system/lib/web/Button/StyledButton.d.ts: -------------------------------------------------------------------------------- 1 | declare const StyledButton: import("styled-components").StyledComponent<"button", import("styled-components").DefaultTheme, import("./DefaultButton").IButtonProps, never>; 2 | export default StyledButton; 3 | -------------------------------------------------------------------------------- /packages/mobile/ios/mobile/AppDelegate.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | @interface AppDelegate : UIResponder 5 | 6 | @property (nonatomic, strong) UIWindow *window; 7 | 8 | @end 9 | -------------------------------------------------------------------------------- /packages/design-system/lib/web/Button/OutlinedButton.d.ts: -------------------------------------------------------------------------------- 1 | declare const OutlinedButton: import("styled-components").StyledComponent<"button", import("styled-components").DefaultTheme, import("./DefaultButton").IButtonProps, never>; 2 | export default OutlinedButton; 3 | -------------------------------------------------------------------------------- /packages/sdk/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "exclude": ["node_modules", "lib-esm", "lib", "**/*.spec*"], 3 | "include": ["src"], 4 | "extends": "../../tsconfig.base.json", 5 | "compilerOptions": { 6 | "outDir": "lib", 7 | "declaration": true 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /packages/mobile/ios/mobile/main.m: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | #import "AppDelegate.h" 4 | 5 | int main(int argc, char * argv[]) { 6 | @autoreleasepool { 7 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /packages/mobile/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "lib": ["esnext", "dom"], 5 | "allowJs": false, 6 | "checkJs": false, 7 | "jsx": "react-native" 8 | }, 9 | "include": ["./src/**/*"] 10 | } 11 | -------------------------------------------------------------------------------- /packages/mobile/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.2-all.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /packages/sdk/lib/utils/routes.constants.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | exports.__esModule = true; 3 | exports.api = { 4 | BASE_URL: 'https://api.github.com/users/viniarruda' 5 | }; 6 | var ROOT_PRODUCTS = '/repos'; 7 | exports.ENDPOINTS = { 8 | PRODUCTS: "" + ROOT_PRODUCTS 9 | }; 10 | -------------------------------------------------------------------------------- /packages/ssr/next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | /// 4 | 5 | // NOTE: This file should not be edited 6 | // see https://nextjs.org/docs/basic-features/typescript for more information. 7 | -------------------------------------------------------------------------------- /packages/design-system/lib/Button/web/DefaultButton.d.ts: -------------------------------------------------------------------------------- 1 | export interface IButtonProps { 2 | full?: boolean; 3 | secondary?: boolean; 4 | } 5 | declare const DefaultButton: import("styled-components").StyledComponent<"button", any, IButtonProps, never>; 6 | export default DefaultButton; 7 | -------------------------------------------------------------------------------- /packages/design-system/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "exclude": ["node_modules", "lib-esm", "lib", "**/*.story*", "**/*.spec*"], 3 | "include": ["src"], 4 | "extends": "../../tsconfig.base.json", 5 | "compilerOptions": { 6 | "outDir": "lib", 7 | "declaration": true 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /packages/mobile/App.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import Routes from './src'; 4 | 5 | declare const global: {HermesInternal: null | {}}; 6 | 7 | const App = () => { 8 | return ( 9 | <> 10 | 11 | 12 | ); 13 | }; 14 | 15 | export default App; 16 | -------------------------------------------------------------------------------- /packages/server/src/attribute/attribute.interface.ts: -------------------------------------------------------------------------------- 1 | import { registerEnumType } from '@nestjs/graphql'; 2 | 3 | export enum Types { 4 | COLOR = 'color', 5 | SIZE = 'size', 6 | } 7 | 8 | registerEnumType(Types, { 9 | name: 'Types', 10 | description: 'Attribute types', 11 | }); 12 | -------------------------------------------------------------------------------- /packages/server/src/auth/dto/auth.interface.ts: -------------------------------------------------------------------------------- 1 | import { Field, ObjectType } from '@nestjs/graphql'; 2 | import { User } from '@user/user.entity'; 3 | 4 | @ObjectType() 5 | export class AuthType { 6 | @Field(() => User) 7 | user: User; 8 | 9 | @Field() 10 | token: string; 11 | } 12 | -------------------------------------------------------------------------------- /packages/design-system/lib/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | exports.__esModule = true; 3 | var web_1 = require("./web"); 4 | exports.DefaultButton = web_1.DefaultButton; 5 | exports.Grid = web_1.Grid; 6 | var globalStyle_1 = require("./theme/globalStyle"); 7 | exports.GlobalStyles = globalStyle_1["default"]; 8 | -------------------------------------------------------------------------------- /packages/sdk/lib/products/product.schema.d.ts: -------------------------------------------------------------------------------- 1 | import * as Yup from 'yup'; 2 | export declare const ProductsSchema: Yup.ArraySchema>; 6 | export declare const ProductSchema: Yup.ObjectSchema>; 9 | -------------------------------------------------------------------------------- /packages/design-system/lib/Button/web/Button.d.ts: -------------------------------------------------------------------------------- 1 | import { FunctionComponent, ReactNode } from 'react'; 2 | export interface IButton { 3 | children: ReactNode; 4 | outline?: boolean; 5 | full?: boolean; 6 | secondary?: boolean; 7 | } 8 | export declare const Button: FunctionComponent; 9 | -------------------------------------------------------------------------------- /packages/ssr/src/pages/home/index.tsx: -------------------------------------------------------------------------------- 1 | import Head from 'next/head'; 2 | 3 | import HomeScreen from '@home/screens/Main'; 4 | 5 | export default function Page() { 6 | return ( 7 | <> 8 | 9 | Home 10 | 11 | 12 | 13 | ); 14 | } 15 | -------------------------------------------------------------------------------- /packages/design-system/lib/web/Button/DefaultButton.d.ts: -------------------------------------------------------------------------------- 1 | export interface IButtonProps { 2 | full?: boolean; 3 | secondary?: boolean; 4 | } 5 | declare const DefaultButton: import("styled-components").StyledComponent<"button", import("styled-components").DefaultTheme, IButtonProps, never>; 6 | export default DefaultButton; 7 | -------------------------------------------------------------------------------- /packages/mobile/ios/mobile.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /packages/sdk/tsconfig.esm.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["src"], 3 | "extends": "./tsconfig.json", 4 | "compilerOptions": { 5 | "outDir": "lib-esm", 6 | "module": "esnext", 7 | "target": "esnext", 8 | "moduleResolution": "node", 9 | "lib": ["dom", "esnext"], 10 | "declaration": false 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/design-system/tsconfig.esm.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["src"], 3 | "extends": "./tsconfig.json", 4 | "compilerOptions": { 5 | "outDir": "lib-esm", 6 | "module": "esnext", 7 | "target": "esnext", 8 | "moduleResolution": "node", 9 | "lib": ["dom", "esnext"], 10 | "declaration": false 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/sdk/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | [ 4 | '@babel/preset-env', 5 | { 6 | targets: { 7 | node: 'current', 8 | }, 9 | }, 10 | ], 11 | '@babel/preset-typescript', 12 | ], 13 | plugins: ['@babel/plugin-proposal-export-default-from'], 14 | }; 15 | -------------------------------------------------------------------------------- /packages/sdk/src/products/product.schema.ts: -------------------------------------------------------------------------------- 1 | import * as Yup from 'yup'; 2 | 3 | export const ProductsSchema = Yup.array().of( 4 | Yup.object().shape({ 5 | id: Yup.string(), 6 | name: Yup.string(), 7 | }) 8 | ); 9 | 10 | export const ProductSchema = Yup.object().shape({ 11 | name: Yup.string().required(), 12 | }); 13 | -------------------------------------------------------------------------------- /packages/web/src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render } from 'react-dom'; 3 | import Root from './root'; 4 | 5 | // import 'slick-carousel/slick/slick.css'; 6 | // import 'slick-carousel/slick/slick-theme.css'; 7 | 8 | // eslint-disable-next-line no-undef 9 | render(, document.getElementById('root')); 10 | -------------------------------------------------------------------------------- /packages/mobile/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /packages/server/src/auth/dto/auth.input.ts: -------------------------------------------------------------------------------- 1 | import { InputType, Field } from '@nestjs/graphql'; 2 | 3 | import { IsNotEmpty } from 'class-validator'; 4 | 5 | @InputType() 6 | export class AuthDto { 7 | @Field() 8 | @IsNotEmpty() 9 | readonly email: string; 10 | 11 | @Field() 12 | @IsNotEmpty() 13 | readonly password: string; 14 | } 15 | -------------------------------------------------------------------------------- /packages/ssr/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.defaultFormatter": "esbenp.prettier-vscode", 3 | "editor.formatOnSave": true, 4 | "editor.formatOnPaste": true, 5 | "editor.codeActionsOnSave": { 6 | "source.fixAll": true, 7 | "source.organizeImports": false 8 | }, 9 | "search.exclude": { 10 | "coverage": true 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/server/src/main.ts: -------------------------------------------------------------------------------- 1 | import { NestFactory } from '@nestjs/core'; 2 | 3 | import { AppModule } from './app.module'; 4 | 5 | async function bootstrap() { 6 | const appOptions = { cors: true }; 7 | const app = await NestFactory.create(AppModule, appOptions); 8 | 9 | app.setGlobalPrefix('api'); 10 | 11 | await app.listen(5000); 12 | } 13 | bootstrap(); 14 | -------------------------------------------------------------------------------- /packages/design-system/lib/Grid/web/Flex.d.ts: -------------------------------------------------------------------------------- 1 | export interface IFlexProps { 2 | justify?: 'center' | 'flex-start' | 'space-between' | 'flex-end'; 3 | align?: 'center' | 'flex-start' | 'space-between' | 'flex-end' | 'stretch'; 4 | direction?: 'row' | 'column'; 5 | } 6 | export declare const Flex: import("styled-components").StyledComponent<"div", any, IFlexProps, never>; 7 | -------------------------------------------------------------------------------- /packages/design-system/lib/web/Grid/Flex.d.ts: -------------------------------------------------------------------------------- 1 | export interface IFlexProps { 2 | justify?: 'center' | 'flex-start' | 'space-between' | 'flex-end'; 3 | align?: 'center' | 'flex-start' | 'space-between' | 'flex-end' | 'stretch'; 4 | direction?: 'row' | 'column'; 5 | } 6 | export declare const Flex: import("styled-components").StyledComponent<"div", any, IFlexProps, never>; 7 | -------------------------------------------------------------------------------- /packages/design-system/src/web/Grid/styles.tsx: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | 3 | import { 4 | border, color, flexbox, layout, position, space, 5 | } from 'styled-system'; 6 | 7 | const Container = styled.div` 8 | ${border} 9 | ${color} 10 | ${flexbox} 11 | ${layout} 12 | ${position} 13 | ${space} 14 | `; 15 | 16 | export default Container; 17 | -------------------------------------------------------------------------------- /packages/design-system/src/provider/index.tsx: -------------------------------------------------------------------------------- 1 | import React, { FunctionComponent } from 'react'; 2 | 3 | import { ThemeProvider } from 'styled-components'; 4 | 5 | import { theme } from '../theme'; 6 | 7 | const ContainerTheme: FunctionComponent = ({ children }) => ( 8 | {children} 9 | ); 10 | 11 | export default ContainerTheme; 12 | -------------------------------------------------------------------------------- /packages/design-system/src/web/Button/OutlinedButton/interface.ts: -------------------------------------------------------------------------------- 1 | import { TColorsTypes } from '../../../interfaces'; 2 | 3 | export type TDefaultButtonProps = { 4 | text: string; 5 | onClick: () => void; 6 | borderColor: TColorsTypes; 7 | } 8 | 9 | export type TContainerStyleProps = { 10 | width: number; 11 | height: number; 12 | borderColor: TColorsTypes; 13 | } 14 | -------------------------------------------------------------------------------- /packages/server/src/shared/base.controller.ts: -------------------------------------------------------------------------------- 1 | import * as jwt from 'jsonwebtoken'; 2 | 3 | export class BaseController { 4 | protected getUserIdFromToken(authorization) { 5 | if (!authorization) return null; 6 | 7 | const token = authorization.split(' ')[1]; 8 | const decoded: any = jwt.verify(token, process.env.SECRET); 9 | return decoded.id; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: ✨ Feature request 3 | about: Suggest an idea. 4 | labels: "enhancement" 5 | --- 6 | 7 | ## Describe the Feature 8 | 9 | 10 | 11 | ## Possible Implementations 12 | 13 | 14 | 15 | ## Related Issues 16 | 17 | 18 | -------------------------------------------------------------------------------- /packages/design-system/lib-esm/theme/globalStyle.js: -------------------------------------------------------------------------------- 1 | import { createGlobalStyle } from 'styled-components'; 2 | const GlobalStyle = createGlobalStyle ` 3 | @import url("https://use.typekit.net/pqn7oor.css"); 4 | * { 5 | padding: 0; 6 | margin: 0; 7 | box-sizing: border-box; 8 | font-family: proxima-nova, sans-serif; 9 | } 10 | `; 11 | export default GlobalStyle; 12 | -------------------------------------------------------------------------------- /packages/design-system/src/interfaces/colors.ts: -------------------------------------------------------------------------------- 1 | export type TColors = { 2 | primary: string; 3 | secondary: string; 4 | primaryDark: string; 5 | secondaryDark: string; 6 | error: string; 7 | black: string; 8 | blackNormal: string; 9 | blackDark: string; 10 | blackLight: string; 11 | white: string; 12 | gray: string; 13 | } 14 | 15 | export type TColorsTypes = keyof TColors; 16 | -------------------------------------------------------------------------------- /packages/design-system/src/theme/globalStyle.tsx: -------------------------------------------------------------------------------- 1 | import { createGlobalStyle } from 'styled-components'; 2 | 3 | const GlobalStyle = createGlobalStyle` 4 | @import url("https://use.typekit.net/pqn7oor.css"); 5 | * { 6 | padding: 0; 7 | margin: 0; 8 | box-sizing: border-box; 9 | font-family: proxima-nova, sans-serif; 10 | } 11 | `; 12 | 13 | export default GlobalStyle; 14 | -------------------------------------------------------------------------------- /packages/design-system/lib/theme/index.d.ts: -------------------------------------------------------------------------------- 1 | import { DefaultTheme } from 'styled-components/native'; 2 | import { TColors, TSpacingSizes, TBorderRadius } from '../interfaces'; 3 | declare module 'styled-components' { 4 | interface DefaultTheme { 5 | colors: TColors; 6 | space: TSpacingSizes; 7 | radii: TBorderRadius; 8 | } 9 | } 10 | export declare const theme: DefaultTheme; 11 | -------------------------------------------------------------------------------- /packages/web/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": "./index.html", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /packages/design-system/src/theme/colors.ts: -------------------------------------------------------------------------------- 1 | const colors = { 2 | primary: '#43FECB', 3 | secondary: '#743AF2', 4 | primaryDark: '#6ffcd6', 5 | secondaryDark: '#9c73f5', 6 | error: '#FF3773', 7 | black: '#1F1F24', 8 | blackNormal: '#34353D', 9 | blackDark: '#27272D', 10 | blackLight: '#484854', 11 | white: '#FFFFFF', 12 | gray: '#cccccc', 13 | }; 14 | 15 | export default { 16 | ...colors, 17 | }; 18 | -------------------------------------------------------------------------------- /packages/server/src/store/dto/link-employee.dto.ts: -------------------------------------------------------------------------------- 1 | import { InputType, Field, ID } from '@nestjs/graphql'; 2 | import { IsNotEmpty, IsNumber } from 'class-validator'; 3 | 4 | @InputType() 5 | export class LinkEmployeeToStoreDto { 6 | @Field() 7 | @IsNumber() 8 | @IsNotEmpty({ message: 'Field required ' }) 9 | readonly storeId: string; 10 | 11 | @Field(() => [ID]) 12 | readonly employeesId: string[]; 13 | } 14 | -------------------------------------------------------------------------------- /packages/web/src/store/index.ts: -------------------------------------------------------------------------------- 1 | import { createStore, applyMiddleware } from 'redux'; 2 | import createSagaMiddleware from 'redux-saga'; 3 | 4 | import reducers from './reducers'; 5 | import sagas from './sagas'; 6 | 7 | const sagaMiddleware = createSagaMiddleware(); 8 | 9 | const store = createStore(reducers(), applyMiddleware(sagaMiddleware)); 10 | 11 | sagaMiddleware.run(sagas); 12 | 13 | export default store; 14 | -------------------------------------------------------------------------------- /packages/mobile/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | extends: ['@react-native-community', 'plugin:@typescript-eslint/recommended'], 4 | parser: '@typescript-eslint/parser', 5 | parserOptions: { 6 | ecmaVersion: 2018, 7 | sourceType: 'module', 8 | }, 9 | plugins: ['@typescript-eslint'], 10 | "rules": { 11 | "@typescript-eslint/explicit-function-return-type": "off", 12 | } 13 | }; 14 | -------------------------------------------------------------------------------- /packages/server/src/store/dto/link-product.dto.ts: -------------------------------------------------------------------------------- 1 | import { InputType, Field, ID } from '@nestjs/graphql'; 2 | import { IsNotEmpty, IsString } from 'class-validator'; 3 | 4 | @InputType() 5 | export class LinkProductToStoreDto { 6 | @Field(() => ID) 7 | @IsString() 8 | @IsNotEmpty({ message: 'Field required ' }) 9 | readonly storeId: string; 10 | 11 | @Field(() => [ID]) 12 | readonly productsId: string[]; 13 | } 14 | -------------------------------------------------------------------------------- /packages/mobile/android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /packages/server/src/product/dto/link-attribute.dto.ts: -------------------------------------------------------------------------------- 1 | import { InputType, Field, ID } from '@nestjs/graphql'; 2 | import { IsNotEmpty, IsString } from 'class-validator'; 3 | 4 | @InputType() 5 | export class LinkAttributeToProductDto { 6 | @Field(() => ID) 7 | @IsString() 8 | @IsNotEmpty({ message: 'Field required ' }) 9 | readonly productId: string; 10 | 11 | @Field(() => [ID]) 12 | readonly attributesId: string[]; 13 | } 14 | -------------------------------------------------------------------------------- /packages/ssr/src/pages/index.tsx: -------------------------------------------------------------------------------- 1 | import { GetServerSideProps } from 'next'; 2 | 3 | import { ROUTES } from '@config/routes'; 4 | 5 | const Index = () => { 6 | return null; 7 | }; 8 | 9 | export const getServerSideProps: GetServerSideProps = async (context) => { 10 | return { 11 | redirect: { 12 | destination: ROUTES.PRIVATE.ROOT(), 13 | permanent: false, 14 | }, 15 | }; 16 | }; 17 | 18 | export default Index; 19 | -------------------------------------------------------------------------------- /packages/design-system/lib-esm/Button/web/StyledButton.js: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | import theme from '../../theme'; 3 | import DefaultButton from './DefaultButton'; 4 | const StyledButton = styled(DefaultButton) ` 5 | background-color: ${(props) => (props.secondary ? theme.colors.secondary : theme.colors.primary)}; 6 | color: ${(props) => (props.secondary ? theme.colors.white : theme.colors.black)}; 7 | `; 8 | export default StyledButton; 9 | -------------------------------------------------------------------------------- /packages/design-system/lib-esm/Button/web/Button.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import StyledButton from './StyledButton'; 3 | import OutlinedButton from './OutlinedButton'; 4 | export const Button = ({ children, outline, full, secondary, }) => (React.createElement(React.Fragment, null, outline ? React.createElement(OutlinedButton, { full: full, secondary: secondary }, children) : React.createElement(StyledButton, { full: full, secondary: secondary }, children))); 5 | -------------------------------------------------------------------------------- /packages/sdk/src/products/product.provider.ts: -------------------------------------------------------------------------------- 1 | import { http as httpClient } from '../utils/httpClient'; 2 | 3 | import { 4 | TGetProducts, 5 | } from './product.interface'; 6 | import { ENDPOINTS } from '../utils/routes.constants'; 7 | 8 | export interface IProductProvider { 9 | getProducts: TGetProducts; 10 | } 11 | 12 | export const ProductProvider: IProductProvider = { 13 | getProducts: async () => httpClient.get(`${ENDPOINTS.PRODUCTS}`), 14 | }; 15 | -------------------------------------------------------------------------------- /packages/mobile/android/app/src/main/java/com/mobile/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.mobile; 2 | 3 | import com.facebook.react.ReactActivity; 4 | 5 | public class MainActivity extends ReactActivity { 6 | 7 | /** 8 | * Returns the name of the main component registered from JavaScript. This is used to schedule 9 | * rendering of the component. 10 | */ 11 | @Override 12 | protected String getMainComponentName() { 13 | return "mobile"; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /packages/server/src/category/dto/create-category.dto.ts: -------------------------------------------------------------------------------- 1 | import { InputType, Field } from '@nestjs/graphql'; 2 | import { IsNotEmpty, IsString } from 'class-validator'; 3 | 4 | @InputType() 5 | export class CreateCategoryDto { 6 | @Field() 7 | @IsString() 8 | @IsNotEmpty({ message: 'Field required ' }) 9 | readonly name: string; 10 | 11 | @Field() 12 | @IsString() 13 | @IsNotEmpty({ message: 'Field required ' }) 14 | readonly description: string; 15 | } 16 | -------------------------------------------------------------------------------- /packages/design-system/src/web/Button/OutlinedButton/index.tsx: -------------------------------------------------------------------------------- 1 | import React, { FunctionComponent } from 'react'; 2 | 3 | import Container from './styles'; 4 | 5 | import { TDefaultButtonProps } from './interface'; 6 | 7 | const Button: FunctionComponent = ({ text, onClick, borderColor }) => ( 8 | 9 | {text} 10 | 11 | ); 12 | 13 | export default Button; 14 | -------------------------------------------------------------------------------- /packages/server/src/user/user.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { TypeOrmModule } from '@nestjs/typeorm'; 3 | 4 | import { UserResolver } from '@user/user.resolver'; 5 | import { User } from '@user/user.entity'; 6 | import { UserService } from '@user/user.service'; 7 | 8 | @Module({ 9 | imports: [TypeOrmModule.forFeature([User])], 10 | providers: [UserService, UserResolver], 11 | exports: [UserService], 12 | }) 13 | export class UserModule {} 14 | -------------------------------------------------------------------------------- /packages/design-system/lib/utils/config/setupEnzyme.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __importDefault = (this && this.__importDefault) || function (mod) { 3 | return (mod && mod.__esModule) ? mod : { "default": mod }; 4 | }; 5 | exports.__esModule = true; 6 | var enzyme_1 = require("enzyme"); 7 | var enzyme_adapter_react_16_1 = __importDefault(require("enzyme-adapter-react-16")); 8 | require("jest-enzyme"); 9 | enzyme_1.configure({ adapter: new enzyme_adapter_react_16_1["default"]() }); 10 | -------------------------------------------------------------------------------- /packages/server/src/product/dto/link-category.dto.ts: -------------------------------------------------------------------------------- 1 | import { InputType, Field, ID } from '@nestjs/graphql'; 2 | import { IsNotEmpty, IsString } from 'class-validator'; 3 | 4 | @InputType() 5 | export class LinkCategoryToProductDto { 6 | @Field(() => ID) 7 | @IsString() 8 | @IsNotEmpty({ message: 'Field required ' }) 9 | readonly productId: string; 10 | 11 | @Field(() => [ID]) 12 | @IsNotEmpty({ message: 'Field required ' }) 13 | readonly categoriesId: string[]; 14 | } 15 | -------------------------------------------------------------------------------- /packages/ssr/src/config/routes/index.ts: -------------------------------------------------------------------------------- 1 | import { Route, Routes } from './types'; 2 | 3 | const mapParameters = (base: string): Route => { 4 | return (...args: string[]) => { 5 | return `/${base}${args.map((parameter) => `/${parameter}`)}`; 6 | }; 7 | }; 8 | 9 | export const ROUTES: Routes = { 10 | PUBLIC: { 11 | ROOT: mapParameters(`home`), 12 | SIGNIN: mapParameters(`sign-in`), 13 | }, 14 | PRIVATE: { 15 | ROOT: mapParameters(`home`), 16 | }, 17 | }; 18 | -------------------------------------------------------------------------------- /packages/mobile/src/index.tsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect } from 'react'; 2 | 3 | import { SafeAreaView, View, Text } from 'react-native'; 4 | 5 | import { ProductProvider } from '@react-shop/sdk'; 6 | 7 | const Routes = () => { 8 | useEffect(() => { 9 | ProductProvider.getProducts(); 10 | }, []); 11 | 12 | return ( 13 | 14 | 15 | Routes 16 | 17 | 18 | ); 19 | }; 20 | 21 | export default Routes; 22 | -------------------------------------------------------------------------------- /packages/server/src/auth/auth.guard.ts: -------------------------------------------------------------------------------- 1 | import { Injectable, ExecutionContext } from '@nestjs/common'; 2 | import { GqlExecutionContext } from '@nestjs/graphql'; 3 | import { AuthGuard } from '@nestjs/passport'; 4 | import { Request } from 'express'; 5 | 6 | @Injectable() 7 | export class GqlAuthGuard extends AuthGuard('jwt') { 8 | getRequest(context: ExecutionContext): Request { 9 | const ctx = GqlExecutionContext.create(context); 10 | 11 | return ctx.getContext().req; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/design-system/src/web/Grid/index.tsx: -------------------------------------------------------------------------------- 1 | import React, { FunctionComponent } from 'react'; 2 | 3 | import Container from './styles'; 4 | 5 | import { TGridProps } from './interface'; 6 | 7 | // import Skeleton from '../Skeleton'; 8 | 9 | const Grid: FunctionComponent = ({ 10 | children, 11 | skeleton, 12 | skeletonHeight, 13 | skeletonWidth, 14 | ...rest 15 | }) => ( 16 | 17 | {children} 18 | 19 | ); 20 | 21 | export default Grid; 22 | -------------------------------------------------------------------------------- /packages/mobile/android/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | -------------------------------------------------------------------------------- /packages/design-system/src/web/Button/story/Button.story.mdx: -------------------------------------------------------------------------------- 1 | import {Meta, Story, Preview} from '@storybook/addon-docs/blocks'; 2 | import DefaultButton from '../DefaultButton'; 3 | 4 | 5 | 6 | # Button 7 | 8 | With `MDX` we can define a story for `DefaultButton` right in the middle of our 9 | markdown documentation. 10 | 11 | 12 | 13 | 'clicked'} /> 14 | 15 | 16 | -------------------------------------------------------------------------------- /packages/design-system/src/web/Button/DefaultButton/styles.tsx: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | import { color, layout, border } from 'styled-system'; 3 | 4 | import { TContainerStyleProps } from './interface'; 5 | 6 | const Container = styled.button` 7 | ${color} 8 | ${layout} 9 | ${border} 10 | 11 | box-shadow: 0px 10px 12px rgba(0,0,0,0.2); 12 | 13 | &:hover { 14 | background-color: ${({ hoverColor, theme }) => theme.colors[hoverColor]} 15 | } 16 | `; 17 | 18 | export default Container; 19 | -------------------------------------------------------------------------------- /packages/server/src/category/category.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { TypeOrmModule } from '@nestjs/typeorm'; 3 | 4 | import { Category } from '@category/category.entity'; 5 | import { CategoryService } from '@category/category.service'; 6 | import { CategoryResolver } from '@category/category.resolver'; 7 | 8 | @Module({ 9 | imports: [TypeOrmModule.forFeature([Category])], 10 | providers: [CategoryResolver, CategoryService], 11 | exports: [CategoryService], 12 | }) 13 | export class CategoryModule {} 14 | -------------------------------------------------------------------------------- /packages/web/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["src"], 3 | "extends": "../../tsconfig.base.json", 4 | "compilerOptions": { 5 | "target": "es5", 6 | "lib": ["dom", "dom.iterable", "esnext"], 7 | "allowJs": true, 8 | "skipLibCheck": true, 9 | "allowSyntheticDefaultImports": true, 10 | "strict": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "module": "esnext", 13 | "moduleResolution": "node", 14 | "resolveJsonModule": true, 15 | "isolatedModules": true, 16 | "noEmit": true 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /packages/design-system/src/theme/units.ts: -------------------------------------------------------------------------------- 1 | const sizes = { 2 | spacing1: 1, 3 | spacing2: 2, 4 | spacing4: 4, 5 | spacing8: 8, 6 | spacing10: 10, 7 | spacing12: 12, 8 | spacing16: 16, 9 | spacing18: 18, 10 | spacing20: 20, 11 | spacing24: 24, 12 | spacing32: 32, 13 | }; 14 | 15 | const borderRadius = { 16 | xsmall: sizes.spacing2, 17 | small: sizes.spacing4, 18 | medium: sizes.spacing8, 19 | large: sizes.spacing12, 20 | full: sizes.spacing32, 21 | }; 22 | 23 | export default { 24 | sizes, 25 | borderRadius, 26 | }; 27 | -------------------------------------------------------------------------------- /packages/sdk/__tests__/products/products.spec.ts: -------------------------------------------------------------------------------- 1 | import { ProductProvider } from '../../src/products/product.provider'; 2 | import { ProductsSchema } from '../../src/products/product.schema'; 3 | 4 | describe('Integration | Test get product', () => { 5 | it('should be return all products', async () => { 6 | const { data } = await ProductProvider.getProducts(); 7 | 8 | const isValidSchema = await ProductsSchema.isValid(data); 9 | 10 | expect(isValidSchema).toBe(true); 11 | expect(data.length).toBeGreaterThan(1); 12 | }); 13 | }); 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /build 11 | 12 | # misc 13 | .DS_Store 14 | .env.local 15 | .env.development.local 16 | .env.test.local 17 | .env.production.local 18 | 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* 22 | 23 | # IDE 24 | .idea/ 25 | 26 | packages/**/lib 27 | packages/**/lib-esm 28 | 29 | 30 | # next.js 31 | packages/ssr/out 32 | packages/ssr/.next 33 | packages/ssr/.vercel -------------------------------------------------------------------------------- /packages/server/src/attribute/attribute.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { TypeOrmModule } from '@nestjs/typeorm'; 3 | 4 | import { Attribute } from '@attribute/attribute.entity'; 5 | import { AttributeService } from '@attribute/attribute.service'; 6 | import { AttributeResolver } from '@attribute/attribute.resolver'; 7 | 8 | @Module({ 9 | imports: [TypeOrmModule.forFeature([Attribute])], 10 | providers: [AttributeService, AttributeResolver], 11 | exports: [AttributeService], 12 | }) 13 | export class AttributeModule {} 14 | -------------------------------------------------------------------------------- /packages/design-system/src/web/Button/OutlinedButton/styles.tsx: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | import { color, layout, border } from 'styled-system'; 3 | 4 | import { TContainerStyleProps } from './interface'; 5 | 6 | const Container = styled.button` 7 | ${color} 8 | ${layout} 9 | ${border} 10 | 11 | box-shadow: 0px 10px 12px rgba(0,0,0,0.2); 12 | background-color: transparent; 13 | 14 | &:hover { 15 | background-color: ${({ theme }) => theme.colors.primaryDark} 16 | } 17 | `; 18 | 19 | export default Container; 20 | -------------------------------------------------------------------------------- /packages/ssr/next.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | module.exports = { 4 | webpack: (config, options) => { 5 | const configExternals = ['styled-components', 'react', 'react-dom']; 6 | if (options.isServer) { 7 | config.externals = [...configExternals, ...config.externals]; 8 | } 9 | 10 | configExternals.forEach((configExternal) => { 11 | config.resolve.alias[configExternal] = path.resolve( 12 | __dirname, 13 | '.', 14 | 'node_modules', 15 | configExternal, 16 | ); 17 | }); 18 | 19 | return config; 20 | }, 21 | }; -------------------------------------------------------------------------------- /packages/mobile/metro.config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Metro configuration for React Native 3 | * https://github.com/facebook/react-native 4 | * 5 | * @format 6 | */ 7 | 8 | const path = require('path'); 9 | 10 | module.exports = { 11 | projectRoot: path.resolve(__dirname, '.'), 12 | 13 | watchFolders: [ 14 | path.resolve(__dirname, '../'), 15 | path.resolve(__dirname, '../../node_modules'), 16 | ], 17 | transformer: { 18 | getTransformOptions: async () => ({ 19 | transform: { 20 | experimentalImportSupport: false, 21 | inlineRequires: false, 22 | }, 23 | }), 24 | }, 25 | }; 26 | -------------------------------------------------------------------------------- /packages/server/.gitignore: -------------------------------------------------------------------------------- 1 | # compiled output 2 | /dist 3 | /node_modules 4 | 5 | # Logs 6 | logs 7 | *.log 8 | npm-debug.log* 9 | pnpm-debug.log* 10 | yarn-debug.log* 11 | yarn-error.log* 12 | lerna-debug.log* 13 | 14 | # OS 15 | .DS_Store 16 | 17 | # Tests 18 | /coverage 19 | /.nyc_output 20 | 21 | # IDEs and editors 22 | /.idea 23 | .project 24 | .classpath 25 | .c9/ 26 | *.launch 27 | .settings/ 28 | *.sublime-workspace 29 | 30 | # IDE - VSCode 31 | .vscode/* 32 | !.vscode/settings.json 33 | !.vscode/tasks.json 34 | !.vscode/launch.json 35 | !.vscode/extensions.json 36 | 37 | .env.development 38 | .env.production 39 | .env -------------------------------------------------------------------------------- /packages/design-system/src/interfaces/align.ts: -------------------------------------------------------------------------------- 1 | export type TAligns = 'flex-start' | 'center' | 'flex-end'; 2 | 3 | export type TAlignItems = TAligns | 'stretch' | 'baseline'; 4 | 5 | export type TJustifyContent = 6 | | TAligns 7 | | 'space-between' 8 | | 'space-around' 9 | | 'space-evenly'; 10 | 11 | export type TFlexDirection = 'row' | 'column' | 'row-reverse' | 'column-reverse'; 12 | 13 | export type TAlignContent = TAligns | 'space-between' | 'space-around'; 14 | 15 | export type TFlexWrap = 'nowrap' | 'wrap'; 16 | 17 | export type TPosition = 'relative' | 'absolute'; 18 | 19 | export type TSizes = 'auto' | string; 20 | -------------------------------------------------------------------------------- /packages/web/src/root/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Provider } from 'react-redux'; 3 | import { BrowserRouter as Router, Route, Switch } from 'react-router-dom'; 4 | 5 | import { GlobalStyles } from '@react-shop/design-system'; 6 | 7 | import store from '../store'; 8 | 9 | import Home from '../modules/views/home'; 10 | 11 | const Root = () => ( 12 | 13 | 14 | 15 | <> 16 | 17 | 18 | 19 | 20 | 21 | 22 | ); 23 | 24 | export default Root; 25 | -------------------------------------------------------------------------------- /packages/sdk/lib/products/product.schema.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __importStar = (this && this.__importStar) || function (mod) { 3 | if (mod && mod.__esModule) return mod; 4 | var result = {}; 5 | if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; 6 | result["default"] = mod; 7 | return result; 8 | }; 9 | exports.__esModule = true; 10 | var Yup = __importStar(require("yup")); 11 | exports.ProductsSchema = Yup.array().of(Yup.object().shape({ 12 | id: Yup.string(), 13 | name: Yup.string() 14 | })); 15 | exports.ProductSchema = Yup.object().shape({ 16 | name: Yup.string().required() 17 | }); 18 | -------------------------------------------------------------------------------- /packages/server/src/attribute/dto/create-attribute.dto.ts: -------------------------------------------------------------------------------- 1 | import { Types } from '@attribute/attribute.interface'; 2 | import { InputType, Field } from '@nestjs/graphql'; 3 | import { IsNotEmpty, IsString, IsEnum } from 'class-validator'; 4 | 5 | @InputType() 6 | export class CreateAttributeDto { 7 | @Field() 8 | @IsString() 9 | @IsNotEmpty({ message: 'Field required ' }) 10 | readonly value: string; 11 | 12 | @Field() 13 | @IsString() 14 | @IsNotEmpty({ message: 'Field required ' }) 15 | readonly name: string; 16 | 17 | @Field(() => Types) 18 | @IsEnum(Types) 19 | @IsNotEmpty({ message: 'Field required ' }) 20 | readonly type: Types; 21 | } 22 | -------------------------------------------------------------------------------- /packages/design-system/lib-esm/Button/web/DefaultButton.js: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | import theme from '../../theme'; 3 | const DefaultButton = styled.button ` 4 | padding: 15px 55px; 5 | border: none; 6 | border-radius: 6px; 7 | width: ${(props) => (props.full ? '100%' : 'auto')}; 8 | text-align: center; 9 | font-family: proxima-nova, sans-serif; 10 | font-size: ${theme.fonts.sizes.body}; 11 | cursor: pointer; 12 | 13 | &:hover { 14 | box-shadow: ${(props) => (props.secondary ? 'none' : '0px 11px 16px rgba(40, 245, 190, 0.2)')}; 15 | opacity: ${(props) => (props.secondary ? 0.8 : 1)} 16 | } 17 | `; 18 | export default DefaultButton; 19 | -------------------------------------------------------------------------------- /packages/server/src/auth/auth.resolver.ts: -------------------------------------------------------------------------------- 1 | import { Args, Mutation, Resolver } from '@nestjs/graphql'; 2 | 3 | import { AuthDto } from '@auth/dto/auth.input'; 4 | import { AuthType } from '@auth/dto/auth.interface'; 5 | import { AuthService } from '@auth/auth.service'; 6 | 7 | @Resolver('Auth') 8 | export class AuthResolver { 9 | constructor(private authService: AuthService) {} 10 | 11 | @Mutation(() => AuthType) 12 | public async login(@Args('data') data: AuthDto): Promise { 13 | const response = await this.authService.validateUser(data); 14 | 15 | return { 16 | user: response.user, 17 | token: response.token, 18 | }; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /packages/mobile/android/app/build_defs.bzl: -------------------------------------------------------------------------------- 1 | """Helper definitions to glob .aar and .jar targets""" 2 | 3 | def create_aar_targets(aarfiles): 4 | for aarfile in aarfiles: 5 | name = "aars__" + aarfile[aarfile.rindex("/") + 1:aarfile.rindex(".aar")] 6 | lib_deps.append(":" + name) 7 | android_prebuilt_aar( 8 | name = name, 9 | aar = aarfile, 10 | ) 11 | 12 | def create_jar_targets(jarfiles): 13 | for jarfile in jarfiles: 14 | name = "jars__" + jarfile[jarfile.rindex("/") + 1:jarfile.rindex(".jar")] 15 | lib_deps.append(":" + name) 16 | prebuilt_jar( 17 | name = name, 18 | binary_jar = jarfile, 19 | ) 20 | -------------------------------------------------------------------------------- /packages/design-system/lib/web/Button/Button.d.ts: -------------------------------------------------------------------------------- 1 | import { FunctionComponent, MouseEvent, ReactNode } from 'react'; 2 | declare type Props = { 3 | /** 4 | * Component to be rendered 5 | */ 6 | children: ReactNode; 7 | /** 8 | * Set this if you want a transparent bg button 9 | */ 10 | outline?: boolean; 11 | /** 12 | * Full width button 13 | */ 14 | full?: boolean; 15 | /** 16 | * Button variant 17 | */ 18 | secondary?: boolean; 19 | /** 20 | * onClick event, that inherits the onClick from React Event 21 | */ 22 | onClick: (e: MouseEvent) => void; 23 | }; 24 | declare const Button: FunctionComponent; 25 | export default Button; 26 | -------------------------------------------------------------------------------- /packages/design-system/src/theme/index.ts: -------------------------------------------------------------------------------- 1 | import { DefaultTheme } from 'styled-components/native'; 2 | 3 | import colors from './colors'; 4 | import units from './units'; 5 | 6 | import { 7 | TColors, 8 | TSpacingSizes, 9 | TBorderRadius, 10 | } from '../interfaces'; 11 | 12 | declare module 'styled-components' { 13 | // eslint-disable-next-line @typescript-eslint/interface-name-prefix 14 | export interface DefaultTheme { 15 | colors: TColors; 16 | space: TSpacingSizes; 17 | radii: TBorderRadius; 18 | } 19 | } 20 | 21 | export const theme: DefaultTheme = { 22 | colors: { 23 | ...colors, 24 | }, 25 | space: { 26 | ...units.sizes, 27 | }, 28 | radii: { 29 | ...units.borderRadius, 30 | }, 31 | }; 32 | -------------------------------------------------------------------------------- /packages/server/docker-compose.yml: -------------------------------------------------------------------------------- 1 | # Use postgres/example user/password credentials 2 | version: '3.1' 3 | 4 | services: 5 | db: 6 | container_name: pg_database 7 | image: postgres 8 | restart: always 9 | ports: 10 | - '${DATABASE_PORT}:${DATABASE_PORT}' 11 | hostname: '${DATABASE_HOST}' 12 | environment: 13 | POSTGRES_USER: '${DATABASE_USER}' 14 | POSTGRES_PASSWORD: '${DATABASE_PASSWORD}' 15 | POSTGRES_DB: '${DATABASE_NAME}' 16 | pgadmin: 17 | container_name: pgadmin4_container 18 | image: dpage/pgadmin4 19 | restart: always 20 | environment: 21 | PGADMIN_DEFAULT_EMAIL: admin@admin.com 22 | PGADMIN_DEFAULT_PASSWORD: root 23 | ports: 24 | - "5050:80" 25 | -------------------------------------------------------------------------------- /packages/server/src/store/store.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { TypeOrmModule } from '@nestjs/typeorm'; 3 | 4 | import { Store } from '@store/store.entity'; 5 | import { StoreService } from '@store/store.service'; 6 | import { StoreResolver } from '@store/store.resolver'; 7 | import { User } from '@user/user.entity'; 8 | import { Product } from '@product/product.entity'; 9 | import { Helpers } from '@utils/helpers'; 10 | 11 | @Module({ 12 | imports: [ 13 | TypeOrmModule.forFeature([Store]), 14 | TypeOrmModule.forFeature([User]), 15 | TypeOrmModule.forFeature([Product]), 16 | ], 17 | providers: [StoreService, StoreResolver, Helpers], 18 | exports: [StoreService], 19 | }) 20 | export class StoreModule {} 21 | -------------------------------------------------------------------------------- /packages/web/src/modules/views/home/index.tsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from 'react'; 2 | import { Button, Container } from '@react-shop/design-system'; 3 | import { ProductProvider } from '@react-shop/sdk'; 4 | 5 | const Home = () => { 6 | const fetchProducts = async () => { 7 | const response = await ProductProvider.getProducts(); 8 | 9 | console.log('response', response); 10 | }; 11 | 12 | useEffect(() => { 13 | fetchProducts(); 14 | }, []); 15 | 16 | const [text, setText] = useState('My Button'); 17 | 18 | return ( 19 | 20 | 23 | 24 | ); 25 | }; 26 | 27 | export default Home; 28 | -------------------------------------------------------------------------------- /packages/mobile/ios/Podfile: -------------------------------------------------------------------------------- 1 | require_relative '../../../node_modules/react-native/scripts/react_native_pods' 2 | require_relative '../../../node_modules/@react-native-community/cli-platform-ios/native_modules' 3 | 4 | platform :ios, '10.0' 5 | 6 | target 'mobile' do 7 | config = use_native_modules! 8 | 9 | use_react_native!(:path => '../../../node_modules/react-native') 10 | 11 | target 'mobileTests' do 12 | inherit! :complete 13 | # Pods for testing 14 | end 15 | 16 | # Enables Flipper. 17 | # 18 | # Note that if you have use_frameworks! enabled, Flipper will not work and 19 | # you should disable these next few lines. 20 | use_flipper! 21 | post_install do |installer| 22 | flipper_post_install(installer) 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /packages/server/test/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from '@nestjs/testing'; 2 | import { INestApplication } from '@nestjs/common'; 3 | import * as request from 'supertest'; 4 | import { AppModule } from '../src/app.module'; 5 | 6 | describe('AppController (e2e)', () => { 7 | let app: INestApplication; 8 | 9 | beforeEach(async () => { 10 | const moduleFixture: TestingModule = await Test.createTestingModule({ 11 | imports: [AppModule], 12 | }).compile(); 13 | 14 | app = moduleFixture.createNestApplication(); 15 | await app.init(); 16 | }); 17 | 18 | it('/ (GET)', () => { 19 | return request(app.getHttpServer()) 20 | .get('/') 21 | .expect(200) 22 | .expect('Hello World!'); 23 | }); 24 | }); 25 | -------------------------------------------------------------------------------- /packages/design-system/lib-esm/Button/web/OutlinedButton.js: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | import theme from '../../theme'; 3 | import DefaultButton from './DefaultButton'; 4 | const OutlinedButton = styled(DefaultButton) ` 5 | border: 1px solid ${(props) => (props.secondary ? theme.colors.secondary : theme.colors.primary)}; 6 | color: ${(props) => (props.secondary ? theme.colors.secondary : theme.colors.primary)}; 7 | font-weight: ${theme.fonts.weight.semiBold}; 8 | background-color: transparent; 9 | 10 | &:hover { 11 | background-color: ${(props) => (props.secondary ? theme.colors.secondary : theme.colors.primary)}; 12 | color: ${(props) => (props.secondary ? theme.colors.white : theme.colors.black)}; 13 | } 14 | `; 15 | export default OutlinedButton; 16 | -------------------------------------------------------------------------------- /packages/ssr/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "lib": ["dom", "dom.iterable", "esnext", "ES2020"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "forceConsistentCasingInFileNames": true, 9 | "noEmit": true, 10 | "esModuleInterop": true, 11 | "module": "esnext", 12 | "moduleResolution": "node", 13 | "resolveJsonModule": true, 14 | "isolatedModules": true, 15 | "jsx": "preserve", 16 | "baseUrl": "./src", 17 | "paths": { 18 | "@pages/*": ["./pages/*"], 19 | "@home/*": ["./modules/home/*"], 20 | "@config/*": ["./config/*"] 21 | } 22 | }, 23 | "exclude": ["node_modules"], 24 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "src/*"] 25 | } 26 | -------------------------------------------------------------------------------- /packages/server/src/product/product.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { TypeOrmModule } from '@nestjs/typeorm'; 3 | 4 | import { Product } from '@product/product.entity'; 5 | import { ProductResolver } from '@product/product.resolver'; 6 | import { ProductService } from '@product/product.service'; 7 | 8 | import { Attribute } from '@attribute/attribute.entity'; 9 | import { Category } from '@category/category.entity'; 10 | 11 | import { Helpers } from '@utils/helpers'; 12 | 13 | @Module({ 14 | imports: [ 15 | TypeOrmModule.forFeature([Product]), 16 | TypeOrmModule.forFeature([Attribute]), 17 | TypeOrmModule.forFeature([Category]), 18 | ], 19 | providers: [ProductResolver, ProductService, Helpers], 20 | exports: [ProductService], 21 | }) 22 | export class ProductModule {} 23 | -------------------------------------------------------------------------------- /packages/server/src/user/user.decorator.ts: -------------------------------------------------------------------------------- 1 | import { createParamDecorator, ExecutionContext } from '@nestjs/common'; 2 | import jwt from 'jsonwebtoken'; 3 | 4 | export const User = createParamDecorator((data: any, ctx: ExecutionContext) => { 5 | const req = ctx.switchToHttp().getRequest(); 6 | // if route is protected, there is a user set in auth.middleware 7 | if (!!req.user) { 8 | return !!data ? req.user[data] : req.user; 9 | } 10 | 11 | // in case a route is not protected, we still want to get the optional auth user from jwt 12 | const token = req.headers.authorization ? (req.headers.authorization as string).split(' ') : null; 13 | if (token && token[1]) { 14 | const decoded: any = jwt.verify(token[1], process.env.SECRET); 15 | return !!data ? decoded[data] : decoded.user; 16 | } 17 | }); 18 | -------------------------------------------------------------------------------- /packages/ssr/tests/snapshotResolver.ts: -------------------------------------------------------------------------------- 1 | const replacePath = (path: string, oldContent: string, newContent: string) => { 2 | const position = path.lastIndexOf(oldContent); 3 | return path.slice(0, position) + path.slice(position).replace(oldContent, newContent); 4 | }; 5 | 6 | module.exports = { 7 | resolveSnapshotPath: (testPath: string, snapshotExtension: string) => { 8 | return replacePath(testPath, `src/`, `tests/__snapshots__/`) + snapshotExtension; 9 | }, 10 | resolveTestPath: (snapshotFilePath: string, snapshotExtension: string) => { 11 | return replacePath(snapshotFilePath, `tests/__snapshots__/`, `src/`).slice( 12 | 0, 13 | -snapshotExtension.length, 14 | ); 15 | }, 16 | testPathForConsistencyCheck: `folder/tests.tsx`, 17 | }; 18 | 19 | export {}; -------------------------------------------------------------------------------- /packages/mobile/ios/mobile/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | } 33 | ], 34 | "info" : { 35 | "version" : 1, 36 | "author" : "xcode" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /packages/server/src/user/user.interface.ts: -------------------------------------------------------------------------------- 1 | import { registerEnumType } from '@nestjs/graphql'; 2 | 3 | export enum Roles { 4 | MEMBER = 'member', 5 | ADMIN = 'admin', 6 | SELLER = 'seller', 7 | } 8 | 9 | registerEnumType(Roles, { 10 | name: 'Roles', 11 | description: 'User possible roles', 12 | }); 13 | 14 | export enum Status { 15 | ACTIVE = 'active', 16 | DISABLED = 'disabled', 17 | } 18 | 19 | registerEnumType(Status, { 20 | name: 'Status', 21 | description: 'Account status', 22 | }); 23 | 24 | export interface UserData { 25 | id: string; 26 | name: string; 27 | username: string; 28 | email: string; 29 | bio: string; 30 | image: string; 31 | role: Roles; 32 | status: Status; 33 | password: string; 34 | token?: string; 35 | } 36 | 37 | export interface UserModel { 38 | user: UserData; 39 | } 40 | -------------------------------------------------------------------------------- /packages/server/src/category/category.entity.ts: -------------------------------------------------------------------------------- 1 | import { Field, InputType, ObjectType, ID } from '@nestjs/graphql'; 2 | import { IsString } from 'class-validator'; 3 | import { Entity, PrimaryGeneratedColumn, Column, ManyToOne } from 'typeorm'; 4 | 5 | import { Product } from '@product/product.entity'; 6 | 7 | @ObjectType() 8 | @InputType('CategoryInput') 9 | @Entity() 10 | export class Category { 11 | @PrimaryGeneratedColumn('increment') 12 | @Field(() => ID) 13 | id: string; 14 | 15 | @Column() 16 | @IsString() 17 | @Field() 18 | name: string; 19 | 20 | @Column() 21 | @IsString() 22 | @Field() 23 | description: string; 24 | 25 | @ManyToOne( 26 | () => Product, 27 | product => product.categories, 28 | ) 29 | @Field(() => [Product], { 30 | nullable: true, 31 | }) 32 | products: Product[]; 33 | } 34 | -------------------------------------------------------------------------------- /packages/design-system/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | roots: ['/src'], 3 | transform: { 4 | '^.+\\.(ts|tsx)$': 'ts-jest', 5 | }, 6 | testRegex: '(/__tests__/.*|(\\.|/)(test|spec))\\.tsx?$', 7 | moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'], 8 | testEnvironment: 'jsdom', 9 | globals: { 10 | 'ts-jest': { 11 | diagnostics: { 12 | warnOnly: true, 13 | }, 14 | }, 15 | }, 16 | testPathIgnorePatterns: [ 17 | '/__tests__/helpers', 18 | ], 19 | collectCoverageFrom: [ 20 | '/src/**/*.tsx', 21 | ], 22 | 23 | // Setup Enzyme 24 | snapshotSerializers: ['enzyme-to-json/serializer'], 25 | setupFilesAfterEnv: ['/src/utils/config/setupEnzyme.ts'], 26 | coveragePathIgnorePatterns: [ 27 | '/node_modules', 28 | ], 29 | }; 30 | -------------------------------------------------------------------------------- /packages/design-system/src/web/Button/story/OutlinedButton.story.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { storiesOf } from '@storybook/react'; 3 | import { withKnobs, text } from '@storybook/addon-knobs'; 4 | 5 | import OutlinedButton from '../OutlinedButton'; 6 | import { Grid } from '../..'; 7 | 8 | const buttonText = text('Name', 'Buy'); 9 | 10 | const stories = storiesOf('Button', module); 11 | 12 | stories 13 | .addParameters({ 14 | component: OutlinedButton, 15 | }) 16 | .addDecorator(withKnobs) 17 | .add('Outlined Button', () => ( 18 | 19 | console.log('Hey, you jest clicked me!')} 23 | /> 24 | 25 | )); 26 | -------------------------------------------------------------------------------- /packages/server/src/auth/auth.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { JwtModule } from '@nestjs/jwt'; 3 | import { TypeOrmModule } from '@nestjs/typeorm'; 4 | 5 | import { AuthService } from '@auth/auth.service'; 6 | import { AuthResolver } from '@auth/auth.resolver'; 7 | import { JwtStrategy } from '@auth/jwt.strategy'; 8 | 9 | import { UserService } from '@user/user.service'; 10 | import { User } from '@user/user.entity'; 11 | 12 | @Module({ 13 | imports: [ 14 | TypeOrmModule.forFeature([User]), 15 | JwtModule.registerAsync({ 16 | useFactory: () => ({ 17 | secret: process.env.SECRET, 18 | signOptions: { 19 | expiresIn: '60m', 20 | }, 21 | }), 22 | }), 23 | ], 24 | providers: [AuthService, AuthResolver, UserService, JwtStrategy], 25 | }) 26 | export class AuthModule {} 27 | -------------------------------------------------------------------------------- /packages/mobile/ios/mobileTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /packages/design-system/src/web/Button/DefaultButton/interface.ts: -------------------------------------------------------------------------------- 1 | import { TColorsTypes } from '../../../interfaces'; 2 | 3 | export type TButtonVariants = 'primary' | 'secondary' 4 | 5 | export type TDefaultButtonProps = { 6 | testID?: string; 7 | text: string; 8 | onClick: () => void; 9 | variant: TButtonVariants; 10 | disabled?: boolean; 11 | } 12 | 13 | export type TContainerStyleProps = { 14 | testID?: string; 15 | width: number; 16 | height: number; 17 | bg: TColorsTypes; 18 | hoverColor: TColorsTypes; 19 | border: string; 20 | } 21 | 22 | export type TGetVariants = { 23 | primary: { 24 | bg: TColorsTypes; 25 | hoverColor: TColorsTypes; 26 | }; 27 | secondary: { 28 | bg: TColorsTypes; 29 | hoverColor: TColorsTypes; 30 | }; 31 | disabled: { 32 | bg: TColorsTypes; 33 | hoverColor: TColorsTypes; 34 | }; 35 | } 36 | -------------------------------------------------------------------------------- /packages/design-system/.storybook/config.js: -------------------------------------------------------------------------------- 1 | import {configure, addParameters, addDecorator} from '@storybook/react'; 2 | import {themes} from '@storybook/theming'; 3 | import {withA11y} from '@storybook/addon-a11y'; 4 | import { withKnobs } from '@storybook/addon-knobs'; 5 | import '@storybook/addon-console'; 6 | 7 | import {DocsPage, DocsContainer} from '@storybook/addon-docs/blocks'; 8 | 9 | import themeDecorator from "./themeDecorator" 10 | 11 | const req = require.context('../src', true, /\.story\.(ts|tsx|mdx)$/); 12 | 13 | addParameters({ 14 | options: { 15 | theme: themes.dark, 16 | }, 17 | docs: { 18 | container: DocsContainer, 19 | page: DocsPage, 20 | }, 21 | }); 22 | 23 | addDecorator(withKnobs); 24 | addDecorator(withA11y); 25 | addDecorator(themeDecorator); 26 | 27 | configure(() => { 28 | req.keys().forEach(filename => req(filename)); 29 | }, module); 30 | -------------------------------------------------------------------------------- /packages/design-system/lib/Button/web/Button.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __importDefault = (this && this.__importDefault) || function (mod) { 3 | return (mod && mod.__esModule) ? mod : { "default": mod }; 4 | }; 5 | exports.__esModule = true; 6 | var react_1 = __importDefault(require("react")); 7 | var StyledButton_1 = __importDefault(require("./StyledButton")); 8 | var OutlinedButton_1 = __importDefault(require("./OutlinedButton")); 9 | exports.Button = function (_a) { 10 | var children = _a.children, outline = _a.outline, full = _a.full, secondary = _a.secondary; 11 | return (react_1["default"].createElement(react_1["default"].Fragment, null, outline ? react_1["default"].createElement(OutlinedButton_1["default"], { full: full, secondary: secondary }, children) : react_1["default"].createElement(StyledButton_1["default"], { full: full, secondary: secondary }, children))); 12 | }; 13 | -------------------------------------------------------------------------------- /packages/mobile/ios/mobile-tvOSTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /packages/design-system/lib/Grid/web/Container.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __makeTemplateObject = (this && this.__makeTemplateObject) || function (cooked, raw) { 3 | if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; } 4 | return cooked; 5 | }; 6 | var __importDefault = (this && this.__importDefault) || function (mod) { 7 | return (mod && mod.__esModule) ? mod : { "default": mod }; 8 | }; 9 | exports.__esModule = true; 10 | var styled_components_1 = __importDefault(require("styled-components")); 11 | exports.Container = styled_components_1["default"].div(templateObject_1 || (templateObject_1 = __makeTemplateObject(["\n width: 100%;\n height: 100%;\n display: flex;\n justify-content: center;\n align-items: center;\n"], ["\n width: 100%;\n height: 100%;\n display: flex;\n justify-content: center;\n align-items: center;\n"]))); 12 | var templateObject_1; 13 | -------------------------------------------------------------------------------- /packages/design-system/lib/web/Grid/Container.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __makeTemplateObject = (this && this.__makeTemplateObject) || function (cooked, raw) { 3 | if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; } 4 | return cooked; 5 | }; 6 | var __importDefault = (this && this.__importDefault) || function (mod) { 7 | return (mod && mod.__esModule) ? mod : { "default": mod }; 8 | }; 9 | exports.__esModule = true; 10 | var styled_components_1 = __importDefault(require("styled-components")); 11 | exports.Container = styled_components_1["default"].div(templateObject_1 || (templateObject_1 = __makeTemplateObject(["\n width: 100%;\n height: 100%;\n display: flex;\n justify-content: center;\n align-items: center;\n"], ["\n width: 100%;\n height: 100%;\n display: flex;\n justify-content: center;\n align-items: center;\n"]))); 12 | var templateObject_1; 13 | -------------------------------------------------------------------------------- /packages/server/src/attribute/attribute.entity.ts: -------------------------------------------------------------------------------- 1 | import { Entity, PrimaryGeneratedColumn, Column, ManyToOne } from 'typeorm'; 2 | import { Field, ObjectType, ID, InputType } from '@nestjs/graphql'; 3 | 4 | import { Product } from '@product/product.entity'; 5 | 6 | import { Types } from '@attribute/attribute.interface'; 7 | 8 | @ObjectType() 9 | @InputType('AttributeInput') 10 | @Entity() 11 | export class Attribute { 12 | @PrimaryGeneratedColumn('increment') 13 | @Field(() => ID) 14 | id: string; 15 | 16 | @Column({ 17 | type: 'enum', 18 | enum: Types, 19 | nullable: true, 20 | }) 21 | @Field(() => Types) 22 | type: Types; 23 | 24 | @Column() 25 | value: string; 26 | 27 | @Column() 28 | name: string; 29 | 30 | @ManyToOne( 31 | () => Product, 32 | product => product.attributes, 33 | ) 34 | @Field(() => Product, { 35 | nullable: true, 36 | }) 37 | product: Product; 38 | } 39 | -------------------------------------------------------------------------------- /packages/server/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "declaration": true, 5 | "removeComments": true, 6 | "emitDecoratorMetadata": true, 7 | "experimentalDecorators": true, 8 | "allowSyntheticDefaultImports": true, 9 | "target": "es2017", 10 | "sourceMap": true, 11 | "outDir": "./dist", 12 | "incremental": true, 13 | "skipLibCheck": true, 14 | "baseUrl": "./src", 15 | "paths": { 16 | "@user/*": ["./user/*"], 17 | "@auth/*": ["./auth/*"], 18 | "@shared/*": ["./shared/*"], 19 | "@graphql/*": ["./graphql/*"], 20 | "@product/*": ["./product/*"], 21 | "@store/*": ["./store/*"], 22 | "@utils/*": ["./utils/*"], 23 | "@attribute/*": ["./attribute/*"], 24 | "@category/*": ["./category/*"] 25 | } 26 | }, 27 | "exclude": ["node_modules"], 28 | "include": ["**/*.ts", "**/*.tsx", "src/*"] 29 | } 30 | -------------------------------------------------------------------------------- /packages/server/src/auth/jwt.strategy.ts: -------------------------------------------------------------------------------- 1 | import { Injectable, UnauthorizedException } from '@nestjs/common'; 2 | import { PassportStrategy } from '@nestjs/passport'; 3 | import { ExtractJwt, Strategy } from 'passport-jwt'; 4 | 5 | import { UserService } from '@user/user.service'; 6 | import { User } from '@user/user.entity'; 7 | 8 | @Injectable() 9 | export class JwtStrategy extends PassportStrategy(Strategy) { 10 | constructor(private userService: UserService) { 11 | super({ 12 | jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), 13 | ignoreExpiration: false, 14 | secretOrKey: process.env.SECRET, 15 | }); 16 | } 17 | 18 | async validate(payload: { sub: User['id']; username: User['username'] }) { 19 | const user = this.userService.findById(payload.sub); 20 | 21 | if (!user) { 22 | throw new UnauthorizedException('Unauthorized'); 23 | } 24 | 25 | return user; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /packages/design-system/lib/theme/globalStyle.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __makeTemplateObject = (this && this.__makeTemplateObject) || function (cooked, raw) { 3 | if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; } 4 | return cooked; 5 | }; 6 | exports.__esModule = true; 7 | var styled_components_1 = require("styled-components"); 8 | var GlobalStyle = styled_components_1.createGlobalStyle(templateObject_1 || (templateObject_1 = __makeTemplateObject(["\n @import url(\"https://use.typekit.net/pqn7oor.css\");\n * {\n padding: 0;\n margin: 0;\n box-sizing: border-box;\n font-family: proxima-nova, sans-serif;\n }\n"], ["\n @import url(\"https://use.typekit.net/pqn7oor.css\");\n * {\n padding: 0;\n margin: 0;\n box-sizing: border-box;\n font-family: proxima-nova, sans-serif;\n }\n"]))); 9 | exports["default"] = GlobalStyle; 10 | var templateObject_1; 11 | -------------------------------------------------------------------------------- /packages/design-system/lib/utils/theme/globalStyle.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __makeTemplateObject = (this && this.__makeTemplateObject) || function (cooked, raw) { 3 | if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; } 4 | return cooked; 5 | }; 6 | exports.__esModule = true; 7 | var styled_components_1 = require("styled-components"); 8 | var GlobalStyle = styled_components_1.createGlobalStyle(templateObject_1 || (templateObject_1 = __makeTemplateObject(["\n @import url(\"https://use.typekit.net/pqn7oor.css\");\n * {\n padding: 0;\n margin: 0;\n box-sizing: border-box;\n font-family: proxima-nova, sans-serif;\n }\n"], ["\n @import url(\"https://use.typekit.net/pqn7oor.css\");\n * {\n padding: 0;\n margin: 0;\n box-sizing: border-box;\n font-family: proxima-nova, sans-serif;\n }\n"]))); 9 | exports["default"] = GlobalStyle; 10 | var templateObject_1; 11 | -------------------------------------------------------------------------------- /packages/design-system/lib/utils/theme/index.d.ts: -------------------------------------------------------------------------------- 1 | declare const theme: Readonly<{ 2 | colors: { 3 | primary: string; 4 | secondary: string; 5 | primaryDark: string; 6 | error: string; 7 | black: string; 8 | blackNormal: string; 9 | blackDark: string; 10 | blackLight: string; 11 | white: string; 12 | gray: string; 13 | }; 14 | viewports: { 15 | smartphone: string; 16 | tablet: string; 17 | desktop: string; 18 | }; 19 | fonts: { 20 | sizes: { 21 | heading: string; 22 | subHeading: string; 23 | body: string; 24 | text: string; 25 | }; 26 | weight: { 27 | thin: number; 28 | semiBold: number; 29 | regular: number; 30 | bold: number; 31 | black: number; 32 | }; 33 | }; 34 | }>; 35 | export default theme; 36 | -------------------------------------------------------------------------------- /packages/design-system/lib/utils/theme/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | exports.__esModule = true; 3 | var colors = { 4 | primary: '#43FECB', 5 | secondary: '#743AF2', 6 | primaryDark: '#1BE0AB', 7 | error: '#FF3773', 8 | black: '#1F1F24', 9 | blackNormal: '#34353D', 10 | blackDark: '#27272D', 11 | blackLight: '#484854', 12 | white: '#FFFFFF', 13 | gray: '#737380' 14 | }; 15 | var viewports = { 16 | smartphone: '360px', 17 | tablet: '720px', 18 | desktop: '1280px' 19 | }; 20 | var fonts = { 21 | sizes: { 22 | heading: '32px', 23 | subHeading: '24px', 24 | body: '16px', 25 | text: '14px' 26 | }, 27 | weight: { 28 | thin: 100, 29 | semiBold: 600, 30 | regular: 400, 31 | bold: 700, 32 | black: 900 33 | } 34 | }; 35 | var theme = Object.freeze({ 36 | colors: colors, 37 | viewports: viewports, 38 | fonts: fonts 39 | }); 40 | exports["default"] = theme; 41 | -------------------------------------------------------------------------------- /packages/design-system/src/web/Grid/interface.ts: -------------------------------------------------------------------------------- 1 | import { 2 | TColorsTypes, 3 | TBorderRadiusTypes, 4 | TCommonSpacingProps, 5 | TAlignContent, 6 | TAlignItems, 7 | TAligns, 8 | TJustifyContent, 9 | TSizes, 10 | TPosition, 11 | TFlexDirection, 12 | TFlexWrap, 13 | } from '../../interfaces'; 14 | 15 | 16 | export type TGridProps = 17 | TCommonSpacingProps & { 18 | bg?: TColorsTypes; 19 | alignContent?: TAlignContent; 20 | alignItems?: TAlignItems; 21 | alignSelf?: TAligns; 22 | borderRadius?: TBorderRadiusTypes; 23 | flex?: number; 24 | flexDirection?: TFlexDirection; 25 | flexWrap?: TFlexWrap; 26 | height?: TSizes; 27 | justifyContent?: TJustifyContent; 28 | opacity?: number; 29 | position?: TPosition; 30 | bottom?: string; 31 | top?: string; 32 | left?: string; 33 | right?: string; 34 | width?: TSizes; 35 | zIndex?: number; 36 | skeleton?: boolean; 37 | skeletonWidth?: number; 38 | skeletonHeight?: number; 39 | display: string; 40 | }; 41 | -------------------------------------------------------------------------------- /packages/design-system/src/interfaces/units.ts: -------------------------------------------------------------------------------- 1 | export type TSpacingSizes = { 2 | spacing1: number; 3 | spacing2: number; 4 | spacing4: number; 5 | spacing8: number; 6 | spacing10: number; 7 | spacing12: number; 8 | spacing16: number; 9 | spacing18: number; 10 | spacing20: number; 11 | spacing24: number; 12 | spacing32: number; 13 | } 14 | 15 | export type TBorderRadius = { 16 | xsmall: number; 17 | small: number; 18 | medium: number; 19 | large: number; 20 | full: number; 21 | } 22 | 23 | export type TCommonSpacingProps = { 24 | padding?: TSpacingSizes; 25 | margin?: TSpacingSizes; 26 | p?: TSpacingSizes; 27 | pt?: TSpacingSizes; 28 | pb?: TSpacingSizes; 29 | pr?: TSpacingSizes; 30 | pl?: TSpacingSizes; 31 | m?: TSpacingSizes; 32 | mt?: TSpacingSizes; 33 | mr?: TSpacingSizes; 34 | mb?: TSpacingSizes; 35 | ml?: TSpacingSizes; 36 | }; 37 | 38 | export type TSpacingSizesTypes = keyof TSpacingSizes; 39 | export type TBorderRadiusTypes = keyof TBorderRadius; 40 | -------------------------------------------------------------------------------- /packages/server/src/user/dto/create-user.dto.ts: -------------------------------------------------------------------------------- 1 | import { InputType, Field } from '@nestjs/graphql'; 2 | import { IsNotEmpty, IsString, IsEmail, MinLength } from 'class-validator'; 3 | 4 | @InputType() 5 | export class CreateUserDto { 6 | @Field() 7 | @IsString() 8 | @IsNotEmpty({ message: 'Field required ' }) 9 | readonly username: string; 10 | 11 | @Field() 12 | @IsString() 13 | @IsNotEmpty({ message: 'Field required ' }) 14 | readonly name: string; 15 | 16 | @Field() 17 | @IsEmail() 18 | @IsNotEmpty({ message: 'Field required ' }) 19 | readonly email: string; 20 | 21 | @Field() 22 | @IsString() 23 | @IsNotEmpty({ message: 'Field required ' }) 24 | @MinLength(6, { message: 'The password need have more than 6 characters' }) 25 | readonly password: string; 26 | 27 | @Field() 28 | @IsString() 29 | @IsNotEmpty({ message: 'Field required ' }) 30 | @MinLength(6, { message: 'The password need have more than 6 characters' }) 31 | readonly confirmPassword: string; 32 | } 33 | -------------------------------------------------------------------------------- /packages/server/src/utils/helpers.ts: -------------------------------------------------------------------------------- 1 | type GenerateSkuProps = { 2 | name: string; 3 | attributeName: string; 4 | brand: string; 5 | }; 6 | 7 | type GenericProvider = { 8 | id: string; 9 | }; 10 | 11 | type GenericExists = { 12 | data: GenericProvider[]; 13 | dataIds: string[]; 14 | }; 15 | 16 | export class Helpers { 17 | generateSku({ name, attributeName, brand }: GenerateSkuProps) { 18 | const nameSplitted = name.split(' '); 19 | 20 | const nameCode = 21 | nameSplitted.length > 1 22 | ? `${nameSplitted[0].charAt(0)}${nameSplitted[1].charAt(0)}` 23 | : nameSplitted[0].substr(0, 2); 24 | 25 | const attributeCode = attributeName.substr(0, 2); 26 | 27 | const brandCode = brand.substr(0, 3); 28 | 29 | const sku = `${nameCode}-${attributeCode}-${brandCode}`; 30 | 31 | return sku.toUpperCase(); 32 | } 33 | 34 | dataExists({ data, dataIds }: GenericExists): boolean { 35 | return data.some(d => dataIds.every(id => id === d.id)); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /packages/server/.eslintrc.js: -------------------------------------------------------------------------------- 1 | const tsconfig = require(`./tsconfig`); 2 | 3 | module.exports = { 4 | parser: '@typescript-eslint/parser', 5 | parserOptions: { 6 | sourceType: 'module', 7 | tsconfigRootDir: __dirname, 8 | project: ["./tsconfig.json"], 9 | }, 10 | plugins: ['@typescript-eslint/eslint-plugin'], 11 | extends: [ 12 | 'plugin:@typescript-eslint/recommended', 13 | `plugin:@typescript-eslint/eslint-recommended`, 14 | 'plugin:prettier/recommended', 15 | ], 16 | root: true, 17 | env: { 18 | node: true, 19 | jest: true, 20 | }, 21 | ignorePatterns: ['.eslintrc.js'], 22 | rules: { 23 | '@typescript-eslint/interface-name-prefix': 'off', 24 | '@typescript-eslint/explicit-function-return-type': 'off', 25 | '@typescript-eslint/explicit-module-boundary-types': 'off', 26 | '@typescript-eslint/no-explicit-any': 'off', 27 | }, 28 | settings: { 29 | 'import/resolver': { 30 | typescript: { 31 | project: `.`, 32 | }, 33 | }, 34 | }, 35 | }; 36 | -------------------------------------------------------------------------------- /packages/design-system/lib/Grid/web/Flex.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __makeTemplateObject = (this && this.__makeTemplateObject) || function (cooked, raw) { 3 | if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; } 4 | return cooked; 5 | }; 6 | var __importDefault = (this && this.__importDefault) || function (mod) { 7 | return (mod && mod.__esModule) ? mod : { "default": mod }; 8 | }; 9 | exports.__esModule = true; 10 | var styled_components_1 = __importDefault(require("styled-components")); 11 | exports.Flex = styled_components_1["default"].div(templateObject_1 || (templateObject_1 = __makeTemplateObject(["\n display: 'flex';\n direction: ", ";\n justify-content: ", ";\n align-items: ", ";\n"], ["\n display: 'flex';\n direction: ", ";\n justify-content: ", ";\n align-items: ", ";\n"])), function (props) { return (props.direction ? props.direction : 'row'); }, function (props) { return props.justify; }, function (props) { return props.align; }); 12 | var templateObject_1; 13 | -------------------------------------------------------------------------------- /packages/design-system/lib/web/Grid/Flex.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __makeTemplateObject = (this && this.__makeTemplateObject) || function (cooked, raw) { 3 | if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; } 4 | return cooked; 5 | }; 6 | var __importDefault = (this && this.__importDefault) || function (mod) { 7 | return (mod && mod.__esModule) ? mod : { "default": mod }; 8 | }; 9 | exports.__esModule = true; 10 | var styled_components_1 = __importDefault(require("styled-components")); 11 | exports.Flex = styled_components_1["default"].div(templateObject_1 || (templateObject_1 = __makeTemplateObject(["\n display: 'flex';\n direction: ", ";\n justify-content: ", ";\n align-items: ", ";\n"], ["\n display: 'flex';\n direction: ", ";\n justify-content: ", ";\n align-items: ", ";\n"])), function (props) { return (props.direction ? props.direction : 'row'); }, function (props) { return props.justify; }, function (props) { return props.align; }); 12 | var templateObject_1; 13 | -------------------------------------------------------------------------------- /packages/web/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ['airbnb', 'plugin:@typescript-eslint/recommended'], 3 | parser: '@typescript-eslint/parser', 4 | plugins: ['@typescript-eslint', 'prettier'], 5 | settings: { 6 | 'import/parsers': { 7 | '@typescript-eslint/parser': ['.ts', '.tsx'], 8 | }, 9 | 'import/resolver': { 10 | typescript: {}, 11 | }, 12 | }, 13 | rules: { 14 | 'react/jsx-filename-extension': [2, { extensions: ['.js', '.jsx', '.ts', '.tsx'] }], 15 | 'import/no-extraneous-dependencies': [2, { devDependencies: ['**/test.tsx', '**/test.ts'] }], 16 | '@typescript-eslint/indent': [2, 2], 17 | '@typescript-eslint/explicit-function-return-type': "off", 18 | '@typescript-eslint/interface-name-prefix': ["error", { "prefixWithI": "always" }], 19 | "@typescript-eslint/no-unused-vars": [2, { "args": "none" }], 20 | "import/extensions": ["error", "ignorePackages", { 21 | "js": "never", 22 | "jsx": "never", 23 | "ts": "never", 24 | "tsx": "never", 25 | }] 26 | }, 27 | }; 28 | -------------------------------------------------------------------------------- /packages/design-system/lib/web/Button/Button.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __importDefault = (this && this.__importDefault) || function (mod) { 3 | return (mod && mod.__esModule) ? mod : { "default": mod }; 4 | }; 5 | exports.__esModule = true; 6 | var react_1 = __importDefault(require("react")); 7 | var StyledButton_1 = __importDefault(require("./StyledButton")); 8 | var OutlinedButton_1 = __importDefault(require("./OutlinedButton")); 9 | var Button = function (_a) { 10 | var children = _a.children, _b = _a.outline, outline = _b === void 0 ? false : _b, _c = _a.full, full = _c === void 0 ? false : _c, _d = _a.secondary, secondary = _d === void 0 ? false : _d, onClick = _a.onClick; 11 | return (react_1["default"].createElement(react_1["default"].Fragment, null, outline ? (react_1["default"].createElement(OutlinedButton_1["default"], { full: full, onClick: onClick, secondary: secondary }, children)) : (react_1["default"].createElement(StyledButton_1["default"], { full: full, onClick: onClick, secondary: secondary }, children)))); 12 | }; 13 | exports["default"] = Button; 14 | -------------------------------------------------------------------------------- /packages/server/src/category/category.resolver.ts: -------------------------------------------------------------------------------- 1 | import { UseGuards } from '@nestjs/common'; 2 | import { Resolver, Args, Mutation, Query } from '@nestjs/graphql'; 3 | 4 | import { CategoryService } from '@category/category.service'; 5 | import { Category } from '@category/category.entity'; 6 | import { CreateCategoryDto } from '@category/dto/create-category.dto'; 7 | 8 | import { GqlAuthGuard } from '@auth/auth.guard'; 9 | 10 | @Resolver() 11 | export class CategoryResolver { 12 | constructor(private categoryService: CategoryService) {} 13 | 14 | @UseGuards(GqlAuthGuard) 15 | @Mutation(() => Category) 16 | async createCategory(@Args('data') data: CreateCategoryDto): Promise { 17 | const category = await this.categoryService.create(data); 18 | 19 | return category; 20 | } 21 | 22 | @UseGuards(GqlAuthGuard) 23 | @Query(() => [Category], { 24 | nullable: true, 25 | }) 26 | async getAllCategories(): Promise { 27 | const categories = await this.categoryService.findAll(); 28 | 29 | return categories; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /packages/sdk/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@react-shop/sdk", 3 | "version": "0.0.1", 4 | "private": true, 5 | "description": "a Sdk provider for react-ecommerce", 6 | "main": "./lib/index.js", 7 | "module": "./lib-esm/index.js", 8 | "types": "./lib/index.d.ts", 9 | "author": "Vinicius Arruda", 10 | "scripts": { 11 | "libbuild": "tsc && tsc --build tsconfig.esm.json", 12 | "start": "tsc && tsc --build tsconfig.esm.json -w", 13 | "test": "jest --color" 14 | }, 15 | "dependencies": { 16 | "axios": "^0.21.1" 17 | }, 18 | "devDependencies": { 19 | "@babel/core": "^7.7.7", 20 | "@babel/plugin-proposal-export-default-from": "^7.7.4", 21 | "@babel/preset-env": "^7.7.7", 22 | "@babel/preset-typescript": "^7.7.7", 23 | "@types/jest": "^24.0.25", 24 | "@types/yup": "^0.26.27", 25 | "jest": "^24.9.0", 26 | "yup": "^0.28.0" 27 | }, 28 | "jest": { 29 | "transformIgnorePatterns": [ 30 | "/node_modules" 31 | ], 32 | "coveragePathIgnorePatterns": [ 33 | "/node_modules" 34 | ] 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /packages/server/src/attribute/attribute.resolver.ts: -------------------------------------------------------------------------------- 1 | import { UseGuards } from '@nestjs/common'; 2 | import { Resolver, Args, Mutation, Query } from '@nestjs/graphql'; 3 | 4 | import { AttributeService } from '@attribute/attribute.service'; 5 | import { Attribute } from '@attribute/attribute.entity'; 6 | import { CreateAttributeDto } from '@attribute/dto/create-attribute.dto'; 7 | 8 | import { GqlAuthGuard } from '@auth/auth.guard'; 9 | 10 | @Resolver() 11 | export class AttributeResolver { 12 | constructor(private attributeService: AttributeService) {} 13 | 14 | @UseGuards(GqlAuthGuard) 15 | @Mutation(() => Attribute) 16 | async createAttribute(@Args('data') data: CreateAttributeDto): Promise { 17 | const attribute = await this.attributeService.create(data); 18 | 19 | return attribute; 20 | } 21 | 22 | @UseGuards(GqlAuthGuard) 23 | @Query(() => [Attribute], { 24 | nullable: true, 25 | }) 26 | async getAllAttributes(): Promise { 27 | const attributes = await this.attributeService.getAll(); 28 | 29 | return attributes; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /packages/design-system/__tests__/helpers/index.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | mount, shallow, ShallowWrapper, ReactWrapper, 3 | } from 'enzyme'; 4 | 5 | import { ThemeProvider, DefaultTheme } from 'styled-components'; 6 | 7 | import React from 'react'; 8 | 9 | import { theme as designSystemTheme } from '../../src/theme'; 10 | 11 | export const mountWithTheme = ( 12 | tree: React.ReactElement, 13 | theme: DefaultTheme = designSystemTheme, 14 | ): ReactWrapper => { 15 | const WrappingThemeProvider: React.FC<{ 16 | children: React.ReactChild; 17 | }> = ({ children }) => {children}; 18 | 19 | return mount(tree, { wrappingComponent: WrappingThemeProvider }); 20 | }; 21 | 22 | export const shallowWithTheme = ( 23 | tree: React.ReactElement, 24 | theme: DefaultTheme = designSystemTheme, 25 | ): ShallowWrapper => { 26 | const WrappingThemeProvider: React.FC<{ 27 | children: React.ReactChild; 28 | }> = ({ children }) => {children}; 29 | 30 | return shallow(tree, { wrappingComponent: WrappingThemeProvider }); 31 | }; 32 | -------------------------------------------------------------------------------- /packages/ssr/jest.config.js: -------------------------------------------------------------------------------- 1 | const { pathsToModuleNameMapper } = require(`ts-jest/utils`); 2 | 3 | const { compilerOptions } = require(`./tsconfig`); 4 | 5 | module.exports = { 6 | preset: `ts-jest`, 7 | testEnvironment: `jsdom`, 8 | testPathIgnorePatterns: [`/node_modules/`, `/.next/`], 9 | snapshotResolver: `/tests/snapshotResolver.ts`, 10 | testMatch: [`**/__tests__/**/*.[jt]s?(x)`, `**/?(*.)+(specs|tests).[tj]s?(x)`], 11 | collectCoverage: true, 12 | collectCoverageFrom: [`src/**/*.ts(x)?`], 13 | coverageDirectory: `/tests/coverage/`, 14 | setupFilesAfterEnv: [`/tests/setupTests.ts`], 15 | modulePaths: [`/src/`], 16 | moduleNameMapper: pathsToModuleNameMapper(compilerOptions.paths, { 17 | prefix: `/src/`, 18 | }), 19 | transform: { 20 | '\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': `/tests/mocks/fileTransformer.js`, 21 | }, 22 | globals: { 23 | NODE_ENV: `test`, 24 | 'ts-jest': { 25 | tsconfig: `tsconfig.jest.json`, 26 | diagnostics: true, 27 | }, 28 | }, 29 | }; -------------------------------------------------------------------------------- /packages/server/src/product/dto/create-product.dto.ts: -------------------------------------------------------------------------------- 1 | import { InputType, Field, ID } from '@nestjs/graphql'; 2 | import { IsNotEmpty, IsString, IsNumber, IsPositive } from 'class-validator'; 3 | 4 | @InputType() 5 | export class CreateProductDto { 6 | @Field() 7 | @IsString() 8 | @IsNotEmpty({ message: 'Field required ' }) 9 | readonly title: string; 10 | 11 | @Field() 12 | @IsString() 13 | @IsNotEmpty({ message: 'Field required ' }) 14 | readonly description: string; 15 | 16 | @Field() 17 | @IsString() 18 | @IsNotEmpty({ message: 'Field required ' }) 19 | readonly brand: string; 20 | 21 | @Field() 22 | @IsPositive() 23 | @IsNumber() 24 | @IsNotEmpty({ message: 'Field required ' }) 25 | readonly price: number; 26 | 27 | @Field() 28 | @IsPositive() 29 | @IsNumber() 30 | @IsNotEmpty({ message: 'Field required ' }) 31 | readonly quantity: number; 32 | 33 | @Field() 34 | @IsString() 35 | @IsNotEmpty({ message: 'Field required ' }) 36 | readonly dimension: string; 37 | 38 | @IsNotEmpty({ message: 'Field required ' }) 39 | @Field(() => [ID]) 40 | readonly attributesId: string[]; 41 | } 42 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Vinícius Arruda 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /packages/mobile/.gitignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | # 3 | .DS_Store 4 | 5 | # Xcode 6 | # 7 | build/ 8 | *.pbxuser 9 | !default.pbxuser 10 | *.mode1v3 11 | !default.mode1v3 12 | *.mode2v3 13 | !default.mode2v3 14 | *.perspectivev3 15 | !default.perspectivev3 16 | xcuserdata 17 | *.xccheckout 18 | *.moved-aside 19 | DerivedData 20 | *.hmap 21 | *.ipa 22 | *.xcuserstate 23 | 24 | # Android/IntelliJ 25 | # 26 | build/ 27 | .idea 28 | .gradle 29 | local.properties 30 | *.iml 31 | 32 | # Visual Studio Code 33 | # 34 | .vscode/ 35 | 36 | # node.js 37 | # 38 | node_modules/ 39 | npm-debug.log 40 | yarn-error.log 41 | 42 | # BUCK 43 | buck-out/ 44 | \.buckd/ 45 | *.keystore 46 | !debug.keystore 47 | 48 | # fastlane 49 | # 50 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 51 | # screenshots whenever they are needed. 52 | # For more information about the recommended setup visit: 53 | # https://docs.fastlane.tools/best-practices/source-control/ 54 | 55 | */fastlane/report.xml 56 | */fastlane/Preview.html 57 | */fastlane/screenshots 58 | 59 | # Bundle artifact 60 | *.jsbundle 61 | 62 | # CocoaPods 63 | /ios/Pods/ 64 | -------------------------------------------------------------------------------- /packages/mobile/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 13 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /packages/design-system/.storybook/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | module.exports = { 3 | module: { 4 | rules: [ 5 | { 6 | test: /\.scss$/, 7 | loaders: ['style-loader', 'css-loader', 'sass-loader'], 8 | include: path.resolve(__dirname, '../'), 9 | }, 10 | { 11 | test: /\.css/, 12 | loaders: ['style-loader', 'css-loader'], 13 | include: path.resolve(__dirname, '../'), 14 | }, 15 | { 16 | enforce: 'pre', 17 | test: /\.js$/, 18 | loader: 'source-map-loader', 19 | exclude: [/node_modules\//], 20 | }, 21 | { 22 | test: /\.tsx?$/, 23 | include: path.resolve(__dirname, '../src'), 24 | loader: 'awesome-typescript-loader', 25 | }, 26 | { 27 | test: /\.tsx?$/, 28 | include: path.resolve(__dirname, '../src'), 29 | loader: 'react-docgen-typescript-loader', 30 | }, 31 | { 32 | test: /\.(woff|woff2|eot|ttf|otf|svg)$/, 33 | loader: 'file-loader', 34 | }, 35 | ], 36 | }, 37 | resolve: { 38 | extensions: ['.tsx', '.ts', '.js'], 39 | }, 40 | }; 41 | -------------------------------------------------------------------------------- /packages/mobile/android/build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | ext { 5 | buildToolsVersion = "29.0.2" 6 | minSdkVersion = 16 7 | compileSdkVersion = 29 8 | targetSdkVersion = 29 9 | } 10 | repositories { 11 | google() 12 | jcenter() 13 | } 14 | dependencies { 15 | classpath("com.android.tools.build:gradle:3.5.3") 16 | // NOTE: Do not place your application dependencies here; they belong 17 | // in the individual module build.gradle files 18 | } 19 | } 20 | 21 | allprojects { 22 | repositories { 23 | mavenLocal() 24 | maven { 25 | // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm 26 | url("$rootDir/../../../node_modules/react-native/android") 27 | } 28 | maven { 29 | // Android JSC is installed from npm 30 | url("$rootDir/../../../node_modules/jsc-android/dist") 31 | } 32 | 33 | google() 34 | jcenter() 35 | maven { url 'https://www.jitpack.io' } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /packages/design-system/src/utils/config/setupEnzyme.ts: -------------------------------------------------------------------------------- 1 | import { configure } from 'enzyme'; 2 | import EnzymeAdapter from 'enzyme-adapter-react-16'; 3 | import 'jest-enzyme'; 4 | 5 | // jest.useFakeTimers(); 6 | 7 | // /** 8 | // * Set up DOM in node.js environment for Enzyme to mount to 9 | // */ 10 | // // eslint-disable-next-line @typescript-eslint/no-var-requires 11 | // const { JSDOM } = require('jsdom'); 12 | 13 | // const jsdom = new JSDOM(''); 14 | // const { window } = jsdom; 15 | 16 | // function copyProps(src, target) { 17 | // Object.defineProperties(target, { 18 | // ...Object.getOwnPropertyDescriptors(src), 19 | // ...Object.getOwnPropertyDescriptors(target), 20 | // }); 21 | // } 22 | 23 | // jest.useFakeTimers(); 24 | 25 | // global.window = window; 26 | // global.document = window.document; 27 | // global.navigator = { 28 | // userAgent: 'node.js', 29 | // }; 30 | 31 | // copyProps(window, global); 32 | 33 | configure({ adapter: new EnzymeAdapter() }); 34 | 35 | // const originalConsoleError = console.error; 36 | // console.error = (message, ...args) => !message.startsWith('Warning: ') && originalConsoleError(message, ...args); 37 | -------------------------------------------------------------------------------- /packages/design-system/src/web/Button/DefaultButton/index.tsx: -------------------------------------------------------------------------------- 1 | import React, { FunctionComponent } from 'react'; 2 | 3 | import Container from './styles'; 4 | 5 | import { TDefaultButtonProps, TGetVariants } from './interface'; 6 | 7 | const Button: FunctionComponent = ({ 8 | text, onClick, variant, disabled, 9 | }) => { 10 | const getButtonVariants = () => { 11 | const getVariants: TGetVariants = { 12 | primary: { 13 | bg: 'primary', 14 | hoverColor: 'primaryDark', 15 | }, 16 | secondary: { 17 | bg: 'secondary', 18 | hoverColor: 'secondaryDark', 19 | }, 20 | disabled: { 21 | bg: 'gray', 22 | hoverColor: 'gray', 23 | }, 24 | }; 25 | 26 | return disabled ? getVariants.disabled : (getVariants[variant] || getVariants.primary); 27 | }; 28 | 29 | return ( 30 | 39 | {text} 40 | 41 | ); 42 | }; 43 | 44 | export default Button; 45 | -------------------------------------------------------------------------------- /packages/mobile/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mobile", 3 | "version": "0.0.1", 4 | "private": true, 5 | "scripts": { 6 | "android": "react-native run-android", 7 | "ios": "react-native run-ios", 8 | "start": "react-native start", 9 | "test": "jest --color", 10 | "lint": "eslint . --ext .js,.jsx,.ts,.tsx" 11 | }, 12 | "dependencies": { 13 | "@react-shop/sdk": "*", 14 | "react": "16.13.1", 15 | "react-native": "0.64.2" 16 | }, 17 | "devDependencies": { 18 | "@babel/core": "^7.8.4", 19 | "@babel/runtime": "^7.8.4", 20 | "@react-native-community/eslint-config": "^1.1.0", 21 | "@types/jest": "^25.2.3", 22 | "@types/react-native": "^0.63.2", 23 | "@types/react-test-renderer": "^16.9.2", 24 | "babel-jest": "^25.1.0", 25 | "eslint": "^6.5.1", 26 | "jest": "^25.1.0", 27 | "metro-react-native-babel-preset": "^0.59.0", 28 | "prettier": "^2.0.4", 29 | "react-test-renderer": "16.13.1", 30 | "typescript": "^3.8.3" 31 | }, 32 | "jest": { 33 | "preset": "react-native", 34 | "moduleFileExtensions": [ 35 | "ts", 36 | "tsx", 37 | "js", 38 | "jsx", 39 | "json", 40 | "node" 41 | ] 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /packages/design-system/lib/Button/web/StyledButton.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __makeTemplateObject = (this && this.__makeTemplateObject) || function (cooked, raw) { 3 | if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; } 4 | return cooked; 5 | }; 6 | var __importDefault = (this && this.__importDefault) || function (mod) { 7 | return (mod && mod.__esModule) ? mod : { "default": mod }; 8 | }; 9 | exports.__esModule = true; 10 | var styled_components_1 = __importDefault(require("styled-components")); 11 | var theme_1 = __importDefault(require("../../theme")); 12 | var DefaultButton_1 = __importDefault(require("./DefaultButton")); 13 | var StyledButton = styled_components_1["default"](DefaultButton_1["default"])(templateObject_1 || (templateObject_1 = __makeTemplateObject(["\n background-color: ", ";\n color: ", ";\n"], ["\n background-color: ", ";\n color: ", ";\n"])), function (props) { return (props.secondary ? theme_1["default"].colors.secondary : theme_1["default"].colors.primary); }, function (props) { return (props.secondary ? theme_1["default"].colors.white : theme_1["default"].colors.black); }); 14 | exports["default"] = StyledButton; 15 | var templateObject_1; 16 | -------------------------------------------------------------------------------- /packages/design-system/lib/web/Button/StyledButton.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __makeTemplateObject = (this && this.__makeTemplateObject) || function (cooked, raw) { 3 | if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; } 4 | return cooked; 5 | }; 6 | var __importDefault = (this && this.__importDefault) || function (mod) { 7 | return (mod && mod.__esModule) ? mod : { "default": mod }; 8 | }; 9 | exports.__esModule = true; 10 | var styled_components_1 = __importDefault(require("styled-components")); 11 | var theme_1 = __importDefault(require("../../theme")); 12 | var DefaultButton_1 = __importDefault(require("./DefaultButton")); 13 | var StyledButton = styled_components_1["default"](DefaultButton_1["default"])(templateObject_1 || (templateObject_1 = __makeTemplateObject(["\n background-color: ", ";\n color: ", ";\n"], ["\n background-color: ", ";\n color: ", ";\n"])), function (props) { return (props.secondary ? theme_1["default"].colors.secondary : theme_1["default"].colors.primary); }, function (props) { return (props.secondary ? theme_1["default"].colors.white : theme_1["default"].colors.black); }); 14 | exports["default"] = StyledButton; 15 | var templateObject_1; 16 | -------------------------------------------------------------------------------- /packages/sdk/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ['airbnb', 'plugin:@typescript-eslint/recommended'], 3 | parser: '@typescript-eslint/parser', 4 | plugins: ['@typescript-eslint', 'prettier'], 5 | settings: { 6 | 'import/parsers': { 7 | '@typescript-eslint/parser': ['.ts', '.tsx'], 8 | }, 9 | 'import/resolver': { 10 | typescript: {}, 11 | }, 12 | }, 13 | rules: { 14 | 'react/jsx-filename-extension': [2, { extensions: ['.js', '.jsx', '.ts', '.tsx'] }], 15 | 'import/no-extraneous-dependencies': [2, { devDependencies: ['**/test.tsx', '**/test.ts'] }], 16 | 'import/prefer-default-export': "off", 17 | '@typescript-eslint/indent': [2, 2], 18 | '@typescript-eslint/explicit-function-return-type': "off", 19 | '@typescript-eslint/interface-name-prefix': ["error", { "prefixWithI": "always" }], 20 | "@typescript-eslint/no-unused-vars": [2, { "args": "none" }], 21 | "import/extensions": ["error", "ignorePackages", { 22 | "js": "never", 23 | "jsx": "never", 24 | "ts": "never", 25 | "tsx": "never", 26 | }], 27 | "import/no-extraneous-dependencies": "off", 28 | 'react/prop-types': 0, 29 | "max-len": ["error", { "code": 120 }] 30 | }, 31 | }; 32 | -------------------------------------------------------------------------------- /packages/design-system/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ['airbnb', 'plugin:@typescript-eslint/recommended'], 3 | parser: '@typescript-eslint/parser', 4 | plugins: ['@typescript-eslint', 'prettier'], 5 | settings: { 6 | 'import/parsers': { 7 | '@typescript-eslint/parser': ['.ts', '.tsx'], 8 | }, 9 | 'import/resolver': { 10 | typescript: {}, 11 | }, 12 | }, 13 | env: { 14 | "jest": true 15 | }, 16 | rules: { 17 | 'react/jsx-filename-extension': [2, { extensions: ['.js', '.jsx', '.ts', '.tsx'] }], 18 | 'import/no-extraneous-dependencies': [2, { devDependencies: ['**/test.tsx', '**/test.ts'] }], 19 | '@typescript-eslint/indent': [2, 2], 20 | '@typescript-eslint/explicit-function-return-type': "off", 21 | '@typescript-eslint/interface-name-prefix': ["error", { "prefixWithI": "always" }], 22 | "@typescript-eslint/no-unused-vars": [2, { "args": "none" }], 23 | "import/extensions": ["error", "ignorePackages", { 24 | "js": "never", 25 | "jsx": "never", 26 | "ts": "never", 27 | "tsx": "never", 28 | }], 29 | "import/no-extraneous-dependencies": "off", 30 | 'react/prop-types': 0, 31 | "max-len": ["error", { "code": 120 }], 32 | "react/jsx-props-no-spreading": "off" 33 | }, 34 | 35 | }; 36 | -------------------------------------------------------------------------------- /packages/sdk/src/utils/httpClient.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-undef */ 2 | /* eslint-disable no-param-reassign */ 3 | import axios from 'axios'; 4 | 5 | import { api } from './routes.constants'; 6 | // Create a basic Axios instance to all requests (this object can be customized before making the call) 7 | export const http = axios.create({ 8 | baseURL: api.BASE_URL, 9 | headers: { 10 | 'Content-Type': 'application/json', 11 | }, 12 | }); 13 | 14 | export interface IAccessUser { 15 | token: string; 16 | } 17 | 18 | // Insert token on all requests when there is a token in the device storage 19 | http.interceptors.request.use(async (config) => { 20 | const accessUser: IAccessUser = JSON.parse(localStorage.getItem('access_token')); 21 | 22 | if (accessUser) { 23 | config.headers.common.Authorization = `Bearer ${accessUser.token}`; 24 | } 25 | 26 | return config; 27 | }); 28 | 29 | http.interceptors.response.use( 30 | (response) => response, 31 | (error) => { 32 | if (error.response && error.response.status === 401) { 33 | localStorage.clear(); 34 | } 35 | 36 | console.log('REQUEST error', error); 37 | 38 | if (!error.response) { 39 | error.response = { data: { genericError: error } }; 40 | } 41 | 42 | return Promise.reject(error); 43 | }, 44 | ); 45 | -------------------------------------------------------------------------------- /packages/server/src/auth/auth.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable, UnauthorizedException } from '@nestjs/common'; 2 | import { JwtService } from '@nestjs/jwt'; 3 | import { compareSync } from 'bcrypt'; 4 | 5 | import { AuthDto } from '@auth/dto/auth.input'; 6 | import { UserService } from '@user/user.service'; 7 | import { AuthType } from '@auth/dto/auth.interface'; 8 | import { User } from '@user/user.entity'; 9 | 10 | @Injectable() 11 | export class AuthService { 12 | constructor(private userService: UserService, private jwtService: JwtService) {} 13 | 14 | async validateUser(data: AuthDto): Promise { 15 | const user = await this.userService.findByEmail(data.email); 16 | 17 | if (!user) { 18 | throw new UnauthorizedException('User not found!'); 19 | } 20 | 21 | const validPassword = compareSync(data.password, user.password); 22 | 23 | if (!validPassword) { 24 | throw new UnauthorizedException('Incorrect Password'); 25 | } 26 | 27 | const token = await this.generateJWT(user); 28 | 29 | return { 30 | user, 31 | token, 32 | }; 33 | } 34 | 35 | public async generateJWT(user: User): Promise { 36 | const payload = { username: user.username, sub: user.id }; 37 | 38 | return this.jwtService.signAsync(payload); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /packages/server/src/user/user.resolver.ts: -------------------------------------------------------------------------------- 1 | import { UseGuards, UsePipes } from '@nestjs/common'; 2 | 3 | import { Resolver, Mutation, Query, Args } from '@nestjs/graphql'; 4 | 5 | import { UserService } from '@user/user.service'; 6 | import { User } from '@user/user.entity'; 7 | import { CreateUserDto } from '@user/dto'; 8 | import { UserData } from '@user/user.interface'; 9 | 10 | import { ValidationPipe } from '@shared/pipes/validation.pipe'; 11 | import { GqlAuthGuard } from '@auth/auth.guard'; 12 | 13 | @Resolver('User') 14 | export class UserResolver { 15 | constructor(private userService: UserService) {} 16 | 17 | @UseGuards(GqlAuthGuard) 18 | @Query(() => User) 19 | async findById(@Args('id') id: string): Promise { 20 | const user = this.userService.findById(id); 21 | 22 | return user; 23 | } 24 | 25 | @UseGuards(GqlAuthGuard) 26 | @Query(() => User) 27 | async findByEmail(@Args('email') email: string): Promise { 28 | const user = this.userService.findByEmail(email); 29 | 30 | return user; 31 | } 32 | 33 | @UsePipes(new ValidationPipe()) 34 | @Mutation(() => User) 35 | async createUser(@Args('data') data: CreateUserDto): Promise { 36 | const user = await this.userService.create(data); 37 | 38 | return user; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-ecommerce", 3 | "private": true, 4 | "version": "1.0.0", 5 | "description": "React E-commerce monorepo", 6 | "repository": "https://github.com/react-shop/react-ecommerce", 7 | "author": "Vinicius Arruda", 8 | "engines": { 9 | "node": "14.x", 10 | "npm": "You must use yarn in this project!", 11 | "yarn": "^1.22.x" 12 | }, 13 | "scripts": { 14 | "story": "lerna run story --stream", 15 | "start": "lerna run start --parallel --scope '{web,@react-shop/design-system,@react-shop/sdk}'", 16 | "test": "lerna run test --stream ", 17 | "server:dev": "lerna run dev --scope @react-shop/server" 18 | }, 19 | "workspaces": { 20 | "packages": [ 21 | "packages/*" 22 | ], 23 | "nohoist": [ 24 | "@commitlint/*" 25 | ] 26 | }, 27 | "npmClient": "yarn", 28 | "useWorkspaces": true, 29 | "devDependencies": { 30 | "@commitlint/cli": "^13.1.0", 31 | "@commitlint/config-conventional": "^13.1.0", 32 | "@types/react": "17.0.14", 33 | "@types/react-dom": "17.0.9", 34 | "@types/styled-components": "^5.1.12", 35 | "husky": "^7.0.2", 36 | "lerna": "3.19.0", 37 | "typescript": "4.3.5" 38 | }, 39 | "husky": { 40 | "hooks": { 41 | "commit-msg": "commitlint -E HUSKY_GIT_PARAMS" 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /packages/design-system/lib-esm/theme/index.js: -------------------------------------------------------------------------------- 1 | import colors from './colors'; 2 | import units from './units'; 3 | export const theme = { 4 | colors: { 5 | primary: colors.primary, 6 | secondary: colors.secondary, 7 | primaryDark: colors.primaryDark, 8 | secondaryDark: colors.secondaryDark, 9 | error: colors.error, 10 | black: colors.black, 11 | blackNormal: colors.blackNormal, 12 | blackDark: colors.blackDark, 13 | blackLight: colors.blackLight, 14 | white: colors.white, 15 | gray: colors.gray, 16 | }, 17 | space: { 18 | spacing1: units.sizes.spacing1, 19 | spacing2: units.sizes.spacing2, 20 | spacing4: units.sizes.spacing4, 21 | spacing8: units.sizes.spacing8, 22 | spacing10: units.sizes.spacing10, 23 | spacing12: units.sizes.spacing12, 24 | spacing16: units.sizes.spacing16, 25 | spacing18: units.sizes.spacing18, 26 | spacing20: units.sizes.spacing20, 27 | spacing24: units.sizes.spacing24, 28 | spacing32: units.sizes.spacing32, 29 | }, 30 | radii: { 31 | xsmall: units.borderRadius.xsmall, 32 | small: units.borderRadius.small, 33 | medium: units.borderRadius.medium, 34 | large: units.borderRadius.large, 35 | full: units.borderRadius.full, 36 | }, 37 | }; 38 | -------------------------------------------------------------------------------- /packages/mobile/android/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true 19 | 20 | # AndroidX package structure to make it clearer which packages are bundled with the 21 | # Android operating system, and which are packaged with your app's APK 22 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 23 | android.useAndroidX=true 24 | # Automatically convert third-party libraries to use AndroidX 25 | android.enableJetifier=true 26 | 27 | # Version of flipper SDK to use with React Native 28 | FLIPPER_VERSION=0.37.0 29 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 🐛 3 | about: Create a bug report for react-ecommerce. 4 | --- 5 | 6 | 7 | 8 | 9 | 10 | - [ ] The issue is present in the latest release. 11 | - [ ] I have searched the [issues](https://github.com/react-shop/react-ecommerce/issues) of this repository and believe that this is not a duplicate. 12 | 13 | ## Current Behavior 😯 14 | 15 | 16 | 17 | ## Expected Behavior 🤔 18 | 19 | 20 | 21 | ## Steps to Reproduce 🕹 22 | 23 | 24 | 25 | Steps: 26 | 27 | 1. 28 | 2. 29 | 3. 30 | 4. 31 | 32 | ## Context 🔦 33 | 34 | 38 | 39 | ## Your Environment 🌎 40 | 41 | 45 | 46 | | Tech | Version | 47 | | --------------- | ------- | 48 | | react-ecommerce | v0.?.? | 49 | | React | | 50 | | Browser | | 51 | | TypeScript | | 52 | | etc. | | -------------------------------------------------------------------------------- /packages/server/src/store/dto/create-store.dto.ts: -------------------------------------------------------------------------------- 1 | import { InputType, Field, ID } from '@nestjs/graphql'; 2 | import { IsNotEmpty, IsString } from 'class-validator'; 3 | 4 | @InputType() 5 | export class CreateStoreDto { 6 | @Field() 7 | @IsString() 8 | @IsNotEmpty({ message: 'Field required ' }) 9 | readonly name: string; 10 | 11 | @Field() 12 | @IsString() 13 | @IsNotEmpty({ message: 'Field required ' }) 14 | readonly bio: string; 15 | 16 | @Field() 17 | @IsString() 18 | @IsNotEmpty({ message: 'Field required ' }) 19 | readonly slug: string; 20 | 21 | @Field() 22 | @IsString() 23 | @IsNotEmpty({ message: 'Field required ' }) 24 | readonly street: string; 25 | 26 | @Field() 27 | @IsString() 28 | @IsNotEmpty({ message: 'Field required ' }) 29 | readonly city: string; 30 | 31 | @Field() 32 | @IsString() 33 | @IsNotEmpty({ message: 'Field required ' }) 34 | readonly state: string; 35 | 36 | @Field() 37 | @IsString() 38 | @IsNotEmpty({ message: 'Field required ' }) 39 | readonly country: string; 40 | 41 | @Field() 42 | @IsString() 43 | @IsNotEmpty({ message: 'Field required ' }) 44 | readonly neighborhood: string; 45 | 46 | @Field() 47 | @IsString() 48 | @IsNotEmpty({ message: 'Field required ' }) 49 | readonly zipCode: string; 50 | 51 | @Field() 52 | @IsString() 53 | @IsNotEmpty({ message: 'Field required ' }) 54 | readonly number: string; 55 | 56 | @Field(() => [ID], { 57 | nullable: true, 58 | }) 59 | readonly employeesId: string[]; 60 | } 61 | -------------------------------------------------------------------------------- /packages/design-system/lib/web/Button/DefaultButton.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __makeTemplateObject = (this && this.__makeTemplateObject) || function (cooked, raw) { 3 | if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; } 4 | return cooked; 5 | }; 6 | var __importDefault = (this && this.__importDefault) || function (mod) { 7 | return (mod && mod.__esModule) ? mod : { "default": mod }; 8 | }; 9 | exports.__esModule = true; 10 | var styled_components_1 = __importDefault(require("styled-components")); 11 | var DefaultButton = styled_components_1["default"].button(templateObject_1 || (templateObject_1 = __makeTemplateObject(["\n padding: 15px 55px;\n border: none;\n border-radius: 6px;\n width: ", ";\n text-align: center;\n font-family: proxima-nova, sans-serif;\n font-size: ", ";\n cursor: pointer;\n\n &:hover {\n box-shadow: ", ";\n opacity: ", "\n }\n"], ["\n padding: 15px 55px;\n border: none;\n border-radius: 6px;\n width: ", ";\n text-align: center;\n font-family: proxima-nova, sans-serif;\n font-size: ", ";\n cursor: pointer;\n\n &:hover {\n box-shadow: ", ";\n opacity: ", "\n }\n"])), function (props) { return (props.full ? '100%' : 'auto'); }, function (_a) { 12 | var theme = _a.theme; 13 | return theme.fonts.sizes.body; 14 | }, function (props) { return (props.secondary ? 'none' : '0px 11px 16px rgba(40, 245, 190, 0.2)'); }, function (props) { return (props.secondary ? 0.8 : 1); }); 15 | exports["default"] = DefaultButton; 16 | var templateObject_1; 17 | -------------------------------------------------------------------------------- /packages/design-system/lib/Button/web/DefaultButton.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __makeTemplateObject = (this && this.__makeTemplateObject) || function (cooked, raw) { 3 | if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; } 4 | return cooked; 5 | }; 6 | var __importDefault = (this && this.__importDefault) || function (mod) { 7 | return (mod && mod.__esModule) ? mod : { "default": mod }; 8 | }; 9 | exports.__esModule = true; 10 | var styled_components_1 = __importDefault(require("styled-components")); 11 | var theme_1 = __importDefault(require("../../theme")); 12 | var DefaultButton = styled_components_1["default"].button(templateObject_1 || (templateObject_1 = __makeTemplateObject(["\n padding: 15px 55px;\n border: none;\n border-radius: 6px;\n width: ", ";\n text-align: center;\n font-family: proxima-nova, sans-serif;\n font-size: ", ";\n cursor: pointer;\n\n &:hover {\n box-shadow: ", ";\n opacity: ", "\n }\n"], ["\n padding: 15px 55px;\n border: none;\n border-radius: 6px;\n width: ", ";\n text-align: center;\n font-family: proxima-nova, sans-serif;\n font-size: ", ";\n cursor: pointer;\n\n &:hover {\n box-shadow: ", ";\n opacity: ", "\n }\n"])), function (props) { return (props.full ? '100%' : 'auto'); }, theme_1["default"].fonts.sizes.body, function (props) { return (props.secondary ? 'none' : '0px 11px 16px rgba(40, 245, 190, 0.2)'); }, function (props) { return (props.secondary ? 0.8 : 1); }); 13 | exports["default"] = DefaultButton; 14 | var templateObject_1; 15 | -------------------------------------------------------------------------------- /packages/mobile/android/app/_BUCK: -------------------------------------------------------------------------------- 1 | # To learn about Buck see [Docs](https://buckbuild.com/). 2 | # To run your application with Buck: 3 | # - install Buck 4 | # - `npm start` - to start the packager 5 | # - `cd android` 6 | # - `keytool -genkey -v -keystore keystores/debug.keystore -storepass android -alias androiddebugkey -keypass android -dname "CN=Android Debug,O=Android,C=US"` 7 | # - `./gradlew :app:copyDownloadableDepsToLibs` - make all Gradle compile dependencies available to Buck 8 | # - `buck install -r android/app` - compile, install and run application 9 | # 10 | 11 | load(":build_defs.bzl", "create_aar_targets", "create_jar_targets") 12 | 13 | lib_deps = [] 14 | 15 | create_aar_targets(glob(["libs/*.aar"])) 16 | 17 | create_jar_targets(glob(["libs/*.jar"])) 18 | 19 | android_library( 20 | name = "all-libs", 21 | exported_deps = lib_deps, 22 | ) 23 | 24 | android_library( 25 | name = "app-code", 26 | srcs = glob([ 27 | "src/main/java/**/*.java", 28 | ]), 29 | deps = [ 30 | ":all-libs", 31 | ":build_config", 32 | ":res", 33 | ], 34 | ) 35 | 36 | android_build_config( 37 | name = "build_config", 38 | package = "com.mobile", 39 | ) 40 | 41 | android_resource( 42 | name = "res", 43 | package = "com.mobile", 44 | res = "src/main/res", 45 | ) 46 | 47 | android_binary( 48 | name = "app", 49 | keystore = "//android/keystores:debug", 50 | manifest = "src/main/AndroidManifest.xml", 51 | package_type = "debug", 52 | deps = [ 53 | ":app-code", 54 | ], 55 | ) 56 | -------------------------------------------------------------------------------- /packages/server/src/app.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { GraphQLModule } from '@nestjs/graphql'; 3 | import { TypeOrmModule } from '@nestjs/typeorm'; 4 | import { ConfigModule } from '@nestjs/config'; 5 | import { join } from 'path'; 6 | 7 | import { UserModule } from '@user/user.module'; 8 | import { AuthModule } from '@auth/auth.module'; 9 | import { ProductModule } from '@product/product.module'; 10 | import { StoreModule } from '@store/store.module'; 11 | import { AttributeModule } from '@attribute/attribute.module'; 12 | import { CategoryModule } from '@category/category.module'; 13 | 14 | import { AppController } from './app.controller'; 15 | 16 | @Module({ 17 | imports: [ 18 | ConfigModule.forRoot({ 19 | envFilePath: ['.env.development', '.env.production'], 20 | }), 21 | GraphQLModule.forRoot({ 22 | autoSchemaFile: join(process.cwd(), 'src/graphql/schemas/schema.gql'), 23 | context: ({ req }) => ({ req }), 24 | }), 25 | TypeOrmModule.forRoot({ 26 | type: 'postgres', 27 | host: process.env.DATABASE_HOST, 28 | port: (process.env.DATABASE_PORT as unknown) as number, 29 | username: process.env.DATABASE_USER, 30 | password: process.env.DATABASE_PASSWORD, 31 | database: process.env.DATABASE_NAME, 32 | autoLoadEntities: true, 33 | synchronize: true, 34 | }), 35 | UserModule, 36 | AuthModule, 37 | ProductModule, 38 | AttributeModule, 39 | StoreModule, 40 | CategoryModule, 41 | ], 42 | controllers: [AppController], 43 | }) 44 | export class AppModule {} 45 | -------------------------------------------------------------------------------- /packages/server/src/shared/pipes/validation.pipe.ts: -------------------------------------------------------------------------------- 1 | import { 2 | PipeTransform, 3 | ArgumentMetadata, 4 | BadRequestException, 5 | HttpStatus, 6 | Injectable, 7 | } from '@nestjs/common'; 8 | import { validate } from 'class-validator'; 9 | import { plainToClass } from 'class-transformer'; 10 | import { HttpException } from '@nestjs/common/exceptions/http.exception'; 11 | 12 | @Injectable() 13 | export class ValidationPipe implements PipeTransform { 14 | async transform(value, metadata: ArgumentMetadata) { 15 | if (!value) { 16 | throw new BadRequestException('No data submitted'); 17 | } 18 | 19 | const { metatype } = metadata; 20 | if (!metatype || !this.toValidate(metatype)) { 21 | return value; 22 | } 23 | const object = plainToClass(metatype, value); 24 | const errors = await validate(object); 25 | if (errors.length > 0) { 26 | throw new HttpException( 27 | { message: 'Input data validation failed', errors: this.buildError(errors) }, 28 | HttpStatus.BAD_REQUEST, 29 | ); 30 | } 31 | return value; 32 | } 33 | 34 | private buildError(errors) { 35 | const result = {}; 36 | errors.forEach(el => { 37 | const prop = el.property; 38 | Object.entries(el.constraints).forEach(constraint => { 39 | result[prop + constraint[0]] = `${constraint[1]}`; 40 | }); 41 | }); 42 | return result; 43 | } 44 | 45 | private toValidate(metatype): boolean { 46 | const types = [String, Boolean, Number, Array, Object]; 47 | return !types.find(type => metatype === type); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /.github/stale.yml: -------------------------------------------------------------------------------- 1 | # Configuration for probot-stale based on: https://github.com/facebook/react-native/blob/master/.github/stale.yml 2 | 3 | # Number of days of inactivity before an Issue or Pull Request becomes stale 4 | daysUntilStale: 30 5 | 6 | # Number of days of inactivity before an Issue or Pull Request with the stale label is closed. 7 | daysUntilClose: 7 8 | 9 | # Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable 10 | exemptLabels: 11 | - pinned 12 | - security 13 | - discussion 14 | - good first issue 15 | - "help wanted" 16 | 17 | # Set to true to ignore issues in a project (defaults to false) 18 | exemptProjects: false 19 | 20 | # Set to true to ignore issues in a milestone (defaults to false) 21 | exemptMilestones: false 22 | 23 | # Set to true to ignore issues with an assignee (defaults to false) 24 | exemptAssignees: false 25 | 26 | # Label to use when marking as stale 27 | staleLabel: stale 28 | 29 | # Comment to post when marking as stale. Set to `false` to disable 30 | markComment: > 31 | This issue has been automatically marked as stale because it has not had 32 | recent activity. It will be closed if no further activity occurs. Thank you 33 | for your contributions. You may also mark this issue as a "discussion" and i 34 | will leave this open. 35 | # Comment to post when closing a stale Issue or Pull Request. 36 | closeComment: > 37 | Closing this issue after a prolonged period of inactivity. Fell free to reopen 38 | this issue, if this still affecting you. 39 | # Limit the number of actions per hour, from 1-30. Default is 30 40 | limitPerRun: 30 41 | 42 | # Limit to only `issues` or `pulls` 43 | only: issues 44 | -------------------------------------------------------------------------------- /packages/design-system/lib/web/Grid/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __assign = (this && this.__assign) || function () { 3 | __assign = Object.assign || function(t) { 4 | for (var s, i = 1, n = arguments.length; i < n; i++) { 5 | s = arguments[i]; 6 | for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) 7 | t[p] = s[p]; 8 | } 9 | return t; 10 | }; 11 | return __assign.apply(this, arguments); 12 | }; 13 | var __rest = (this && this.__rest) || function (s, e) { 14 | var t = {}; 15 | for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) 16 | t[p] = s[p]; 17 | if (s != null && typeof Object.getOwnPropertySymbols === "function") 18 | for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { 19 | if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) 20 | t[p[i]] = s[p[i]]; 21 | } 22 | return t; 23 | }; 24 | var __importDefault = (this && this.__importDefault) || function (mod) { 25 | return (mod && mod.__esModule) ? mod : { "default": mod }; 26 | }; 27 | exports.__esModule = true; 28 | var react_1 = __importDefault(require("react")); 29 | var styles_1 = __importDefault(require("./styles")); 30 | // import Skeleton from '../Skeleton'; 31 | var Grid = function (_a) { 32 | var children = _a.children, skeleton = _a.skeleton, skeletonHeight = _a.skeletonHeight, skeletonWidth = _a.skeletonWidth, rest = __rest(_a, ["children", "skeleton", "skeletonHeight", "skeletonWidth"]); 33 | return (react_1["default"].createElement(styles_1["default"], __assign({}, rest), children)); 34 | }; 35 | exports["default"] = Grid; 36 | -------------------------------------------------------------------------------- /packages/server/src/product/product.resolver.ts: -------------------------------------------------------------------------------- 1 | import { UseGuards } from '@nestjs/common'; 2 | import { Resolver, Args, Mutation, Query } from '@nestjs/graphql'; 3 | 4 | import { ProductService } from '@product/product.service'; 5 | import { Product } from '@product/product.entity'; 6 | import { 7 | CreateProductDto, 8 | LinkAttributeToProductDto, 9 | LinkCategoryToProductDto, 10 | } from '@product/dto'; 11 | 12 | import { GqlAuthGuard } from '@auth/auth.guard'; 13 | 14 | @Resolver() 15 | export class ProductResolver { 16 | constructor(private productService: ProductService) {} 17 | 18 | @UseGuards(GqlAuthGuard) 19 | @Mutation(() => Product) 20 | async createProduct(@Args('data') data: CreateProductDto): Promise { 21 | const product = await this.productService.create(data); 22 | 23 | return product; 24 | } 25 | 26 | @UseGuards(GqlAuthGuard) 27 | @Query(() => [Product], { 28 | nullable: true, 29 | }) 30 | async getAllProducts(): Promise { 31 | const products = await this.productService.findAll(); 32 | 33 | return products; 34 | } 35 | 36 | @UseGuards(GqlAuthGuard) 37 | @Mutation(() => Product, { 38 | nullable: true, 39 | }) 40 | async linkAttributeToProduct(@Args('data') data: LinkAttributeToProductDto): Promise { 41 | const product = await this.productService.linkAttribute(data); 42 | 43 | return product; 44 | } 45 | 46 | @UseGuards(GqlAuthGuard) 47 | @Mutation(() => Product, { 48 | nullable: true, 49 | }) 50 | async linkCategoryToProduct(@Args('data') data: LinkCategoryToProductDto): Promise { 51 | const product = await this.productService.linkCategory(data); 52 | 53 | return product; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /packages/mobile/ios/mobile-tvOS/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | NSAppTransportSecurity 26 | 27 | NSExceptionDomains 28 | 29 | localhost 30 | 31 | NSExceptionAllowsInsecureHTTPLoads 32 | 33 | 34 | 35 | 36 | NSLocationWhenInUseUsageDescription 37 | 38 | UILaunchStoryboardName 39 | LaunchScreen 40 | UIRequiredDeviceCapabilities 41 | 42 | armv7 43 | 44 | UISupportedInterfaceOrientations 45 | 46 | UIInterfaceOrientationPortrait 47 | UIInterfaceOrientationLandscapeLeft 48 | UIInterfaceOrientationLandscapeRight 49 | 50 | UIViewControllerBasedStatusBarAppearance 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /packages/design-system/src/web/Button/story/Button.story.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { storiesOf } from '@storybook/react'; 3 | import { text, select } from '@storybook/addon-knobs'; 4 | 5 | import DefaultButton from '../DefaultButton'; 6 | import { Grid } from '../..'; 7 | 8 | import { TButtonVariants } from '../DefaultButton/interface'; 9 | 10 | const stories = storiesOf('Button', module); 11 | 12 | stories 13 | .addParameters({ 14 | component: DefaultButton, 15 | }) 16 | .add('Default Button', () => { 17 | const buttonText = text('Name', 'Buy'); 18 | const label = 'Variant'; 19 | const options: TButtonVariants[] = ['primary', 'secondary']; 20 | const buttonVariant: TButtonVariants = select(label, options, 'primary'); 21 | 22 | return ( 23 | 24 | console.log('Hey, you jest clicked me!')} 28 | /> 29 | 30 | ); 31 | }) 32 | .add('Default Button Disabled', () => { 33 | const buttonText = text('Name', 'Buy'); 34 | const label = 'Variant'; 35 | const options: TButtonVariants[] = ['primary', 'secondary']; 36 | const buttonVariant: TButtonVariants = select(label, options, 'primary'); 37 | 38 | return ( 39 | 40 | console.log('Hey, you jest clicked me!')} 44 | disabled 45 | /> 46 | 47 | ); 48 | }); 49 | -------------------------------------------------------------------------------- /packages/design-system/lib/Button/web/OutlinedButton.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __makeTemplateObject = (this && this.__makeTemplateObject) || function (cooked, raw) { 3 | if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; } 4 | return cooked; 5 | }; 6 | var __importDefault = (this && this.__importDefault) || function (mod) { 7 | return (mod && mod.__esModule) ? mod : { "default": mod }; 8 | }; 9 | exports.__esModule = true; 10 | var styled_components_1 = __importDefault(require("styled-components")); 11 | var theme_1 = __importDefault(require("../../theme")); 12 | var DefaultButton_1 = __importDefault(require("./DefaultButton")); 13 | var OutlinedButton = styled_components_1["default"](DefaultButton_1["default"])(templateObject_1 || (templateObject_1 = __makeTemplateObject(["\n border: 1px solid ", ";\n color: ", ";\n font-weight: ", ";\n background-color: transparent;\n\n &:hover {\n background-color: ", ";\n color: ", ";\n }\n"], ["\n border: 1px solid ", ";\n color: ", ";\n font-weight: ", ";\n background-color: transparent;\n\n &:hover {\n background-color: ", ";\n color: ", ";\n }\n"])), function (props) { return (props.secondary ? theme_1["default"].colors.secondary : theme_1["default"].colors.primary); }, function (props) { return (props.secondary ? theme_1["default"].colors.secondary : theme_1["default"].colors.primary); }, theme_1["default"].fonts.weight.semiBold, function (props) { return (props.secondary ? theme_1["default"].colors.secondary : theme_1["default"].colors.primary); }, function (props) { return (props.secondary ? theme_1["default"].colors.white : theme_1["default"].colors.black); }); 14 | exports["default"] = OutlinedButton; 15 | var templateObject_1; 16 | -------------------------------------------------------------------------------- /packages/web/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "web", 3 | "version": "0.0.1", 4 | "private": true, 5 | "dependencies": { 6 | "@react-shop/design-system": "*", 7 | "@react-shop/sdk": "*", 8 | "react-redux": "^7.1.3", 9 | "react-router-dom": "^4.2.2", 10 | "react-slick": "^0.23.2", 11 | "redux": "^4.0.5", 12 | "redux-actions": "^2.6.4", 13 | "redux-promise-middleware": "^5.0.0", 14 | "redux-saga": "^1.1.3", 15 | "react-scripts": "3.2.0", 16 | "slick-carousel": "^1.8.1" 17 | }, 18 | "devDependencies": { 19 | "@types/jest": "^24.0.25", 20 | "@types/node": "^13.1.1", 21 | "@types/react-redux": "^7.1.5", 22 | "@types/react-router-dom": "^5.1.3", 23 | "@typescript-eslint/eslint-plugin": "^2.13.0", 24 | "@typescript-eslint/parser": "^2.13.0", 25 | "eslint": "^6.8.0", 26 | "eslint-config-airbnb": "^18.0.1", 27 | "eslint-config-prettier": "^6.8.0", 28 | "eslint-import-resolver-typescript": "^2.0.0", 29 | "eslint-plugin-import": "^2.19.1", 30 | "eslint-plugin-json": "^2.0.1", 31 | "eslint-plugin-jsx-a11y": "^6.2.3", 32 | "eslint-plugin-prettier": "^3.1.2", 33 | "eslint-plugin-react": "^7.17.0", 34 | "prettier": "^1.19.1" 35 | }, 36 | "scripts": { 37 | "start": "react-scripts start", 38 | "build": "react-scripts build", 39 | "test": "react-scripts test --env=jsdom", 40 | "eject": "react-scripts eject", 41 | "lint": "eslint . --ext .js,.jsx,.ts,.tsx" 42 | }, 43 | "browserslist": { 44 | "production": [ 45 | ">0.2%", 46 | "not dead", 47 | "not op_mini all" 48 | ], 49 | "development": [ 50 | "last 1 chrome version", 51 | "last 1 firefox version", 52 | "last 1 safari version" 53 | ] 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /packages/design-system/lib/web/Button/OutlinedButton.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __makeTemplateObject = (this && this.__makeTemplateObject) || function (cooked, raw) { 3 | if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; } 4 | return cooked; 5 | }; 6 | var __importDefault = (this && this.__importDefault) || function (mod) { 7 | return (mod && mod.__esModule) ? mod : { "default": mod }; 8 | }; 9 | exports.__esModule = true; 10 | var styled_components_1 = __importDefault(require("styled-components")); 11 | var DefaultButton_1 = __importDefault(require("./DefaultButton")); 12 | var OutlinedButton = styled_components_1["default"](DefaultButton_1["default"])(templateObject_1 || (templateObject_1 = __makeTemplateObject(["\n border: 1px solid ", ";\n color: ", ";\n font-weight: ", ";\n background-color: transparent;\n\n &:hover {\n background-color: ", ";\n color: ", ";\n }\n"], ["\n border: 1px solid ", ";\n color: ", ";\n font-weight: ", ";\n background-color: transparent;\n\n &:hover {\n background-color: ", ";\n color: ", ";\n }\n"])), function (_a) { 13 | var secondary = _a.secondary, theme = _a.theme; 14 | return (secondary ? theme.colors.secondary : theme.colors.primary); 15 | }, function (_a) { 16 | var secondary = _a.secondary, theme = _a.theme; 17 | return (secondary ? theme.colors.secondary : theme.colors.primary); 18 | }, theme.fonts.weight.semiBold, function (_a) { 19 | var secondary = _a.secondary, theme = _a.theme; 20 | return (secondary ? theme.colors.secondary : theme.colors.primary); 21 | }, function (_a) { 22 | var secondary = _a.secondary, theme = _a.theme; 23 | return (secondary ? theme.colors.white : theme.colors.black); 24 | }); 25 | exports["default"] = OutlinedButton; 26 | var templateObject_1; 27 | -------------------------------------------------------------------------------- /packages/design-system/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@react-shop/design-system", 3 | "version": "0.0.1", 4 | "private": true, 5 | "description": "a UI library for react-ecommerce", 6 | "main": "./lib/index.js", 7 | "module": "./lib-esm/index.js", 8 | "types": "./lib/index.d.ts", 9 | "author": "Vinicius Arruda", 10 | "scripts": { 11 | "story": "start-storybook", 12 | "libbuild": "tsc && tsc --build tsconfig.esm.json", 13 | "start": "tsc && tsc --build tsconfig.esm.json -w", 14 | "test": "jest --color" 15 | }, 16 | "peerDependencies": { 17 | "react": "^16.12.0", 18 | "react-dom": "^16.12.0" 19 | }, 20 | "devDependencies": { 21 | "@babel/core": "^7.6.4", 22 | "@storybook/addon-a11y": "^5.2.8", 23 | "@storybook/addon-actions": "^5.3.6", 24 | "@storybook/addon-console": "^1.2.1", 25 | "@storybook/addon-docs": "^5.2.8", 26 | "@storybook/addon-knobs": "^5.2.8", 27 | "@storybook/react": "^5.2.5", 28 | "@types/enzyme": "^3.10.4", 29 | "@types/enzyme-adapter-react-16": "^1.0.5", 30 | "@types/jest": "^24.0.25", 31 | "@types/storybook__react": "^4.0.2", 32 | "@types/styled-system": "^5.1.9", 33 | "awesome-typescript-loader": "^5.2.1", 34 | "babel-loader": "^8.0.6", 35 | "enzyme": "^3.11.0", 36 | "enzyme-adapter-react-16": "^1.15.2", 37 | "enzyme-to-json": "^3.4.3", 38 | "eslint": "^6.8.0", 39 | "eslint-config-prettier": "^6.8.0", 40 | "eslint-plugin-prettier": "^3.1.2", 41 | "jest": "^24.9.0", 42 | "jest-enzyme": "^7.1.2", 43 | "prettier": "^1.19.1", 44 | "react-docgen-typescript-loader": "^3.6.0", 45 | "sass-loader": "^8.0.0", 46 | "source-map-loader": "^0.2.4", 47 | "style-loader": "^1.0.0", 48 | "ts-jest": "^24.3.0" 49 | }, 50 | "dependencies": { 51 | "styled-system": "^5.1.5" 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /packages/mobile/ios/mobile/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | mobile 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1 25 | LSRequiresIPhoneOS 26 | 27 | NSAppTransportSecurity 28 | 29 | NSAllowsArbitraryLoads 30 | 31 | NSExceptionDomains 32 | 33 | localhost 34 | 35 | NSExceptionAllowsInsecureHTTPLoads 36 | 37 | 38 | 39 | 40 | NSLocationWhenInUseUsageDescription 41 | 42 | UILaunchStoryboardName 43 | LaunchScreen 44 | UIRequiredDeviceCapabilities 45 | 46 | armv7 47 | 48 | UISupportedInterfaceOrientations 49 | 50 | UIInterfaceOrientationPortrait 51 | UIInterfaceOrientationLandscapeLeft 52 | UIInterfaceOrientationLandscapeRight 53 | 54 | UIViewControllerBasedStatusBarAppearance 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /packages/web/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | 13 | 14 | 23 | React App 24 | 25 | 26 | 29 |
30 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /packages/server/src/user/user.entity.ts: -------------------------------------------------------------------------------- 1 | import { Field, ObjectType, ID, HideField, InputType } from '@nestjs/graphql'; 2 | import { 3 | BeforeInsert, 4 | Column, 5 | Entity, 6 | PrimaryGeneratedColumn, 7 | CreateDateColumn, 8 | UpdateDateColumn, 9 | ManyToMany, 10 | JoinTable, 11 | } from 'typeorm'; 12 | import * as bcrypt from 'bcrypt'; 13 | import { IsEmail } from 'class-validator'; 14 | 15 | import { Roles, Status } from '@user/user.interface'; 16 | import { Store } from '@store/store.entity'; 17 | 18 | @ObjectType() 19 | @InputType('UserInput') 20 | @Entity('users') 21 | export class User { 22 | @PrimaryGeneratedColumn('uuid') 23 | @Field(() => ID) 24 | id: string; 25 | 26 | @CreateDateColumn({ name: 'created_at' }) 27 | createdAt: Date; 28 | 29 | @UpdateDateColumn({ name: 'updated_at' }) 30 | updatedAt: Date; 31 | 32 | @Column({ 33 | length: '256', 34 | }) 35 | name: string; 36 | 37 | @Column({ 38 | length: '100', 39 | }) 40 | username: string; 41 | 42 | @Column() 43 | @IsEmail() 44 | email: string; 45 | 46 | @Column({ default: '' }) 47 | bio: string; 48 | 49 | @Column({ default: '' }) 50 | image: string; 51 | 52 | @Column({ 53 | type: 'enum', 54 | enum: Roles, 55 | default: Roles.MEMBER, 56 | }) 57 | @Field(() => Roles) 58 | role: Roles; 59 | 60 | @Column({ 61 | type: 'enum', 62 | enum: Status, 63 | default: Status.ACTIVE, 64 | }) 65 | @Field(() => Status) 66 | status: Status; 67 | 68 | @HideField() 69 | @Column() 70 | password: string; 71 | 72 | @ManyToMany( 73 | () => Store, 74 | (store: Store) => store.employees, 75 | ) 76 | @Field(() => [Store], { 77 | nullable: true, 78 | }) 79 | store: Store[]; 80 | 81 | @BeforeInsert() 82 | async hashPassword() { 83 | this.password = await bcrypt.hash(this.password, 10); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /packages/ssr/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@react-shop/ssr", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint" 10 | }, 11 | "lint-staged": { 12 | "./src/**/*.{ts,js,jsx,tsx}": [ 13 | "yarn eslint --ignore-path .gitignore \"src/**/*.+(ts|js|tsx)\" --fix", 14 | "yarn prettier --ignore-path .gitignore \"src/**/*.+(ts|js|tsx)\" --write" 15 | ] 16 | }, 17 | "dependencies": { 18 | "next": "11.1.0", 19 | "react": "17.0.2", 20 | "react-dom": "17.0.2", 21 | "styled-components": "^5.3.0" 22 | }, 23 | "devDependencies": { 24 | "@commitlint/cli": "13.1.0", 25 | "@commitlint/config-conventional": "13.1.0", 26 | "@types/jest": "26.0.23", 27 | "@types/node": "16.4.0", 28 | "@types/react": "17.0.14", 29 | "@types/react-dom": "17.0.9", 30 | "@types/styled-components": "^5.1.12", 31 | "@typescript-eslint/eslint-plugin": "4.28.4", 32 | "@typescript-eslint/parser": "4.28.4", 33 | "babel-plugin-styled-components": "1.13.2", 34 | "eslint": "7.31.0", 35 | "eslint-config-airbnb": "18.2.1", 36 | "eslint-config-next": "11.0.1", 37 | "eslint-config-prettier": "8.3.0", 38 | "eslint-import-resolver-typescript": "2.4.0", 39 | "eslint-plugin-import": "2.23.4", 40 | "eslint-plugin-jsx-a11y": "6.4.1", 41 | "eslint-plugin-prettier": "3.4.0", 42 | "eslint-plugin-react": "7.24.0", 43 | "eslint-plugin-react-hooks": "4.2.0", 44 | "husky": "6.0.0", 45 | "jest": "27.0.4", 46 | "jest-environment-jsdom": "27.0.3", 47 | "jest-styled-components": "7.0.4", 48 | "lint-staged": "11.0.0", 49 | "prettier": "2.3.2", 50 | "ts-jest": "27.0.3", 51 | "ts-loader": "9.2.3", 52 | "typescript": "4.3.5", 53 | "webpack": "5.45.1" 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /packages/server/src/store/store.resolver.ts: -------------------------------------------------------------------------------- 1 | import { UseGuards } from '@nestjs/common'; 2 | import { Resolver, Args, Mutation, Query } from '@nestjs/graphql'; 3 | 4 | import { StoreService } from '@store/store.service'; 5 | import { Store } from '@store/store.entity'; 6 | import { CreateStoreDto, LinkEmployeeToStoreDto, LinkProductToStoreDto } from '@store/dto'; 7 | 8 | import { GqlAuthGuard } from '@auth/auth.guard'; 9 | 10 | @Resolver() 11 | export class StoreResolver { 12 | constructor(private storeService: StoreService) {} 13 | 14 | @UseGuards(GqlAuthGuard) 15 | @Mutation(() => Store) 16 | async createStore(@Args('data') data: CreateStoreDto): Promise { 17 | const store = await this.storeService.create(data); 18 | 19 | return store; 20 | } 21 | 22 | @UseGuards(GqlAuthGuard) 23 | @Mutation(() => Store, { 24 | nullable: true, 25 | }) 26 | async linkEmployeesToStore(@Args('data') data: LinkEmployeeToStoreDto): Promise { 27 | const store = await this.storeService.linkEmployees(data); 28 | 29 | return store; 30 | } 31 | 32 | @UseGuards(GqlAuthGuard) 33 | @Mutation(() => Store, { 34 | nullable: true, 35 | }) 36 | async linkProductsToStore(@Args('data') data: LinkProductToStoreDto): Promise { 37 | const store = await this.storeService.linkProducts(data); 38 | 39 | return store; 40 | } 41 | 42 | @UseGuards(GqlAuthGuard) 43 | @Query(() => Store, { 44 | nullable: true, 45 | }) 46 | async findStoreById(@Args('id') id: string): Promise { 47 | const store = await this.storeService.findById(id); 48 | 49 | return store; 50 | } 51 | 52 | @UseGuards(GqlAuthGuard) 53 | @Query(() => [Store], { 54 | nullable: true, 55 | }) 56 | async getAllStores(): Promise { 57 | const stores = await this.storeService.findAll(); 58 | 59 | return stores; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /packages/server/src/store/store.entity.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Entity, 3 | PrimaryGeneratedColumn, 4 | Column, 5 | ManyToMany, 6 | JoinTable, 7 | OneToMany, 8 | CreateDateColumn, 9 | UpdateDateColumn, 10 | } from 'typeorm'; 11 | import { Field, ObjectType, ID, InputType } from '@nestjs/graphql'; 12 | 13 | import { Product } from '@product/product.entity'; 14 | 15 | import { User } from '@user/user.entity'; 16 | 17 | @ObjectType() 18 | @InputType('StoreInput') 19 | @Entity() 20 | export class Store { 21 | @PrimaryGeneratedColumn('increment') 22 | @Field(() => ID) 23 | id: string; 24 | 25 | @CreateDateColumn({ name: 'created_at' }) 26 | createdAt: Date; 27 | 28 | @UpdateDateColumn({ name: 'updated_at' }) 29 | updatedAt: Date; 30 | 31 | @Column() 32 | name: string; 33 | 34 | @Column() 35 | bio: string; 36 | 37 | @Column({ 38 | default: 0, 39 | }) 40 | rate: number; 41 | 42 | @Column({ 43 | unique: true, 44 | }) 45 | slug: string; 46 | 47 | @Column() 48 | street: string; 49 | 50 | @Column() 51 | city: string; 52 | 53 | @Column() 54 | state: string; 55 | 56 | @Column() 57 | country: string; 58 | 59 | @Column() 60 | neighborhood: string; 61 | 62 | @Column() 63 | number: string; 64 | 65 | @Column() 66 | zipCode: string; 67 | 68 | @Column({ 69 | default: 0, 70 | }) 71 | sales: number; 72 | 73 | @OneToMany( 74 | () => Product, 75 | (product: Product) => product.store, 76 | { 77 | cascade: true, 78 | }, 79 | ) 80 | @JoinTable() 81 | @Field(() => [Product], { 82 | nullable: true, 83 | }) 84 | products: Product[]; 85 | 86 | @ManyToMany( 87 | () => User, 88 | (user: User) => user.store, 89 | { 90 | cascade: true, 91 | }, 92 | ) 93 | @JoinTable() 94 | @Field(() => [User], { 95 | nullable: true, 96 | }) 97 | employees: User[]; 98 | } 99 | -------------------------------------------------------------------------------- /packages/design-system/lib/theme/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __importDefault = (this && this.__importDefault) || function (mod) { 3 | return (mod && mod.__esModule) ? mod : { "default": mod }; 4 | }; 5 | exports.__esModule = true; 6 | var colors_1 = __importDefault(require("./colors")); 7 | var units_1 = __importDefault(require("./units")); 8 | exports.theme = { 9 | colors: { 10 | primary: colors_1["default"].primary, 11 | secondary: colors_1["default"].secondary, 12 | primaryDark: colors_1["default"].primaryDark, 13 | error: colors_1["default"].error, 14 | black: colors_1["default"].black, 15 | blackNormal: colors_1["default"].blackNormal, 16 | blackDark: colors_1["default"].blackDark, 17 | blackLight: colors_1["default"].blackLight, 18 | white: colors_1["default"].white, 19 | gray: colors_1["default"].gray 20 | }, 21 | space: { 22 | spacing1: units_1["default"].sizes.spacing1, 23 | spacing2: units_1["default"].sizes.spacing2, 24 | spacing4: units_1["default"].sizes.spacing4, 25 | spacing8: units_1["default"].sizes.spacing8, 26 | spacing10: units_1["default"].sizes.spacing10, 27 | spacing12: units_1["default"].sizes.spacing12, 28 | spacing16: units_1["default"].sizes.spacing16, 29 | spacing18: units_1["default"].sizes.spacing18, 30 | spacing20: units_1["default"].sizes.spacing20, 31 | spacing24: units_1["default"].sizes.spacing24, 32 | spacing32: units_1["default"].sizes.spacing32 33 | }, 34 | radii: { 35 | xsmall: units_1["default"].borderRadius.xsmall, 36 | small: units_1["default"].borderRadius.small, 37 | medium: units_1["default"].borderRadius.medium, 38 | large: units_1["default"].borderRadius.large, 39 | full: units_1["default"].borderRadius.full 40 | } 41 | }; 42 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## Pull request checklist 2 | 3 | Please check if your PR fulfills the following requirements: 4 | 5 | - [ ] Tests for the changes have been added (for bug fixes / features) 6 | - [ ] Build (`yarn build`) was run locally and any changes were pushed 7 | - [ ] Lint has passed locally and any fixes were made for failures 8 | - [ ] Code Coverage stayed the same or increased 9 | 10 | ## Pull request type 11 | 12 | 13 | 14 | 15 | 16 | Please check the type of change your PR introduces: 17 | 18 | - [ ] Bugfix 19 | - [ ] Feature 20 | - [ ] Code style update (formatting, renaming) 21 | - [ ] Refactoring (no functional changes, no api changes) 22 | - [ ] Build related changes 23 | - [ ] Tests related changes 24 | - [ ] Documentation content changes 25 | - [ ] Other (please describe): 26 | 27 | ## What is the current behavior? 28 | 29 | 30 | 31 | 32 | ## What is the new behavior? 33 | 34 | 35 | 36 | ### - Ex: Adding a new cool button at home screen 37 | 38 | 39 | 40 | ## Does this introduce a breaking change? 41 | 42 | - [ ] Yes 43 | - [ ] No 44 | 45 | 46 | 47 | ## Other information 48 | 49 | 50 | 51 | ## Screenshots (optional) 52 | 53 | 54 | -------------------------------------------------------------------------------- /packages/server/src/category/category.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable, HttpStatus, HttpException } from '@nestjs/common'; 2 | import { InjectRepository } from '@nestjs/typeorm'; 3 | import { Repository, getRepository } from 'typeorm'; 4 | import { validate } from 'class-validator'; 5 | 6 | import { Category } from '@category/category.entity'; 7 | import { CreateCategoryDto } from '@category/dto/create-category.dto'; 8 | 9 | @Injectable() 10 | export class CategoryService { 11 | constructor( 12 | @InjectRepository(Category) 13 | private readonly categoryRepository: Repository, 14 | ) {} 15 | 16 | async create(dto: CreateCategoryDto): Promise { 17 | const { name, description } = dto; 18 | const qb = await getRepository(Category) 19 | .createQueryBuilder('category') 20 | .where('category.name = :name', { name }); 21 | 22 | const category = await qb.getOne(); 23 | 24 | if (category) { 25 | const errors = { message: 'This category already been registered' }; 26 | throw new HttpException( 27 | { message: 'Input data validation failed', errors }, 28 | HttpStatus.BAD_REQUEST, 29 | ); 30 | } 31 | 32 | const newCategory = new Category(); 33 | newCategory.name = name; 34 | newCategory.description = description; 35 | 36 | const errors = await validate(newCategory); 37 | if (errors.length > 0) { 38 | const _errors = { name: 'Name is not valid.' }; 39 | throw new HttpException( 40 | { message: 'Input data validation failed', _errors }, 41 | HttpStatus.BAD_REQUEST, 42 | ); 43 | } else { 44 | const savedCategory = await this.categoryRepository.save(newCategory); 45 | 46 | return savedCategory; 47 | } 48 | } 49 | 50 | async findAll(): Promise { 51 | const categories = await this.categoryRepository.find(); 52 | 53 | return categories; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /packages/server/src/attribute/attribute.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable, HttpStatus, HttpException } from '@nestjs/common'; 2 | import { InjectRepository } from '@nestjs/typeorm'; 3 | import { Repository, getRepository } from 'typeorm'; 4 | import { validate } from 'class-validator'; 5 | 6 | import { Attribute } from '@attribute/attribute.entity'; 7 | import { CreateAttributeDto } from '@attribute/dto/create-attribute.dto'; 8 | 9 | @Injectable() 10 | export class AttributeService { 11 | constructor( 12 | @InjectRepository(Attribute) 13 | private readonly attributeRepository: Repository, 14 | ) {} 15 | 16 | async create(dto: CreateAttributeDto): Promise { 17 | const { value, name, type } = dto; 18 | 19 | const attribute = await this.attributeRepository.findOne({ 20 | where: { 21 | value, 22 | }, 23 | }); 24 | 25 | if (attribute) { 26 | const errors = { message: 'This value already been registered' }; 27 | throw new HttpException( 28 | { message: 'Input data validation failed', errors }, 29 | HttpStatus.BAD_REQUEST, 30 | ); 31 | } 32 | 33 | const newAttribute = new Attribute(); 34 | newAttribute.name = name; 35 | newAttribute.type = type; 36 | newAttribute.value = value; 37 | 38 | const errors = await validate(newAttribute); 39 | if (errors.length > 0) { 40 | const _errors = { message: 'Value is not valid.' }; 41 | throw new HttpException( 42 | { message: 'Input data validation failed', _errors }, 43 | HttpStatus.BAD_REQUEST, 44 | ); 45 | } else { 46 | const savedAttribute = await this.attributeRepository.save(newAttribute); 47 | 48 | return savedAttribute; 49 | } 50 | } 51 | 52 | async getAll(): Promise { 53 | const attributes = await this.attributeRepository.find({ 54 | relations: ['product'], 55 | }); 56 | 57 | return attributes; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /packages/server/src/product/product.entity.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Entity, 3 | PrimaryGeneratedColumn, 4 | Column, 5 | JoinTable, 6 | OneToMany, 7 | ManyToOne, 8 | CreateDateColumn, 9 | UpdateDateColumn, 10 | } from 'typeorm'; 11 | import { Field, ObjectType, ID, InputType } from '@nestjs/graphql'; 12 | 13 | import { Attribute } from '@attribute/attribute.entity'; 14 | import { Store } from '@store/store.entity'; 15 | import { Category } from '@category/category.entity'; 16 | @ObjectType() 17 | @InputType('ProductInput') 18 | @Entity() 19 | export class Product { 20 | @PrimaryGeneratedColumn('increment') 21 | @Field(() => ID) 22 | id: string; 23 | 24 | @CreateDateColumn({ name: 'created_at' }) 25 | createdAt: Date; 26 | 27 | @UpdateDateColumn({ name: 'updated_at' }) 28 | updatedAt: Date; 29 | 30 | @Column() 31 | title: string; 32 | 33 | @Column() 34 | description: string; 35 | 36 | @Column() 37 | brand: string; 38 | 39 | @Column({ 40 | unique: true, 41 | }) 42 | sku: string; 43 | 44 | @Column() 45 | price: number; 46 | 47 | @Column({ default: '' }) 48 | thumbnail: string; 49 | 50 | @Column({ default: '' }) 51 | images: string; //TODO - array images 52 | 53 | @Column({ default: 0 }) 54 | reviews: number; 55 | 56 | @Column() 57 | quantity: number; 58 | 59 | @Column() 60 | dimension: string; 61 | 62 | @OneToMany( 63 | () => Attribute, 64 | attribute => attribute.product, 65 | { 66 | cascade: true, 67 | }, 68 | ) 69 | @JoinTable() 70 | @Field(() => [Attribute], { 71 | nullable: true, 72 | }) 73 | attributes: Attribute[]; 74 | 75 | @ManyToOne( 76 | () => Store, 77 | (store: Store) => store.products, 78 | ) 79 | @Field(() => Store, { 80 | nullable: true, 81 | }) 82 | store: Store; 83 | 84 | @OneToMany( 85 | () => Category, 86 | category => category.products, 87 | { 88 | cascade: true, 89 | }, 90 | ) 91 | @JoinTable() 92 | @Field(() => [Category], { 93 | nullable: true, 94 | }) 95 | categories: Category[]; 96 | } 97 | -------------------------------------------------------------------------------- /packages/mobile/ios/mobileTests/mobileTests.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | #import 5 | #import 6 | 7 | #define TIMEOUT_SECONDS 600 8 | #define TEXT_TO_LOOK_FOR @"Welcome to React" 9 | 10 | @interface mobileTests : XCTestCase 11 | 12 | @end 13 | 14 | @implementation mobileTests 15 | 16 | - (BOOL)findSubviewInView:(UIView *)view matching:(BOOL(^)(UIView *view))test 17 | { 18 | if (test(view)) { 19 | return YES; 20 | } 21 | for (UIView *subview in [view subviews]) { 22 | if ([self findSubviewInView:subview matching:test]) { 23 | return YES; 24 | } 25 | } 26 | return NO; 27 | } 28 | 29 | - (void)testRendersWelcomeScreen 30 | { 31 | UIViewController *vc = [[[RCTSharedApplication() delegate] window] rootViewController]; 32 | NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS]; 33 | BOOL foundElement = NO; 34 | 35 | __block NSString *redboxError = nil; 36 | #ifdef DEBUG 37 | RCTSetLogFunction(^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) { 38 | if (level >= RCTLogLevelError) { 39 | redboxError = message; 40 | } 41 | }); 42 | #endif 43 | 44 | while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) { 45 | [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; 46 | [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; 47 | 48 | foundElement = [self findSubviewInView:vc.view matching:^BOOL(UIView *view) { 49 | if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) { 50 | return YES; 51 | } 52 | return NO; 53 | }]; 54 | } 55 | 56 | #ifdef DEBUG 57 | RCTSetLogFunction(RCTDefaultLogFunction); 58 | #endif 59 | 60 | XCTAssertNil(redboxError, @"RedBox error: %@", redboxError); 61 | XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS); 62 | } 63 | 64 | 65 | @end 66 | -------------------------------------------------------------------------------- /packages/design-system/src/web/Button/DefaultButton/__tests__/__snapshots__/index.spec.tsx.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`Unit | DefaultButton should compare a snapshot with a disabled style 1`] = ` 4 | 74 | 75 | 76 | 77 | `; 78 | 79 | exports[`Unit | DefaultButton should create snapshot 1`] = `"Press me"`; 80 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # React E-commerce 2 | 3 | This project is being restructured. 4 | 5 | ## This project is created using: 6 | 7 | - [x] Monorepo 8 | - [x] Lerna 9 | - [x] Design System 10 | - [x] NextJs (SSR) 11 | - [ ] Hooks 12 | - [ ] Redux Hooks 13 | - [x] Storybook 14 | - [x] NestJs 15 | - [x] Graphql 16 | 17 | ## Future Features 18 | 19 | - Home (List products) 20 | - Detail products 21 | - Recommended products 22 | - Cart 23 | - Login / Register 24 | - Admin (Seller) 25 | - Profile (Buyer) 26 | - Contact Us 27 | - Message between Seller and Buyer 28 | - Ratings about the Seller 29 | - Dashboard for Sellers 30 | - Notifications 31 | - Favorites 32 | - Pwa 33 | - Firebase or storage 34 | - Socket.io 35 | - App 36 | - SSR 37 | 38 | ## Sitemap 39 | 40 | ``` 41 | ├── Home 42 | │ 43 | ├── Social Media Links 44 | │ ├── Twitter 45 | │ ├── Instagram 46 | │ └── Facebook 47 | │ 48 | ├── Shop Categories 49 | │ ├── Mens 50 | │ │ ├── T-Shirts 51 | │ │ └── Caps 52 | │ │ 53 | │ ├── Womans 54 | │ │ 55 | │ │ 56 | │ └── News 57 | │ └── Any 58 | │ 59 | ├── About Us 60 | │ └── Out Story 61 | │ 62 | ├── Contact 63 | │ ├── Info/Form 64 | │ ├── Terms 65 | │ └── FAQ 66 | │ 67 | ├── Account 68 | │ ├── Profile 69 | │ ├── Payment Methods 70 | │ ├── Saved Address 71 | │ ├── Order History 72 | │ └── Password 73 | │ 74 | ├── Forms 75 | │ ├── Login 76 | │ ├── Register 77 | │ ├── Forgot Password 78 | │ └── Contact 79 | │ 80 | └── Cart / Checkout 81 | ├── Cart Overview 82 | ├── Shipping Address 83 | ├── Billing Details 84 | ├── Payment Method 85 | └── Order Summary 86 | ``` 87 | 88 | ## Run the project 89 | 90 | `yarn` 91 | 92 | `yarn start` 93 | 94 | 95 | Install dependencies in package: `cd packages/name && yarn add -W dependencie-name` 96 | 97 | ## Storybook for Design System 98 | 99 | `yarn story` 100 | 101 | ## Tests 102 | 103 | `yarn test` to run ALL packages test at the same time or `cd packages/ && yarn test` 104 | 105 | ### Lerna commands 106 | 107 | https://lerna.js.org/ 108 | 109 | Api: https://github.com/viniarruda/elixir-ecommerce-api [Elixir] 110 | 111 | Enjoy! 112 | -------------------------------------------------------------------------------- /packages/design-system/src/web/Button/DefaultButton/__tests__/index.spec.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { mountWithTheme } from '../../../../../__tests__/helpers'; 3 | 4 | import DefaultButton from '..'; 5 | 6 | describe('Unit | DefaultButton', () => { 7 | const onPress = jest.fn(); 8 | 9 | afterEach(() => { 10 | jest.clearAllMocks(); 11 | }); 12 | 13 | it('should create snapshot', () => { 14 | const wrapper = mountWithTheme( 15 | , 16 | ); 17 | 18 | expect(wrapper.text()).toMatchSnapshot(); 19 | }); 20 | 21 | it('should render a Button with a label Press me', () => { 22 | const wrapper = mountWithTheme( 23 | , 24 | ); 25 | 26 | expect(wrapper.text()).toContain('Press me'); 27 | }); 28 | 29 | it('should call the onPress function one time', () => { 30 | const wrapper = mountWithTheme( 31 | , 32 | ); 33 | 34 | const onPressHandler = wrapper 35 | .find('[testID="button"]') 36 | .first() 37 | .prop('onPress') as () => void; 38 | 39 | onPressHandler(); 40 | 41 | expect(onPress).toBeCalledTimes(1); 42 | 43 | wrapper.unmount(); 44 | }); 45 | 46 | it.skip('should render a Button with a Loading', () => { 47 | const wrapper = mountWithTheme( 48 | , 49 | ); 50 | 51 | expect(wrapper.find('[testID="loadingIndicator"]').exists()).toBeTruthy(); 52 | }); 53 | 54 | it.skip('should call the onPress function zero times if the button is loading', () => { 55 | const wrapper = mountWithTheme( 56 | , 57 | ); 58 | 59 | const onPressHandler = wrapper 60 | .find('[testID="button"]') 61 | .first() 62 | .prop('onPress') as () => void; 63 | 64 | onPressHandler(); 65 | 66 | expect(onPress).toBeCalledTimes(0); 67 | }); 68 | 69 | it('should compare a snapshot with a disabled style', () => { 70 | const wrapper = mountWithTheme( 71 | , 72 | ); 73 | 74 | expect(wrapper).toMatchSnapshot(); 75 | }); 76 | 77 | it.skip('should compare a snapshot with a loading style', () => { 78 | const wrapper = mountWithTheme( 79 |