├── apps ├── api │ ├── src │ │ ├── assets │ │ │ └── .gitkeep │ │ ├── environments │ │ │ ├── environment.prod.ts │ │ │ └── environment.ts │ │ ├── app │ │ │ └── app.module.ts │ │ └── main.ts │ ├── .eslintrc.json │ ├── tsconfig.spec.json │ ├── tsconfig.json │ ├── tsconfig.app.json │ └── jest.config.js ├── web │ ├── src │ │ ├── test-setup.ts │ │ ├── styles.scss │ │ ├── app │ │ │ ├── app.component.ts │ │ │ └── app.module.ts │ │ ├── index.html │ │ ├── main.ts │ │ └── polyfills.ts │ ├── tsconfig.editor.json │ ├── tsconfig.app.json │ ├── tsconfig.spec.json │ ├── tslint.json │ ├── tsconfig.json │ ├── proxy.conf.js │ ├── .browserslistrc │ └── jest.config.js ├── web-e2e │ ├── src │ │ ├── support │ │ │ ├── app.po.ts │ │ │ ├── index.ts │ │ │ └── commands.ts │ │ ├── fixtures │ │ │ └── example.json │ │ ├── integration │ │ │ └── app.spec.ts │ │ └── plugins │ │ │ └── index.js │ ├── tslint.json │ ├── tsconfig.json │ ├── tsconfig.e2e.json │ └── cypress.json └── api-e2e │ ├── src │ ├── environments │ │ ├── environment.ts │ │ └── environment.prod.ts │ └── integration │ │ ├── app.spec.ts │ │ └── core.spec.ts │ ├── .eslintrc.json │ ├── tsconfig.spec.json │ ├── tsconfig.json │ └── jest.config.js ├── tools ├── generators │ └── .gitkeep └── tsconfig.tools.json ├── .dockerignore ├── libs ├── web │ ├── assets │ │ └── src │ │ │ ├── assets │ │ │ ├── fonts │ │ │ │ └── .gitkeep │ │ │ ├── icons │ │ │ │ └── .gitkeep │ │ │ └── images │ │ │ │ └── logo.png │ │ │ └── favicon.ico │ ├── layout │ │ ├── src │ │ │ ├── test-setup.ts │ │ │ ├── index.ts │ │ │ └── lib │ │ │ │ ├── web-layout.component.ts │ │ │ │ ├── web-layout.module.ts │ │ │ │ └── web-layout.component.html │ │ ├── README.md │ │ ├── tsconfig.json │ │ ├── tsconfig.spec.json │ │ ├── tslint.json │ │ ├── tsconfig.lib.json │ │ └── jest.config.js │ ├── ui-form │ │ ├── src │ │ │ ├── test-setup.ts │ │ │ ├── index.ts │ │ │ └── lib │ │ │ │ ├── web-ui-form-field-repeat.component.ts │ │ │ │ ├── web-ui-form.validators.ts │ │ │ │ ├── web-ui-form.component.ts │ │ │ │ ├── web-ui-form.module.ts │ │ │ │ └── web-ui-form.field.ts │ │ ├── README.md │ │ ├── tsconfig.json │ │ ├── tsconfig.spec.json │ │ ├── tslint.json │ │ ├── tsconfig.lib.json │ │ └── jest.config.js │ ├── about │ │ └── feature │ │ │ ├── src │ │ │ ├── test-setup.ts │ │ │ ├── index.ts │ │ │ └── lib │ │ │ │ ├── web-about-feature.module.ts │ │ │ │ └── web-about-feature.component.ts │ │ │ ├── README.md │ │ │ ├── tsconfig.json │ │ │ ├── tsconfig.spec.json │ │ │ ├── tslint.json │ │ │ ├── tsconfig.lib.json │ │ │ └── jest.config.js │ ├── auth │ │ ├── feature │ │ │ ├── src │ │ │ │ ├── test-setup.ts │ │ │ │ ├── index.ts │ │ │ │ └── lib │ │ │ │ │ ├── components │ │ │ │ │ └── auth-page │ │ │ │ │ │ ├── auth-page.module.ts │ │ │ │ │ │ └── auth-page.component.ts │ │ │ │ │ ├── register │ │ │ │ │ ├── register.module.ts │ │ │ │ │ ├── register.component.spec.ts │ │ │ │ │ └── register.component.ts │ │ │ │ │ ├── login │ │ │ │ │ ├── login.component.spec.ts │ │ │ │ │ ├── login.module.ts │ │ │ │ │ └── login.component.ts │ │ │ │ │ ├── logout │ │ │ │ │ ├── logout.component.spec.ts │ │ │ │ │ ├── logout.module.ts │ │ │ │ │ └── logout.component.ts │ │ │ │ │ └── web-auth-feature.module.ts │ │ │ ├── README.md │ │ │ ├── tsconfig.json │ │ │ ├── tsconfig.spec.json │ │ │ ├── tslint.json │ │ │ ├── tsconfig.lib.json │ │ │ └── jest.config.js │ │ └── data-access │ │ │ ├── src │ │ │ ├── test-setup.ts │ │ │ ├── index.ts │ │ │ └── lib │ │ │ │ ├── guards │ │ │ │ ├── is-logged-in.guard.spec.ts │ │ │ │ └── is-logged-in.guard.ts │ │ │ │ ├── +state │ │ │ │ └── auth │ │ │ │ │ ├── auth.selectors.ts │ │ │ │ │ ├── auth.reducer.spec.ts │ │ │ │ │ ├── auth.actions.ts │ │ │ │ │ ├── auth.effects.spec.ts │ │ │ │ │ ├── auth.reducer.ts │ │ │ │ │ ├── auth.selectors.spec.ts │ │ │ │ │ └── auth.effects.ts │ │ │ │ ├── web-auth-data-access.service.ts │ │ │ │ └── web-auth-data-access.module.ts │ │ │ ├── README.md │ │ │ ├── tsconfig.json │ │ │ ├── tsconfig.spec.json │ │ │ ├── tslint.json │ │ │ ├── tsconfig.lib.json │ │ │ └── jest.config.js │ ├── core │ │ ├── feature │ │ │ ├── src │ │ │ │ ├── test-setup.ts │ │ │ │ ├── index.ts │ │ │ │ ├── environments │ │ │ │ │ ├── environment.prod.ts │ │ │ │ │ └── environment.ts │ │ │ │ └── lib │ │ │ │ │ ├── web-core-feature.module.ts │ │ │ │ │ └── web-core-feature-graphql.module.ts │ │ │ ├── README.md │ │ │ ├── tsconfig.json │ │ │ ├── tsconfig.spec.json │ │ │ ├── tslint.json │ │ │ ├── tsconfig.lib.json │ │ │ └── jest.config.js │ │ └── data-access │ │ │ ├── src │ │ │ ├── test-setup.ts │ │ │ ├── index.ts │ │ │ ├── lib │ │ │ │ ├── web-core-data-access.module.ts │ │ │ │ └── web-core-data-access.service.ts │ │ │ ├── graphql │ │ │ │ ├── core-feature.graphql │ │ │ │ └── auth-feature.graphql │ │ │ ├── codegen.yml │ │ │ └── generated │ │ │ │ └── graphql.ts │ │ │ ├── README.md │ │ │ ├── tsconfig.json │ │ │ ├── tsconfig.spec.json │ │ │ ├── tslint.json │ │ │ ├── tsconfig.lib.json │ │ │ └── jest.config.js │ ├── shell │ │ └── feature │ │ │ ├── src │ │ │ ├── test-setup.ts │ │ │ ├── index.ts │ │ │ └── lib │ │ │ │ ├── not-found │ │ │ │ ├── not-found.component.ts │ │ │ │ ├── not-found.module.ts │ │ │ │ └── not-found.component.spec.ts │ │ │ │ └── web-shell-feature.module.ts │ │ │ ├── README.md │ │ │ ├── tsconfig.json │ │ │ ├── tsconfig.spec.json │ │ │ ├── tslint.json │ │ │ ├── tsconfig.lib.json │ │ │ └── jest.config.js │ ├── dashboard │ │ └── feature │ │ │ ├── src │ │ │ ├── test-setup.ts │ │ │ ├── index.ts │ │ │ └── lib │ │ │ │ ├── web-dashboard-feature.module.ts │ │ │ │ ├── settings │ │ │ │ ├── web-settings-feature.component.ts │ │ │ │ └── web-settings-feature.component.html │ │ │ │ ├── messages │ │ │ │ ├── web-messages-feature.component.ts │ │ │ │ └── web-messages-feature.component.html │ │ │ │ └── posts │ │ │ │ ├── web-posts-feature.component.ts │ │ │ │ └── web-posts-feature.component.html │ │ │ ├── README.md │ │ │ ├── tsconfig.json │ │ │ ├── tsconfig.spec.json │ │ │ ├── tslint.json │ │ │ ├── tsconfig.lib.json │ │ │ └── jest.config.js │ └── style │ │ └── src │ │ └── index.scss └── api │ ├── auth │ ├── data-access │ │ ├── src │ │ │ ├── lib │ │ │ │ ├── dto │ │ │ │ │ ├── jwt.dto.ts │ │ │ │ │ ├── login.input.ts │ │ │ │ │ └── register.input.ts │ │ │ │ ├── models │ │ │ │ │ ├── role.ts │ │ │ │ │ ├── user-token.ts │ │ │ │ │ └── user.ts │ │ │ │ ├── decorators │ │ │ │ │ └── ctx-user.decorator.ts │ │ │ │ ├── api-auth-data-access.resolver.ts │ │ │ │ ├── api-auth-data-access.controller.ts │ │ │ │ ├── guards │ │ │ │ │ ├── gql-auth.guard.ts │ │ │ │ │ └── gql-auth-web.guard.ts │ │ │ │ ├── api-auth-data-access.module.ts │ │ │ │ ├── strategies │ │ │ │ │ └── jwt.strategy.ts │ │ │ │ ├── api-auth-data-access.helper.ts │ │ │ │ └── api-auth-data-access.service.ts │ │ │ └── index.ts │ │ ├── .eslintrc.json │ │ ├── README.md │ │ ├── tsconfig.json │ │ ├── tsconfig.spec.json │ │ ├── tsconfig.lib.json │ │ └── jest.config.js │ └── feature │ │ ├── src │ │ ├── index.ts │ │ └── lib │ │ │ ├── api-auth-feature.service.ts │ │ │ ├── api-auth-feature.controller.ts │ │ │ ├── api-auth-feature.module.ts │ │ │ └── api-auth-feature.resolver.ts │ │ ├── .eslintrc.json │ │ ├── README.md │ │ ├── tsconfig.json │ │ ├── tsconfig.spec.json │ │ ├── tsconfig.lib.json │ │ └── jest.config.js │ └── core │ ├── feature │ ├── src │ │ ├── index.ts │ │ └── lib │ │ │ ├── api-core-feature.controller.ts │ │ │ ├── api-core-feature.resolver.ts │ │ │ ├── config │ │ │ ├── configuration.ts │ │ │ └── validation.ts │ │ │ ├── api-core-feature.service.ts │ │ │ └── api-core-feature.module.ts │ ├── .eslintrc.json │ ├── README.md │ ├── tsconfig.json │ ├── tsconfig.spec.json │ ├── tsconfig.lib.json │ └── jest.config.js │ └── data-access │ ├── src │ ├── index.ts │ ├── lib │ │ ├── api-core-data-access.resolver.ts │ │ ├── api-core-data-access.controller.ts │ │ ├── api-core-data-access.module.ts │ │ ├── api-core-data-access.helper.ts │ │ └── api-core-data-access.service.ts │ └── prisma │ │ └── schema.prisma │ ├── .eslintrc.json │ ├── README.md │ ├── tsconfig.json │ ├── tsconfig.spec.json │ ├── tsconfig.lib.json │ └── jest.config.js ├── .prettierignore ├── jest.preset.js ├── .env.example ├── .prettierrc ├── .vscode └── extensions.json ├── Dockerfile ├── .editorconfig ├── docker-compose.yml ├── tailwind.config.js ├── .gitignore ├── jest.config.js ├── webpack.config.js ├── .eslintrc.json ├── .github └── workflows │ └── build-test.yml ├── tsconfig.base.json ├── api-schema.graphql ├── nx.json ├── tslint.json ├── README.md └── package.json /apps/api/src/assets/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tools/generators/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | dist 2 | node_modules -------------------------------------------------------------------------------- /libs/web/assets/src/assets/fonts/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /libs/web/assets/src/assets/icons/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | package.json 2 | dist 3 | coverage 4 | tmp -------------------------------------------------------------------------------- /apps/web/src/test-setup.ts: -------------------------------------------------------------------------------- 1 | import 'jest-preset-angular' 2 | -------------------------------------------------------------------------------- /libs/web/layout/src/test-setup.ts: -------------------------------------------------------------------------------- 1 | import 'jest-preset-angular' 2 | -------------------------------------------------------------------------------- /libs/web/ui-form/src/test-setup.ts: -------------------------------------------------------------------------------- 1 | import 'jest-preset-angular' 2 | -------------------------------------------------------------------------------- /libs/web/about/feature/src/test-setup.ts: -------------------------------------------------------------------------------- 1 | import 'jest-preset-angular' 2 | -------------------------------------------------------------------------------- /libs/web/auth/feature/src/test-setup.ts: -------------------------------------------------------------------------------- 1 | import 'jest-preset-angular' 2 | -------------------------------------------------------------------------------- /libs/web/core/feature/src/test-setup.ts: -------------------------------------------------------------------------------- 1 | import 'jest-preset-angular' 2 | -------------------------------------------------------------------------------- /libs/web/shell/feature/src/test-setup.ts: -------------------------------------------------------------------------------- 1 | import 'jest-preset-angular' 2 | -------------------------------------------------------------------------------- /libs/web/auth/data-access/src/test-setup.ts: -------------------------------------------------------------------------------- 1 | import 'jest-preset-angular' 2 | -------------------------------------------------------------------------------- /libs/web/core/data-access/src/test-setup.ts: -------------------------------------------------------------------------------- 1 | import 'jest-preset-angular' 2 | -------------------------------------------------------------------------------- /libs/web/dashboard/feature/src/test-setup.ts: -------------------------------------------------------------------------------- 1 | import 'jest-preset-angular' 2 | -------------------------------------------------------------------------------- /apps/web-e2e/src/support/app.po.ts: -------------------------------------------------------------------------------- 1 | export const getGreeting = () => cy.get('h1') 2 | -------------------------------------------------------------------------------- /libs/web/about/feature/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './lib/web-about-feature.module' 2 | -------------------------------------------------------------------------------- /libs/web/auth/feature/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './lib/web-auth-feature.module' 2 | -------------------------------------------------------------------------------- /libs/web/shell/feature/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './lib/web-shell-feature.module' 2 | -------------------------------------------------------------------------------- /libs/web/dashboard/feature/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './lib/web-dashboard-feature.module' 2 | -------------------------------------------------------------------------------- /apps/api-e2e/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: false, 3 | } 4 | -------------------------------------------------------------------------------- /apps/api/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { "extends": "../../.eslintrc.json", "ignorePatterns": ["!**/*"], "rules": {} } 2 | -------------------------------------------------------------------------------- /apps/api/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true, 3 | } 4 | -------------------------------------------------------------------------------- /apps/api/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: false, 3 | } 4 | -------------------------------------------------------------------------------- /apps/web/src/styles.scss: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | -------------------------------------------------------------------------------- /jest.preset.js: -------------------------------------------------------------------------------- 1 | const nxPreset = require('@nrwl/jest/preset') 2 | 3 | module.exports = { ...nxPreset } 4 | -------------------------------------------------------------------------------- /libs/api/auth/data-access/src/lib/dto/jwt.dto.ts: -------------------------------------------------------------------------------- 1 | export interface JwtDto { 2 | userId: string 3 | } 4 | -------------------------------------------------------------------------------- /apps/api-e2e/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { "extends": "../../.eslintrc.json", "ignorePatterns": ["!**/*"], "rules": {} } 2 | -------------------------------------------------------------------------------- /apps/api-e2e/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true, 3 | } 4 | -------------------------------------------------------------------------------- /libs/web/ui-form/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './lib/web-ui-form.module' 2 | export * from './lib/web-ui-form.field' 3 | -------------------------------------------------------------------------------- /libs/web/layout/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './lib/web-layout.module' 2 | export * from './lib/web-layout.component' 3 | -------------------------------------------------------------------------------- /libs/web/assets/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beeman/tailwind-twitter-clone/HEAD/libs/web/assets/src/favicon.ico -------------------------------------------------------------------------------- /libs/web/core/feature/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './environments/environment' 2 | export * from './lib/web-core-feature.module' 3 | -------------------------------------------------------------------------------- /apps/web-e2e/src/fixtures/example.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Using fixtures to represent data", 3 | "email": "hello@cypress.io" 4 | } 5 | -------------------------------------------------------------------------------- /libs/api/auth/feature/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './lib/api-auth-feature.module' 2 | export * from './lib/api-auth-feature.service' 3 | -------------------------------------------------------------------------------- /libs/api/core/feature/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './lib/api-core-feature.module' 2 | export * from './lib/api-core-feature.service' 3 | -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | NODE_ENV=development 2 | PORT=3000 3 | DATABASE_URL=postgresql://prisma:prisma@localhost:5432/prisma?schema=beehive-api4587485 4 | -------------------------------------------------------------------------------- /apps/web-e2e/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tslint.json", 3 | "linterOptions": { "exclude": ["!**/*"] }, 4 | "rules": {} 5 | } 6 | -------------------------------------------------------------------------------- /libs/api/auth/feature/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../../../.eslintrc.json", 3 | "ignorePatterns": ["!**/*"], 4 | "rules": {} 5 | } 6 | -------------------------------------------------------------------------------- /libs/api/core/data-access/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './lib/api-core-data-access.module' 2 | export * from './lib/api-core-data-access.service' 3 | -------------------------------------------------------------------------------- /libs/api/core/feature/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../../../.eslintrc.json", 3 | "ignorePatterns": ["!**/*"], 4 | "rules": {} 5 | } 6 | -------------------------------------------------------------------------------- /libs/api/auth/data-access/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../../../.eslintrc.json", 3 | "ignorePatterns": ["!**/*"], 4 | "rules": {} 5 | } 6 | -------------------------------------------------------------------------------- /libs/api/core/data-access/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../../../.eslintrc.json", 3 | "ignorePatterns": ["!**/*"], 4 | "rules": {} 5 | } 6 | -------------------------------------------------------------------------------- /libs/web/assets/src/assets/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beeman/tailwind-twitter-clone/HEAD/libs/web/assets/src/assets/images/logo.png -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "printWidth": 120, 4 | "semi": false, 5 | "trailingComma": "all", 6 | "arrowParens": "always" 7 | } 8 | -------------------------------------------------------------------------------- /libs/web/core/feature/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | api: '/api', 3 | graphql: '/graphql', 4 | production: true, 5 | } 6 | -------------------------------------------------------------------------------- /apps/web/tsconfig.editor.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "include": ["**/*.ts"], 4 | "compilerOptions": { 5 | "types": ["jest", "node"] 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /libs/web/core/data-access/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './generated/graphql' 2 | export * from './lib/web-core-data-access.module' 3 | export * from './lib/web-core-data-access.service' 4 | -------------------------------------------------------------------------------- /libs/web/style/src/index.scss: -------------------------------------------------------------------------------- 1 | @import 'tailwindcss/base'; 2 | @import 'tailwindcss/components'; 3 | @import 'tailwindcss/utilities'; 4 | 5 | html, 6 | body { 7 | height: 100vh; 8 | } 9 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "ms-vscode.vscode-typescript-tslint-plugin", 4 | "esbenp.prettier-vscode", 5 | "firsttris.vscode-jest-runner" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /libs/api/auth/feature/src/lib/api-auth-feature.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@nestjs/common' 2 | 3 | @Injectable() 4 | export class ApiAuthFeatureService { 5 | constructor() {} 6 | } 7 | -------------------------------------------------------------------------------- /libs/web/layout/README.md: -------------------------------------------------------------------------------- 1 | # web-layout 2 | 3 | This library was generated with [Nx](https://nx.dev). 4 | 5 | ## Running unit tests 6 | 7 | Run `nx test web-layout` to execute the unit tests. 8 | -------------------------------------------------------------------------------- /libs/web/ui-form/README.md: -------------------------------------------------------------------------------- 1 | # web-ui-form 2 | 3 | This library was generated with [Nx](https://nx.dev). 4 | 5 | ## Running unit tests 6 | 7 | Run `nx test web-ui-form` to execute the unit tests. 8 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:14-alpine 2 | 3 | WORKDIR /workspace 4 | 5 | COPY package.json yarn.lock /workspace/ 6 | 7 | RUN yarn 8 | 9 | COPY . . 10 | 11 | RUN yarn build 12 | 13 | CMD ["yarn", "start"] -------------------------------------------------------------------------------- /libs/web/layout/src/lib/web-layout.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core' 2 | 3 | @Component({ 4 | templateUrl: './web-layout.component.html', 5 | }) 6 | export class WebLayoutComponent {} 7 | -------------------------------------------------------------------------------- /libs/web/about/feature/README.md: -------------------------------------------------------------------------------- 1 | # web-about-feature 2 | 3 | This library was generated with [Nx](https://nx.dev). 4 | 5 | ## Running unit tests 6 | 7 | Run `nx test web-about-feature` to execute the unit tests. 8 | -------------------------------------------------------------------------------- /libs/web/auth/feature/README.md: -------------------------------------------------------------------------------- 1 | # web-auth-feature 2 | 3 | This library was generated with [Nx](https://nx.dev). 4 | 5 | ## Running unit tests 6 | 7 | Run `nx test web-auth-feature` to execute the unit tests. 8 | -------------------------------------------------------------------------------- /libs/web/core/feature/README.md: -------------------------------------------------------------------------------- 1 | # web-core-feature 2 | 3 | This library was generated with [Nx](https://nx.dev). 4 | 5 | ## Running unit tests 6 | 7 | Run `nx test web-core-feature` to execute the unit tests. 8 | -------------------------------------------------------------------------------- /libs/web/shell/feature/README.md: -------------------------------------------------------------------------------- 1 | # web-shell-feature 2 | 3 | This library was generated with [Nx](https://nx.dev). 4 | 5 | ## Running unit tests 6 | 7 | Run `nx test web-shell-feature` to execute the unit tests. 8 | -------------------------------------------------------------------------------- /apps/web/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "types": [] 6 | }, 7 | "files": ["src/main.ts", "src/polyfills.ts"] 8 | } 9 | -------------------------------------------------------------------------------- /apps/web-e2e/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "./tsconfig.e2e.json" 8 | } 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /apps/web/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core' 2 | 3 | @Component({ 4 | selector: 'beehive-root', 5 | template: '', 6 | }) 7 | export class AppComponent {} 8 | -------------------------------------------------------------------------------- /libs/web/auth/data-access/README.md: -------------------------------------------------------------------------------- 1 | # web-auth-data-access 2 | 3 | This library was generated with [Nx](https://nx.dev). 4 | 5 | ## Running unit tests 6 | 7 | Run `nx test web-auth-data-access` to execute the unit tests. 8 | -------------------------------------------------------------------------------- /libs/web/core/data-access/README.md: -------------------------------------------------------------------------------- 1 | # web-core-data-access 2 | 3 | This library was generated with [Nx](https://nx.dev). 4 | 5 | ## Running unit tests 6 | 7 | Run `nx test web-core-data-access` to execute the unit tests. 8 | -------------------------------------------------------------------------------- /libs/web/dashboard/feature/README.md: -------------------------------------------------------------------------------- 1 | # web-dashboard-feature 2 | 3 | This library was generated with [Nx](https://nx.dev). 4 | 5 | ## Running unit tests 6 | 7 | Run `nx test web-dashboard-feature` to execute the unit tests. 8 | -------------------------------------------------------------------------------- /libs/api/auth/feature/README.md: -------------------------------------------------------------------------------- 1 | # api-auth-feature 2 | 3 | This library was generated with [Nx](https://nx.dev). 4 | 5 | ## Running unit tests 6 | 7 | Run `nx test api-auth-feature` to execute the unit tests via [Jest](https://jestjs.io). 8 | -------------------------------------------------------------------------------- /libs/api/core/feature/README.md: -------------------------------------------------------------------------------- 1 | # api-core-feature 2 | 3 | This library was generated with [Nx](https://nx.dev). 4 | 5 | ## Running unit tests 6 | 7 | Run `nx test api-core-feature` to execute the unit tests via [Jest](https://jestjs.io). 8 | -------------------------------------------------------------------------------- /libs/api/auth/data-access/README.md: -------------------------------------------------------------------------------- 1 | # api-auth-data-access 2 | 3 | This library was generated with [Nx](https://nx.dev). 4 | 5 | ## Running unit tests 6 | 7 | Run `nx test api-auth-data-access` to execute the unit tests via [Jest](https://jestjs.io). 8 | -------------------------------------------------------------------------------- /libs/api/auth/data-access/src/lib/models/role.ts: -------------------------------------------------------------------------------- 1 | import { registerEnumType } from '@nestjs/graphql' 2 | import { Role } from '@prisma/client' 3 | export { Role } 4 | 5 | registerEnumType(Role, { 6 | name: 'Role', 7 | description: 'User role', 8 | }) 9 | -------------------------------------------------------------------------------- /libs/api/core/data-access/README.md: -------------------------------------------------------------------------------- 1 | # api-core-data-access 2 | 3 | This library was generated with [Nx](https://nx.dev). 4 | 5 | ## Running unit tests 6 | 7 | Run `nx test api-core-data-access` to execute the unit tests via [Jest](https://jestjs.io). 8 | -------------------------------------------------------------------------------- /apps/api/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "include": ["**/*.spec.ts", "**/*.d.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /apps/api-e2e/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "include": ["**/*.spec.ts", "**/*.d.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /apps/api/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "./tsconfig.app.json" 8 | }, 9 | { 10 | "path": "./tsconfig.spec.json" 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /apps/api-e2e/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "./tsconfig.app.json" 8 | }, 9 | { 10 | "path": "./tsconfig.spec.json" 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /libs/web/layout/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "./tsconfig.lib.json" 8 | }, 9 | { 10 | "path": "./tsconfig.spec.json" 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /libs/web/ui-form/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "./tsconfig.lib.json" 8 | }, 9 | { 10 | "path": "./tsconfig.spec.json" 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /apps/web-e2e/tsconfig.e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "sourceMap": false, 5 | "outDir": "../../dist/out-tsc", 6 | "allowJs": true, 7 | "types": ["cypress", "node"] 8 | }, 9 | "include": ["src/**/*.ts", "src/**/*.js"] 10 | } 11 | -------------------------------------------------------------------------------- /libs/api/auth/data-access/src/lib/decorators/ctx-user.decorator.ts: -------------------------------------------------------------------------------- 1 | import { createParamDecorator } from '@nestjs/common' 2 | import { GqlExecutionContext } from '@nestjs/graphql' 3 | 4 | export const CtxUser = createParamDecorator((data, ctx) => GqlExecutionContext.create(ctx).getContext().req.user) 5 | -------------------------------------------------------------------------------- /libs/api/auth/data-access/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "./tsconfig.lib.json" 8 | }, 9 | { 10 | "path": "./tsconfig.spec.json" 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /libs/api/auth/feature/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "./tsconfig.lib.json" 8 | }, 9 | { 10 | "path": "./tsconfig.spec.json" 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /libs/api/core/data-access/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "./tsconfig.lib.json" 8 | }, 9 | { 10 | "path": "./tsconfig.spec.json" 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /libs/api/core/feature/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "./tsconfig.lib.json" 8 | }, 9 | { 10 | "path": "./tsconfig.spec.json" 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /libs/web/about/feature/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "./tsconfig.lib.json" 8 | }, 9 | { 10 | "path": "./tsconfig.spec.json" 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /libs/web/auth/data-access/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "./tsconfig.lib.json" 8 | }, 9 | { 10 | "path": "./tsconfig.spec.json" 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /libs/web/auth/feature/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "./tsconfig.lib.json" 8 | }, 9 | { 10 | "path": "./tsconfig.spec.json" 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /libs/web/core/data-access/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "./tsconfig.lib.json" 8 | }, 9 | { 10 | "path": "./tsconfig.spec.json" 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /libs/web/core/feature/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "./tsconfig.lib.json" 8 | }, 9 | { 10 | "path": "./tsconfig.spec.json" 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /libs/web/shell/feature/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "./tsconfig.lib.json" 8 | }, 9 | { 10 | "path": "./tsconfig.spec.json" 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /tools/tsconfig.tools.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.base.json", 3 | "compilerOptions": { 4 | "outDir": "../dist/out-tsc/tools", 5 | "rootDir": ".", 6 | "module": "commonjs", 7 | "target": "es5", 8 | "types": ["node"] 9 | }, 10 | "include": ["**/*.ts"] 11 | } 12 | -------------------------------------------------------------------------------- /apps/web/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "files": ["src/test-setup.ts"], 9 | "include": ["**/*.spec.ts", "**/*.d.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /libs/web/dashboard/feature/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "./tsconfig.lib.json" 8 | }, 9 | { 10 | "path": "./tsconfig.spec.json" 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /apps/web/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tslint.json", 3 | "rules": { 4 | "directive-selector": [true, "attribute", "beehive", "camelCase"], 5 | "component-selector": [true, "element", "beehive", "kebab-case"] 6 | }, 7 | "linterOptions": { 8 | "exclude": ["!**/*"] 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /apps/api/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "types": ["node"], 6 | "emitDecoratorMetadata": true, 7 | "target": "es2015" 8 | }, 9 | "exclude": ["**/*.spec.ts"], 10 | "include": ["**/*.ts"] 11 | } 12 | -------------------------------------------------------------------------------- /libs/web/layout/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "files": ["src/test-setup.ts"], 9 | "include": ["**/*.spec.ts", "**/*.d.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /libs/web/ui-form/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "files": ["src/test-setup.ts"], 9 | "include": ["**/*.spec.ts", "**/*.d.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /libs/web/ui-form/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../../tslint.json", 3 | "rules": { 4 | "directive-selector": [true, "attribute", "form", "camelCase"], 5 | "component-selector": [true, "element", "form", "kebab-case"] 6 | }, 7 | "linterOptions": { 8 | "exclude": ["!**/*"] 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | postgres: 4 | image: postgres 5 | ports: 6 | - 5432:5432 7 | environment: 8 | POSTGRES_DB: prisma 9 | POSTGRES_USER: prisma 10 | POSTGRES_PASSWORD: prisma 11 | volumes: 12 | - ./tmp/postgres:/var/lib/postgresql/data 13 | -------------------------------------------------------------------------------- /libs/api/auth/feature/src/lib/api-auth-feature.controller.ts: -------------------------------------------------------------------------------- 1 | import { Controller } from '@nestjs/common' 2 | 3 | import { ApiAuthFeatureService } from './api-auth-feature.service' 4 | 5 | @Controller() 6 | export class ApiAuthFeatureController { 7 | constructor(private readonly auth: ApiAuthFeatureService) {} 8 | } 9 | -------------------------------------------------------------------------------- /libs/web/layout/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../../tslint.json", 3 | "rules": { 4 | "directive-selector": [true, "attribute", "layout", "camelCase"], 5 | "component-selector": [true, "element", "layout", "kebab-case"] 6 | }, 7 | "linterOptions": { 8 | "exclude": ["!**/*"] 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /apps/api/src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { ApiAuthFeatureModule } from '@beehive/api/auth/feature' 2 | import { ApiCoreFeatureModule } from '@beehive/api/core/feature' 3 | import { Module } from '@nestjs/common' 4 | 5 | @Module({ 6 | imports: [ApiAuthFeatureModule, ApiCoreFeatureModule], 7 | }) 8 | export class AppModule {} 9 | -------------------------------------------------------------------------------- /libs/api/auth/data-access/src/lib/models/user-token.ts: -------------------------------------------------------------------------------- 1 | import { Field, ObjectType } from '@nestjs/graphql' 2 | import { User } from './user' 3 | 4 | @ObjectType() 5 | export class UserToken { 6 | @Field({ description: 'JWT Bearer token' }) 7 | token: string 8 | 9 | @Field(() => User) 10 | user: User 11 | } 12 | -------------------------------------------------------------------------------- /libs/web/about/feature/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "files": ["src/test-setup.ts"], 9 | "include": ["**/*.spec.ts", "**/*.d.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /libs/web/about/feature/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../../../tslint.json", 3 | "rules": { 4 | "directive-selector": [true, "attribute", "about", "camelCase"], 5 | "component-selector": [true, "element", "about", "kebab-case"] 6 | }, 7 | "linterOptions": { 8 | "exclude": ["!**/*"] 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /libs/web/auth/feature/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "files": ["src/test-setup.ts"], 9 | "include": ["**/*.spec.ts", "**/*.d.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /libs/web/auth/feature/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../../../tslint.json", 3 | "rules": { 4 | "directive-selector": [true, "attribute", "auth", "camelCase"], 5 | "component-selector": [true, "element", "auth", "kebab-case"] 6 | }, 7 | "linterOptions": { 8 | "exclude": ["!**/*"] 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /libs/web/core/feature/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "files": ["src/test-setup.ts"], 9 | "include": ["**/*.spec.ts", "**/*.d.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /libs/web/core/feature/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../../../tslint.json", 3 | "rules": { 4 | "directive-selector": [true, "attribute", "core", "camelCase"], 5 | "component-selector": [true, "element", "core", "kebab-case"] 6 | }, 7 | "linterOptions": { 8 | "exclude": ["!**/*"] 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /libs/web/shell/feature/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "files": ["src/test-setup.ts"], 9 | "include": ["**/*.spec.ts", "**/*.d.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /libs/web/shell/feature/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../../../tslint.json", 3 | "rules": { 4 | "directive-selector": [true, "attribute", "shell", "camelCase"], 5 | "component-selector": [true, "element", "shell", "kebab-case"] 6 | }, 7 | "linterOptions": { 8 | "exclude": ["!**/*"] 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /libs/web/auth/data-access/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "files": ["src/test-setup.ts"], 9 | "include": ["**/*.spec.ts", "**/*.d.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /libs/web/auth/data-access/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../../../tslint.json", 3 | "rules": { 4 | "directive-selector": [true, "attribute", "auth", "camelCase"], 5 | "component-selector": [true, "element", "auth", "kebab-case"] 6 | }, 7 | "linterOptions": { 8 | "exclude": ["!**/*"] 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /libs/web/core/data-access/src/lib/web-core-data-access.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core' 2 | 3 | import { WebCoreDataAccessService } from './web-core-data-access.service' 4 | 5 | @NgModule({ 6 | imports: [], 7 | providers: [WebCoreDataAccessService], 8 | }) 9 | export class WebCoreDataAccessModule {} 10 | -------------------------------------------------------------------------------- /libs/web/core/data-access/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "files": ["src/test-setup.ts"], 9 | "include": ["**/*.spec.ts", "**/*.d.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /libs/web/core/data-access/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../../../tslint.json", 3 | "rules": { 4 | "directive-selector": [true, "attribute", "core", "camelCase"], 5 | "component-selector": [true, "element", "core", "kebab-case"] 6 | }, 7 | "linterOptions": { 8 | "exclude": ["!**/*"] 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /libs/web/dashboard/feature/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "files": ["src/test-setup.ts"], 9 | "include": ["**/*.spec.ts", "**/*.d.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /libs/api/auth/data-access/src/lib/api-auth-data-access.resolver.ts: -------------------------------------------------------------------------------- 1 | import { Resolver } from '@nestjs/graphql' 2 | 3 | import { ApiAuthDataAccessService } from './api-auth-data-access.service' 4 | 5 | @Resolver() 6 | export class ApiAuthDataAccessResolver { 7 | constructor(private readonly service: ApiAuthDataAccessService) {} 8 | } 9 | -------------------------------------------------------------------------------- /libs/api/auth/feature/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "include": ["**/*.spec.ts", "**/*.spec.tsx", "**/*.spec.js", "**/*.spec.jsx", "**/*.d.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /libs/api/core/data-access/src/lib/api-core-data-access.resolver.ts: -------------------------------------------------------------------------------- 1 | import { Resolver } from '@nestjs/graphql' 2 | 3 | import { ApiCoreDataAccessService } from './api-core-data-access.service' 4 | 5 | @Resolver() 6 | export class ApiCoreDataAccessResolver { 7 | constructor(private readonly service: ApiCoreDataAccessService) {} 8 | } 9 | -------------------------------------------------------------------------------- /libs/api/core/feature/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "include": ["**/*.spec.ts", "**/*.spec.tsx", "**/*.spec.js", "**/*.spec.jsx", "**/*.d.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /libs/api/auth/data-access/src/lib/api-auth-data-access.controller.ts: -------------------------------------------------------------------------------- 1 | import { Controller } from '@nestjs/common' 2 | 3 | import { ApiAuthDataAccessService } from './api-auth-data-access.service' 4 | 5 | @Controller() 6 | export class ApiAuthDataAccessController { 7 | constructor(private readonly auth: ApiAuthDataAccessService) {} 8 | } 9 | -------------------------------------------------------------------------------- /libs/api/auth/data-access/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "include": ["**/*.spec.ts", "**/*.spec.tsx", "**/*.spec.js", "**/*.spec.jsx", "**/*.d.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /libs/api/core/data-access/src/lib/api-core-data-access.controller.ts: -------------------------------------------------------------------------------- 1 | import { Controller } from '@nestjs/common' 2 | 3 | import { ApiCoreDataAccessService } from './api-core-data-access.service' 4 | 5 | @Controller() 6 | export class ApiCoreDataAccessController { 7 | constructor(private readonly auth: ApiCoreDataAccessService) {} 8 | } 9 | -------------------------------------------------------------------------------- /libs/api/core/data-access/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "include": ["**/*.spec.ts", "**/*.spec.tsx", "**/*.spec.js", "**/*.spec.jsx", "**/*.d.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /libs/web/dashboard/feature/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../../../tslint.json", 3 | "rules": { 4 | "directive-selector": [true, "attribute", "dashboard", "camelCase"], 5 | "component-selector": [true, "element", "dashboard", "kebab-case"] 6 | }, 7 | "linterOptions": { 8 | "exclude": ["!**/*"] 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /apps/web/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "./tsconfig.app.json" 8 | }, 9 | { 10 | "path": "./tsconfig.spec.json" 11 | }, 12 | { 13 | "path": "./tsconfig.editor.json" 14 | } 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /apps/web/proxy.conf.js: -------------------------------------------------------------------------------- 1 | const dotenv = require('dotenv') 2 | dotenv.config() 3 | 4 | const PORT = process.env.PORT || 3000 5 | const HOST = process.env.HOST || 'localhost' 6 | const target = `http://${HOST}:${PORT}` 7 | module.exports = { 8 | '/api': { target, secure: false }, 9 | '/graphql': { target, secure: false, ws: true }, 10 | } 11 | -------------------------------------------------------------------------------- /libs/api/auth/feature/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "outDir": "../../../../dist/out-tsc", 6 | "declaration": true, 7 | "types": ["node"], 8 | "target": "es6" 9 | }, 10 | "exclude": ["**/*.spec.ts"], 11 | "include": ["**/*.ts"] 12 | } 13 | -------------------------------------------------------------------------------- /libs/api/core/feature/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "outDir": "../../../../dist/out-tsc", 6 | "declaration": true, 7 | "types": ["node"], 8 | "target": "es6" 9 | }, 10 | "exclude": ["**/*.spec.ts"], 11 | "include": ["**/*.ts"] 12 | } 13 | -------------------------------------------------------------------------------- /libs/web/auth/data-access/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './lib/+state/auth/auth.actions' 2 | export * from './lib/+state/auth/auth.reducer' 3 | export * from './lib/+state/auth/auth.selectors' 4 | export * from './lib/guards/is-logged-in.guard' 5 | export * from './lib/web-auth-data-access.module' 6 | export * from './lib/web-auth-data-access.service' 7 | -------------------------------------------------------------------------------- /libs/api/auth/data-access/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "outDir": "../../../../dist/out-tsc", 6 | "declaration": true, 7 | "types": ["node"], 8 | "target": "es6" 9 | }, 10 | "exclude": ["**/*.spec.ts"], 11 | "include": ["**/*.ts"] 12 | } 13 | -------------------------------------------------------------------------------- /libs/api/core/data-access/src/lib/api-core-data-access.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common' 2 | 3 | import { ApiCoreDataAccessService } from './api-core-data-access.service' 4 | 5 | @Module({ 6 | providers: [ApiCoreDataAccessService], 7 | exports: [ApiCoreDataAccessService], 8 | }) 9 | export class ApiCoreDataAccessModule {} 10 | -------------------------------------------------------------------------------- /libs/api/core/data-access/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "outDir": "../../../../dist/out-tsc", 6 | "declaration": true, 7 | "types": ["node"], 8 | "target": "es6" 9 | }, 10 | "exclude": ["**/*.spec.ts"], 11 | "include": ["**/*.ts"] 12 | } 13 | -------------------------------------------------------------------------------- /libs/web/shell/feature/src/lib/not-found/not-found.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core' 2 | 3 | @Component({ 4 | template: ` 5 |
6 |

This page could not be found :(

7 |
8 | `, 9 | }) 10 | export class NotFoundComponent {} 11 | -------------------------------------------------------------------------------- /libs/api/auth/data-access/src/lib/dto/login.input.ts: -------------------------------------------------------------------------------- 1 | import { Field, InputType } from '@nestjs/graphql' 2 | import { IsNotEmpty, MinLength } from 'class-validator' 3 | 4 | @InputType() 5 | export class LoginInput { 6 | @Field() 7 | @IsNotEmpty() 8 | email: string 9 | 10 | @Field() 11 | @IsNotEmpty() 12 | @MinLength(8) 13 | password: string 14 | } 15 | -------------------------------------------------------------------------------- /apps/api/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | displayName: 'api', 3 | preset: '../../jest.preset.js', 4 | globals: { 5 | 'ts-jest': { 6 | tsConfig: '/tsconfig.spec.json', 7 | }, 8 | }, 9 | transform: { 10 | '^.+\\.[tj]s$': 'ts-jest', 11 | }, 12 | moduleFileExtensions: ['ts', 'js', 'html'], 13 | coverageDirectory: '../../coverage/apps/api', 14 | } 15 | -------------------------------------------------------------------------------- /libs/api/auth/feature/src/lib/api-auth-feature.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common' 2 | import { ApiAuthDataAccessModule } from '@beehive/api/auth/data-access' 3 | import { ApiAuthFeatureResolver } from './api-auth-feature.resolver' 4 | 5 | @Module({ 6 | imports: [ApiAuthDataAccessModule], 7 | providers: [ApiAuthFeatureResolver], 8 | }) 9 | export class ApiAuthFeatureModule {} 10 | -------------------------------------------------------------------------------- /apps/api-e2e/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | displayName: 'api-e2e', 3 | preset: '../../jest.preset.js', 4 | globals: { 5 | 'ts-jest': { 6 | tsConfig: '/tsconfig.spec.json', 7 | }, 8 | }, 9 | transform: { 10 | '^.+\\.[tj]s$': 'ts-jest', 11 | }, 12 | moduleFileExtensions: ['ts', 'js', 'html'], 13 | coverageDirectory: '../../coverage/apps/api-e2e', 14 | } 15 | -------------------------------------------------------------------------------- /libs/web/layout/src/lib/web-layout.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core' 2 | import { CommonModule } from '@angular/common' 3 | import { RouterModule } from '@angular/router' 4 | 5 | import { WebLayoutComponent } from './web-layout.component' 6 | 7 | @NgModule({ 8 | declarations: [WebLayoutComponent], 9 | imports: [CommonModule, RouterModule], 10 | }) 11 | export class WebLayoutModule {} 12 | -------------------------------------------------------------------------------- /apps/web/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Web 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /libs/api/core/feature/src/lib/api-core-feature.controller.ts: -------------------------------------------------------------------------------- 1 | import { Controller, Get } from '@nestjs/common' 2 | import { ApiCoreFeatureService } from './api-core-feature.service' 3 | 4 | @Controller() 5 | export class ApiCoreFeatureController { 6 | constructor(private readonly service: ApiCoreFeatureService) {} 7 | 8 | @Get('uptime') 9 | uptime() { 10 | return this.service.uptime() 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /apps/web/src/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core' 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic' 3 | import { environment } from '@beehive/web/core/feature' 4 | 5 | import { AppModule } from './app/app.module' 6 | 7 | if (environment.production) { 8 | enableProdMode() 9 | } 10 | 11 | platformBrowserDynamic() 12 | .bootstrapModule(AppModule) 13 | .catch((err) => console.error(err)) 14 | -------------------------------------------------------------------------------- /libs/api/core/feature/src/lib/api-core-feature.resolver.ts: -------------------------------------------------------------------------------- 1 | import { Float, Query, Resolver } from '@nestjs/graphql' 2 | import { ApiCoreFeatureService } from './api-core-feature.service' 3 | 4 | @Resolver() 5 | export class ApiCoreFeatureResolver { 6 | constructor(private readonly service: ApiCoreFeatureService) {} 7 | 8 | @Query(() => Float, { nullable: true }) 9 | uptime() { 10 | return this.service.uptime() 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /libs/api/auth/data-access/src/lib/guards/gql-auth.guard.ts: -------------------------------------------------------------------------------- 1 | import { ExecutionContext, Injectable } from '@nestjs/common' 2 | import { GqlExecutionContext } from '@nestjs/graphql' 3 | import { AuthGuard } from '@nestjs/passport' 4 | 5 | @Injectable() 6 | export class GqlAuthGuard extends AuthGuard('jwt') { 7 | getRequest(context: ExecutionContext) { 8 | const ctx = GqlExecutionContext.create(context) 9 | 10 | return ctx.getContext().req 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /libs/web/shell/feature/src/lib/not-found/not-found.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core' 2 | import { CommonModule } from '@angular/common' 3 | import { RouterModule } from '@angular/router' 4 | import { NotFoundComponent } from './not-found.component' 5 | 6 | @NgModule({ 7 | declarations: [NotFoundComponent], 8 | imports: [CommonModule, RouterModule.forChild([{ path: '', component: NotFoundComponent }])], 9 | }) 10 | export class NotFoundModule {} 11 | -------------------------------------------------------------------------------- /apps/web-e2e/cypress.json: -------------------------------------------------------------------------------- 1 | { 2 | "fileServerFolder": ".", 3 | "fixturesFolder": "./src/fixtures", 4 | "integrationFolder": "./src/integration", 5 | "modifyObstructiveCode": false, 6 | "pluginsFile": "./src/plugins/index", 7 | "supportFile": "./src/support/index.ts", 8 | "video": true, 9 | "videosFolder": "../../dist/cypress/apps/web-e2e/videos", 10 | "screenshotsFolder": "../../dist/cypress/apps/web-e2e/screenshots", 11 | "chromeWebSecurity": false 12 | } 13 | -------------------------------------------------------------------------------- /apps/web-e2e/src/integration/app.spec.ts: -------------------------------------------------------------------------------- 1 | import { getGreeting } from '../support/app.po' 2 | 3 | describe('web', () => { 4 | beforeEach(() => cy.visit('/')) 5 | 6 | it('should display welcome message', () => { 7 | // Custom command example, see `../support/commands.ts` file 8 | cy.login('my-email@something.com', 'myPassword') 9 | 10 | // Function helper example, see `../support/app.po.ts` file 11 | getGreeting().contains('Welcome to web!') 12 | }) 13 | }) 14 | -------------------------------------------------------------------------------- /libs/api/auth/feature/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | displayName: 'api-auth-feature', 3 | preset: '../../../../jest.preset.js', 4 | globals: { 5 | 'ts-jest': { 6 | tsConfig: '/tsconfig.spec.json', 7 | }, 8 | }, 9 | testEnvironment: 'node', 10 | transform: { 11 | '^.+\\.[tj]sx?$': 'ts-jest', 12 | }, 13 | moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'], 14 | coverageDirectory: '../../../../coverage/libs/api/auth/feature', 15 | } 16 | -------------------------------------------------------------------------------- /libs/api/core/feature/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | displayName: 'api-core-feature', 3 | preset: '../../../../jest.preset.js', 4 | globals: { 5 | 'ts-jest': { 6 | tsConfig: '/tsconfig.spec.json', 7 | }, 8 | }, 9 | testEnvironment: 'node', 10 | transform: { 11 | '^.+\\.[tj]sx?$': 'ts-jest', 12 | }, 13 | moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'], 14 | coverageDirectory: '../../../../coverage/libs/api/core/feature', 15 | } 16 | -------------------------------------------------------------------------------- /libs/web/auth/data-access/src/lib/guards/is-logged-in.guard.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing' 2 | 3 | import { IsLoggedInGuard } from './is-logged-in.guard' 4 | 5 | describe('IsLoggedInGuard', () => { 6 | let guard: IsLoggedInGuard 7 | 8 | beforeEach(() => { 9 | TestBed.configureTestingModule({}) 10 | guard = TestBed.inject(IsLoggedInGuard) 11 | }) 12 | 13 | it('should be created', () => { 14 | expect(guard).toBeTruthy() 15 | }) 16 | }) 17 | -------------------------------------------------------------------------------- /libs/web/core/data-access/src/graphql/core-feature.graphql: -------------------------------------------------------------------------------- 1 | query Uptime { 2 | uptime 3 | } 4 | 5 | fragment IntercomDetails on IntercomMessage { 6 | type 7 | scope 8 | payload 9 | } 10 | 11 | mutation IntercomPub($type: String!, $scope: String, $payload: JSON) { 12 | intercomPub(type: $type, scope: $scope, payload: $payload) { 13 | ...IntercomDetails 14 | } 15 | } 16 | 17 | subscription IntercomSub { 18 | intercomSub { 19 | ...IntercomDetails 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /libs/api/auth/data-access/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | displayName: 'api-auth-data-access', 3 | preset: '../../../../jest.preset.js', 4 | globals: { 5 | 'ts-jest': { 6 | tsConfig: '/tsconfig.spec.json', 7 | }, 8 | }, 9 | testEnvironment: 'node', 10 | transform: { 11 | '^.+\\.[tj]sx?$': 'ts-jest', 12 | }, 13 | moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'], 14 | coverageDirectory: '../../../../coverage/libs/api/auth/data-access', 15 | } 16 | -------------------------------------------------------------------------------- /libs/api/core/data-access/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | displayName: 'api-core-data-access', 3 | preset: '../../../../jest.preset.js', 4 | globals: { 5 | 'ts-jest': { 6 | tsConfig: '/tsconfig.spec.json', 7 | }, 8 | }, 9 | testEnvironment: 'node', 10 | transform: { 11 | '^.+\\.[tj]sx?$': 'ts-jest', 12 | }, 13 | moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'], 14 | coverageDirectory: '../../../../coverage/libs/api/core/data-access', 15 | } 16 | -------------------------------------------------------------------------------- /libs/web/auth/feature/src/lib/components/auth-page/auth-page.module.ts: -------------------------------------------------------------------------------- 1 | import { CommonModule } from '@angular/common' 2 | import { NgModule } from '@angular/core' 3 | import { RouterModule } from '@angular/router' 4 | import { WebUiFormModule } from '@beehive/web/ui-form' 5 | import { AuthPageComponent } from './auth-page.component' 6 | 7 | @NgModule({ 8 | declarations: [AuthPageComponent], 9 | imports: [CommonModule, RouterModule, WebUiFormModule], 10 | exports: [AuthPageComponent], 11 | }) 12 | export class AuthPageModule {} 13 | -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | const colors = require('tailwindcss/colors') 2 | module.exports = (isProd) => ({ 3 | prefix: '', 4 | purge: { 5 | enabled: isProd, 6 | content: ['./apps/**/*.html', './apps/**/*.ts', './libs/**/*.html', './libs/**/*.ts'], 7 | }, 8 | darkMode: 'class', // or 'media' or 'class' 9 | theme: { 10 | extend: { 11 | colors: { 12 | blue: colors.lightBlue, 13 | }, 14 | }, 15 | }, 16 | variants: { 17 | extend: {}, 18 | }, 19 | plugins: [require('@tailwindcss/forms')], 20 | }) 21 | -------------------------------------------------------------------------------- /libs/api/core/feature/src/lib/config/configuration.ts: -------------------------------------------------------------------------------- 1 | export const configuration = () => ({ 2 | prefix: 'api', 3 | environment: process.env.NODE_ENV, 4 | host: process.env.HOST, 5 | port: parseInt(process.env.PORT, 10), 6 | apiUrl: process.env.API_URL, 7 | api: { 8 | cookie: { 9 | name: process.env.API_COOKIE_NAME, 10 | options: { 11 | domain: process.env.API_COOKIE_DOMAIN, 12 | httpOnly: true, 13 | }, 14 | }, 15 | cors: { 16 | origin: [process.env.WEB_URL], 17 | }, 18 | }, 19 | }) 20 | -------------------------------------------------------------------------------- /libs/web/core/data-access/src/codegen.yml: -------------------------------------------------------------------------------- 1 | overwrite: true 2 | schema: 'http://localhost:3000/graphql' 3 | documents: 4 | - 'libs/web/core/data-access/src/graphql/**/*.graphql' 5 | generates: 6 | libs/web/core/data-access/src/generated/graphql.ts: 7 | config: 8 | sdkClass: true 9 | plugins: 10 | - 'typescript' 11 | - 'typescript-operations' 12 | - 'typescript-apollo-angular' 13 | ./graphql.schema.json: 14 | plugins: 15 | - 'introspection' 16 | 17 | hooks: 18 | afterAllFileWrite: 19 | - prettier --write 20 | -------------------------------------------------------------------------------- /libs/web/layout/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../../dist/out-tsc", 5 | "target": "es2015", 6 | "declaration": true, 7 | "declarationMap": true, 8 | "inlineSources": true, 9 | "types": [], 10 | "lib": ["dom", "es2018"] 11 | }, 12 | "angularCompilerOptions": { 13 | "skipTemplateCodegen": true, 14 | "strictMetadataEmit": true, 15 | "enableResourceInlining": true 16 | }, 17 | "exclude": ["src/test-setup.ts", "**/*.spec.ts"], 18 | "include": ["**/*.ts"] 19 | } 20 | -------------------------------------------------------------------------------- /libs/web/ui-form/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../../dist/out-tsc", 5 | "target": "es2015", 6 | "declaration": true, 7 | "declarationMap": true, 8 | "inlineSources": true, 9 | "types": [], 10 | "lib": ["dom", "es2018"] 11 | }, 12 | "angularCompilerOptions": { 13 | "skipTemplateCodegen": true, 14 | "strictMetadataEmit": true, 15 | "enableResourceInlining": true 16 | }, 17 | "exclude": ["src/test-setup.ts", "**/*.spec.ts"], 18 | "include": ["**/*.ts"] 19 | } 20 | -------------------------------------------------------------------------------- /libs/web/auth/feature/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../../../dist/out-tsc", 5 | "target": "es2015", 6 | "declaration": true, 7 | "declarationMap": true, 8 | "inlineSources": true, 9 | "types": [], 10 | "lib": ["dom", "es2018"] 11 | }, 12 | "angularCompilerOptions": { 13 | "skipTemplateCodegen": true, 14 | "strictMetadataEmit": true, 15 | "enableResourceInlining": true 16 | }, 17 | "exclude": ["src/test-setup.ts", "**/*.spec.ts"], 18 | "include": ["**/*.ts"] 19 | } 20 | -------------------------------------------------------------------------------- /libs/web/core/feature/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../../../dist/out-tsc", 5 | "target": "es2015", 6 | "declaration": true, 7 | "declarationMap": true, 8 | "inlineSources": true, 9 | "types": [], 10 | "lib": ["dom", "es2018"] 11 | }, 12 | "angularCompilerOptions": { 13 | "skipTemplateCodegen": true, 14 | "strictMetadataEmit": true, 15 | "enableResourceInlining": true 16 | }, 17 | "exclude": ["src/test-setup.ts", "**/*.spec.ts"], 18 | "include": ["**/*.ts"] 19 | } 20 | -------------------------------------------------------------------------------- /libs/web/about/feature/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../../../dist/out-tsc", 5 | "target": "es2015", 6 | "declaration": true, 7 | "declarationMap": true, 8 | "inlineSources": true, 9 | "types": [], 10 | "lib": ["dom", "es2018"] 11 | }, 12 | "angularCompilerOptions": { 13 | "skipTemplateCodegen": true, 14 | "strictMetadataEmit": true, 15 | "enableResourceInlining": true 16 | }, 17 | "exclude": ["src/test-setup.ts", "**/*.spec.ts"], 18 | "include": ["**/*.ts"] 19 | } 20 | -------------------------------------------------------------------------------- /libs/web/auth/data-access/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../../../dist/out-tsc", 5 | "target": "es2015", 6 | "declaration": true, 7 | "declarationMap": true, 8 | "inlineSources": true, 9 | "types": [], 10 | "lib": ["dom", "es2018"] 11 | }, 12 | "angularCompilerOptions": { 13 | "skipTemplateCodegen": true, 14 | "strictMetadataEmit": true, 15 | "enableResourceInlining": true 16 | }, 17 | "exclude": ["src/test-setup.ts", "**/*.spec.ts"], 18 | "include": ["**/*.ts"] 19 | } 20 | -------------------------------------------------------------------------------- /libs/web/core/data-access/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../../../dist/out-tsc", 5 | "target": "es2015", 6 | "declaration": true, 7 | "declarationMap": true, 8 | "inlineSources": true, 9 | "types": [], 10 | "lib": ["dom", "es2018"] 11 | }, 12 | "angularCompilerOptions": { 13 | "skipTemplateCodegen": true, 14 | "strictMetadataEmit": true, 15 | "enableResourceInlining": true 16 | }, 17 | "exclude": ["src/test-setup.ts", "**/*.spec.ts"], 18 | "include": ["**/*.ts"] 19 | } 20 | -------------------------------------------------------------------------------- /libs/web/dashboard/feature/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../../../dist/out-tsc", 5 | "target": "es2015", 6 | "declaration": true, 7 | "declarationMap": true, 8 | "inlineSources": true, 9 | "types": [], 10 | "lib": ["dom", "es2018"] 11 | }, 12 | "angularCompilerOptions": { 13 | "skipTemplateCodegen": true, 14 | "strictMetadataEmit": true, 15 | "enableResourceInlining": true 16 | }, 17 | "exclude": ["src/test-setup.ts", "**/*.spec.ts"], 18 | "include": ["**/*.ts"] 19 | } 20 | -------------------------------------------------------------------------------- /libs/web/shell/feature/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../../../dist/out-tsc", 5 | "target": "es2015", 6 | "declaration": true, 7 | "declarationMap": true, 8 | "inlineSources": true, 9 | "types": [], 10 | "lib": ["dom", "es2018"] 11 | }, 12 | "angularCompilerOptions": { 13 | "skipTemplateCodegen": true, 14 | "strictMetadataEmit": true, 15 | "enableResourceInlining": true 16 | }, 17 | "exclude": ["src/test-setup.ts", "**/*.spec.ts"], 18 | "include": ["**/*.ts"] 19 | } 20 | -------------------------------------------------------------------------------- /libs/api/auth/data-access/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './lib/api-auth-data-access.helper' 2 | export * from './lib/api-auth-data-access.module' 3 | export * from './lib/api-auth-data-access.service' 4 | export * from './lib/decorators/ctx-user.decorator' 5 | export * from './lib/dto/jwt.dto' 6 | export * from './lib/dto/login.input' 7 | export * from './lib/dto/register.input' 8 | export * from './lib/guards/gql-auth-web.guard' 9 | export * from './lib/guards/gql-auth.guard' 10 | export * from './lib/models/role' 11 | export * from './lib/models/user' 12 | export * from './lib/models/user-token' 13 | -------------------------------------------------------------------------------- /libs/web/auth/data-access/src/lib/+state/auth/auth.selectors.ts: -------------------------------------------------------------------------------- 1 | import { createFeatureSelector, createSelector } from '@ngrx/store' 2 | import { AUTH_FEATURE_KEY, AuthPartialState, State } from './auth.reducer' 3 | 4 | export const getAuthState = createFeatureSelector(AUTH_FEATURE_KEY) 5 | 6 | export const getAuthError = createSelector(getAuthState, (state: State) => state.error) 7 | 8 | export const getAuthUser = createSelector(getAuthState, (state: State) => state.user) 9 | 10 | export const isLoggedIn = createSelector(getAuthState, (state: State) => !!state.user) 11 | -------------------------------------------------------------------------------- /apps/web/src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { BrowserModule } from '@angular/platform-browser' 2 | import { NgModule } from '@angular/core' 3 | import { RouterModule } from '@angular/router' 4 | import { WebCoreFeatureModule } from '@beehive/web/core/feature' 5 | import { WebShellFeatureModule } from '@beehive/web/shell/feature' 6 | 7 | import { AppComponent } from './app.component' 8 | 9 | @NgModule({ 10 | declarations: [AppComponent], 11 | imports: [BrowserModule, RouterModule, WebCoreFeatureModule, WebShellFeatureModule], 12 | providers: [], 13 | bootstrap: [AppComponent], 14 | }) 15 | export class AppModule {} 16 | -------------------------------------------------------------------------------- /libs/web/auth/data-access/src/lib/web-auth-data-access.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core' 2 | import { ApolloAngularSDK, LoginInput, RegisterInput } from '@beehive/web/core/data-access' 3 | 4 | @Injectable() 5 | export class WebAuthDataAccessService { 6 | constructor(public readonly sdk: ApolloAngularSDK) {} 7 | 8 | me() { 9 | return this.sdk.me() 10 | } 11 | 12 | login(input: LoginInput) { 13 | return this.sdk.login({ input }) 14 | } 15 | 16 | logout() { 17 | return this.sdk.logout() 18 | } 19 | 20 | register(input: RegisterInput) { 21 | return this.sdk.register({ input }) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /libs/web/about/feature/src/lib/web-about-feature.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core' 2 | import { CommonModule } from '@angular/common' 3 | import { RouterModule } from '@angular/router' 4 | import { WebCoreDataAccessModule } from '@beehive/web/core/data-access' 5 | import { WebAboutFeatureComponent } from './web-about-feature.component' 6 | 7 | @NgModule({ 8 | declarations: [WebAboutFeatureComponent], 9 | imports: [ 10 | CommonModule, 11 | WebCoreDataAccessModule, 12 | RouterModule.forChild([{ path: '', pathMatch: 'full', component: WebAboutFeatureComponent }]), 13 | ], 14 | }) 15 | export class WebAboutFeatureModule {} 16 | -------------------------------------------------------------------------------- /libs/web/core/data-access/src/graphql/auth-feature.graphql: -------------------------------------------------------------------------------- 1 | fragment UserTokenDetails on UserToken { 2 | token 3 | user { 4 | ...UserDetails 5 | } 6 | } 7 | 8 | fragment UserDetails on User { 9 | id 10 | firstName 11 | lastName 12 | username 13 | avatarUrl 14 | email 15 | } 16 | 17 | query me { 18 | me { 19 | ...UserDetails 20 | } 21 | } 22 | 23 | mutation Logout { 24 | logout 25 | } 26 | 27 | mutation Login($input: LoginInput!) { 28 | login(input: $input) { 29 | ...UserTokenDetails 30 | } 31 | } 32 | 33 | mutation Register($input: RegisterInput!) { 34 | register(input: $input) { 35 | ...UserTokenDetails 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /libs/api/core/feature/src/lib/config/validation.ts: -------------------------------------------------------------------------------- 1 | import * as Joi from 'joi' 2 | 3 | export const validationSchema = Joi.object({ 4 | NODE_ENV: Joi.string().valid('development', 'production', 'test'), 5 | HOST: Joi.string().alphanum().default('localhost'), 6 | PORT: Joi.number().default(3000), 7 | WEB_PORT: Joi.number().default(4200), 8 | WEB_URL: Joi.string().default(`http://${process.env.HOST || 'localhost'}:${process.env.WEB_PORT}`), 9 | API_COOKIE_DOMAIN: Joi.string().default('localhost'), 10 | API_COOKIE_NAME: Joi.string().default('__session'), 11 | API_URL: Joi.string().default(`http://${process.env.HOST || 'localhost'}:${process.env.PORT}/api`), 12 | }) 13 | -------------------------------------------------------------------------------- /apps/web-e2e/src/support/index.ts: -------------------------------------------------------------------------------- 1 | // *********************************************************** 2 | // This example support/index.js is processed and 3 | // loaded automatically before your test files. 4 | // 5 | // This is a great place to put global configuration and 6 | // behavior that modifies Cypress. 7 | // 8 | // You can change the location of this file or turn off 9 | // automatically serving support files with the 10 | // 'supportFile' configuration option. 11 | // 12 | // You can read more here: 13 | // https://on.cypress.io/configuration 14 | // *********************************************************** 15 | 16 | // Import commands.js using ES2015 syntax: 17 | import './commands' 18 | -------------------------------------------------------------------------------- /libs/api/core/data-access/src/lib/api-core-data-access.helper.ts: -------------------------------------------------------------------------------- 1 | import { compareSync, hashSync } from 'bcryptjs' 2 | import { createHash } from 'crypto' 3 | 4 | const getHash = (str) => createHash('md5').update(str).digest('hex') 5 | 6 | const gravatarUrl = 'https://www.gravatar.com/avatar/' 7 | const gravatarSize = 460 8 | 9 | export const getGravatarUrl = (email = '') => `${gravatarUrl}${getHash(email)}?s=${gravatarSize}&d=mp` 10 | 11 | export function validatePassword(password: string, hashedPassword: string): boolean { 12 | return compareSync(password, hashedPassword) 13 | } 14 | 15 | export function hashPassword(password: string): string { 16 | return hashSync(password, 10) 17 | } 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | 8 | # dependencies 9 | /node_modules 10 | 11 | # IDEs and editors 12 | /.idea 13 | .project 14 | .classpath 15 | .c9/ 16 | *.launch 17 | .settings/ 18 | *.sublime-workspace 19 | 20 | # IDE - VSCode 21 | .vscode/* 22 | !.vscode/settings.json 23 | !.vscode/tasks.json 24 | !.vscode/launch.json 25 | !.vscode/extensions.json 26 | 27 | # misc 28 | /.sass-cache 29 | /connect.lock 30 | /coverage 31 | /libpeerconnection.log 32 | npm-debug.log 33 | yarn-error.log 34 | testem.log 35 | /typings 36 | 37 | # System Files 38 | .DS_Store 39 | Thumbs.db 40 | .env 41 | -------------------------------------------------------------------------------- /libs/web/auth/feature/src/lib/register/register.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core' 2 | import { CommonModule } from '@angular/common' 3 | import { Routes, RouterModule } from '@angular/router' 4 | import { WebAuthDataAccessModule } from '@beehive/web/auth/data-access' 5 | import { AuthPageModule } from '../components/auth-page/auth-page.module' 6 | import { RegisterComponent } from './register.component' 7 | 8 | const routes: Routes = [{ path: '', component: RegisterComponent }] 9 | 10 | @NgModule({ 11 | declarations: [RegisterComponent], 12 | imports: [CommonModule, RouterModule.forChild(routes), AuthPageModule, WebAuthDataAccessModule], 13 | }) 14 | export class RegisterModule {} 15 | -------------------------------------------------------------------------------- /libs/api/auth/data-access/src/lib/dto/register.input.ts: -------------------------------------------------------------------------------- 1 | import { IsEmail, IsNotEmpty, MinLength } from 'class-validator' 2 | import { InputType, Field } from '@nestjs/graphql' 3 | 4 | @InputType() 5 | export class RegisterInput { 6 | @Field() 7 | @IsNotEmpty() 8 | @IsEmail() 9 | email: string 10 | 11 | @Field({ nullable: true }) 12 | username?: string 13 | 14 | @Field({ nullable: true }) 15 | firstName?: string 16 | 17 | @Field({ nullable: true }) 18 | lastName?: string 19 | 20 | @Field({ nullable: true }) 21 | phone?: string 22 | 23 | @Field({ nullable: true }) 24 | avatarUrl?: string 25 | 26 | @Field() 27 | @IsNotEmpty() 28 | @MinLength(8) 29 | password: string 30 | } 31 | -------------------------------------------------------------------------------- /libs/api/core/feature/src/lib/api-core-feature.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable, Logger } from '@nestjs/common' 2 | import { ConfigService } from '@nestjs/config' 3 | import { CookieOptions } from 'express' 4 | import { join } from 'path' 5 | 6 | @Injectable() 7 | export class ApiCoreFeatureService { 8 | constructor(public readonly config: ConfigService) {} 9 | 10 | uptime(): number { 11 | return process.uptime() 12 | } 13 | 14 | get apiUrl(): string { 15 | return this.config.get('apiUrl') 16 | } 17 | 18 | get apiCorsOrigins(): string[] { 19 | return this.config.get('api.cors.origin') 20 | } 21 | 22 | get cookie(): { name: string; options: CookieOptions } { 23 | return this.config.get('api.cookie') 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /apps/api-e2e/src/integration/app.spec.ts: -------------------------------------------------------------------------------- 1 | import { AppModule } from '@beehive/api-app-module' 2 | import { INestApplication } from '@nestjs/common' 3 | import { Test, TestingModule } from '@nestjs/testing' 4 | import * as request from 'supertest' 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 | app.setGlobalPrefix('api') 16 | await app.init() 17 | }) 18 | 19 | it('/api/uptime (GET)', () => { 20 | return request(app.getHttpServer()).get('/api/uptime').expect(200) 21 | }) 22 | }) 23 | -------------------------------------------------------------------------------- /libs/web/auth/feature/src/lib/login/login.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing' 2 | 3 | import { LoginComponent } from './login.component' 4 | 5 | describe('LoginComponent', () => { 6 | let component: LoginComponent 7 | let fixture: ComponentFixture 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [LoginComponent], 12 | }).compileComponents() 13 | }) 14 | 15 | beforeEach(() => { 16 | fixture = TestBed.createComponent(LoginComponent) 17 | component = fixture.componentInstance 18 | fixture.detectChanges() 19 | }) 20 | 21 | it('should create', () => { 22 | expect(component).toBeTruthy() 23 | }) 24 | }) 25 | -------------------------------------------------------------------------------- /libs/web/auth/feature/src/lib/login/login.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core' 2 | import { CommonModule } from '@angular/common' 3 | import { Routes, RouterModule } from '@angular/router' 4 | import { WebAuthDataAccessModule } from '@beehive/web/auth/data-access' 5 | import { WebUiFormModule } from '@beehive/web/ui-form' 6 | import { AuthPageModule } from '../components/auth-page/auth-page.module' 7 | import { LoginComponent } from './login.component' 8 | 9 | const routes: Routes = [{ path: '', component: LoginComponent }] 10 | 11 | @NgModule({ 12 | declarations: [LoginComponent], 13 | imports: [CommonModule, RouterModule.forChild(routes), WebUiFormModule, AuthPageModule, WebAuthDataAccessModule], 14 | }) 15 | export class LoginModule {} 16 | -------------------------------------------------------------------------------- /libs/web/auth/feature/src/lib/logout/logout.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing' 2 | 3 | import { LoginComponent } from './logout.component' 4 | 5 | describe('LoginComponent', () => { 6 | let component: LoginComponent 7 | let fixture: ComponentFixture 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [LoginComponent], 12 | }).compileComponents() 13 | }) 14 | 15 | beforeEach(() => { 16 | fixture = TestBed.createComponent(LoginComponent) 17 | component = fixture.componentInstance 18 | fixture.detectChanges() 19 | }) 20 | 21 | it('should create', () => { 22 | expect(component).toBeTruthy() 23 | }) 24 | }) 25 | -------------------------------------------------------------------------------- /libs/web/auth/feature/src/lib/logout/logout.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core' 2 | import { CommonModule } from '@angular/common' 3 | import { Routes, RouterModule } from '@angular/router' 4 | import { WebAuthDataAccessModule } from '@beehive/web/auth/data-access' 5 | import { WebUiFormModule } from '@beehive/web/ui-form' 6 | import { AuthPageModule } from '../components/auth-page/auth-page.module' 7 | import { LogoutComponent } from './logout.component' 8 | 9 | const routes: Routes = [{ path: '', component: LogoutComponent }] 10 | 11 | @NgModule({ 12 | declarations: [LogoutComponent], 13 | imports: [CommonModule, RouterModule.forChild(routes), WebUiFormModule, AuthPageModule, WebAuthDataAccessModule], 14 | }) 15 | export class LogoutModule {} 16 | -------------------------------------------------------------------------------- /libs/api/core/data-access/src/prisma/schema.prisma: -------------------------------------------------------------------------------- 1 | datasource db { 2 | provider = "postgresql" 3 | url = env("DATABASE_URL") 4 | } 5 | 6 | generator client { 7 | provider = "prisma-client-js" 8 | binaryTargets = ["native"] 9 | } 10 | 11 | model User { 12 | id String @id @default(cuid()) 13 | createdAt DateTime @default(now()) 14 | updatedAt DateTime @default(now()) @updatedAt 15 | role Role 16 | developer Boolean @default(false) 17 | email String @unique 18 | username String @unique 19 | password String? 20 | firstName String? 21 | lastName String? 22 | avatarUrl String? 23 | location String? 24 | phone String? 25 | bio String? 26 | } 27 | 28 | enum Role { 29 | Web 30 | User 31 | } 32 | -------------------------------------------------------------------------------- /libs/web/auth/feature/src/lib/register/register.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing' 2 | 3 | import { RegisterComponent } from './register.component' 4 | 5 | describe('RegisterComponent', () => { 6 | let component: RegisterComponent 7 | let fixture: ComponentFixture 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [RegisterComponent], 12 | }).compileComponents() 13 | }) 14 | 15 | beforeEach(() => { 16 | fixture = TestBed.createComponent(RegisterComponent) 17 | component = fixture.componentInstance 18 | fixture.detectChanges() 19 | }) 20 | 21 | it('should create', () => { 22 | expect(component).toBeTruthy() 23 | }) 24 | }) 25 | -------------------------------------------------------------------------------- /apps/web/.browserslistrc: -------------------------------------------------------------------------------- 1 | # This file is used by the build system to adjust CSS and JS output to support the specified browsers below. 2 | # For additional information regarding the format and rule options, please see: 3 | # https://github.com/browserslist/browserslist#queries 4 | 5 | # For the full list of supported browsers by the Angular framework, please see: 6 | # https://angular.io/guide/browser-support 7 | 8 | # You can see what browsers were selected by your queries by running: 9 | # npx browserslist 10 | 11 | last 1 Chrome version 12 | last 1 Firefox version 13 | last 2 Edge major versions 14 | last 2 Safari major versions 15 | last 2 iOS major versions 16 | Firefox ESR 17 | not IE 11 # Angular supports IE 11 only as an opt-in. To opt-in, remove the 'not' prefix on this line. 18 | -------------------------------------------------------------------------------- /libs/web/about/feature/src/lib/web-about-feature.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core' 2 | import { WebCoreDataAccessService } from '@beehive/web/core/data-access' 3 | import { environment } from '@beehive/web/core/feature' 4 | 5 | @Component({ 6 | template: ` 7 |
8 |
9 |
About
10 |
{{ environment | json }}
11 | 12 |
13 |
14 | `, 15 | }) 16 | export class WebAboutFeatureComponent { 17 | public environment = environment 18 | public uptime$ = this.data.uptimeWatch() 19 | constructor(private readonly data: WebCoreDataAccessService) {} 20 | } 21 | -------------------------------------------------------------------------------- /libs/web/shell/feature/src/lib/not-found/not-found.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing' 2 | 3 | import { NotFoundComponent } from './not-found.component' 4 | 5 | describe('NotFoundComponent', () => { 6 | let component: NotFoundComponent 7 | let fixture: ComponentFixture 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [NotFoundComponent], 12 | }).compileComponents() 13 | }) 14 | 15 | beforeEach(() => { 16 | fixture = TestBed.createComponent(NotFoundComponent) 17 | component = fixture.componentInstance 18 | fixture.detectChanges() 19 | }) 20 | 21 | it('should create', () => { 22 | expect(component).toBeTruthy() 23 | }) 24 | }) 25 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | projects: [ 3 | '/apps/api', 4 | '/apps/api-e2e', 5 | '/libs/api/auth/data-access', 6 | '/libs/api/auth/feature', 7 | '/libs/api/core/data-access', 8 | '/libs/api/core/feature', 9 | '/apps/web', 10 | '/libs/web/assets', 11 | '/libs/web/auth/data-access', 12 | '/libs/web/core/data-access', 13 | '/libs/web/about/feature', 14 | '/libs/web/auth/feature', 15 | '/libs/web/core/feature', 16 | '/libs/web/dashboard/feature', 17 | '/libs/web/shell/feature', 18 | '/libs/web/layout', 19 | '/libs/web/style', 20 | '/libs/web/ui-form', 21 | ], 22 | } 23 | -------------------------------------------------------------------------------- /libs/web/ui-form/src/lib/web-ui-form-field-repeat.component.ts: -------------------------------------------------------------------------------- 1 | import { FieldArrayType } from '@ngx-formly/core' 2 | import { Component } from '@angular/core' 3 | 4 | @Component({ 5 | template: ` 6 |
7 | 8 |
9 | 10 |
11 |
12 |
13 | 16 |
17 | `, 18 | }) 19 | export class WebUiFormFieldRepeatComponent extends FieldArrayType { 20 | // 21 | } 22 | -------------------------------------------------------------------------------- /libs/web/auth/feature/src/lib/web-auth-feature.module.ts: -------------------------------------------------------------------------------- 1 | import { CommonModule } from '@angular/common' 2 | import { NgModule } from '@angular/core' 3 | import { RouterModule } from '@angular/router' 4 | 5 | @NgModule({ 6 | imports: [ 7 | CommonModule, 8 | RouterModule.forChild([ 9 | { 10 | path: 'login', 11 | loadChildren: () => import('./login/login.module').then((m) => m.LoginModule), 12 | }, 13 | { 14 | path: 'logout', 15 | loadChildren: () => import('./logout/logout.module').then((m) => m.LogoutModule), 16 | }, 17 | { 18 | path: 'register', 19 | loadChildren: () => import('./register/register.module').then((m) => m.RegisterModule), 20 | }, 21 | ]), 22 | ], 23 | }) 24 | export class WebAuthFeatureModule {} 25 | -------------------------------------------------------------------------------- /libs/web/core/feature/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // This file can be replaced during build by using the `fileReplacements` array. 2 | // `ng build --prod` replaces `environment.ts` with `environment.prod.ts`. 3 | // The list of file replacements can be found in `angular.json`. 4 | 5 | export const environment = { 6 | api: '/api', 7 | graphql: '/graphql', 8 | production: false, 9 | } 10 | 11 | /* 12 | * For easier debugging in development mode, you can import the following file 13 | * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`. 14 | * 15 | * This import should be commented out in production mode because it will have a negative impact 16 | * on performance if an error is thrown. 17 | */ 18 | // import 'zone.js/dist/zone-error'; // Included with Angular CLI. 19 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const webpackMerge = require('webpack-merge') 2 | 3 | module.exports = (config) => { 4 | const merge = webpackMerge && webpackMerge.merge ? webpackMerge.merge : webpackMerge 5 | const isProd = config.mode === 'production' 6 | const tailwindConfig = require('./tailwind.config.js')(isProd) 7 | 8 | return merge(config, { 9 | module: { 10 | rules: [ 11 | { 12 | test: /\.scss$/, 13 | loader: 'postcss-loader', 14 | options: { 15 | postcssOptions: { 16 | ident: 'postcss', 17 | syntax: 'postcss-scss', 18 | plugins: [require('postcss-import'), require('tailwindcss')(tailwindConfig), require('autoprefixer')], 19 | }, 20 | }, 21 | }, 22 | ], 23 | }, 24 | }) 25 | } 26 | -------------------------------------------------------------------------------- /libs/web/auth/feature/src/lib/logout/logout.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core' 2 | import { Router } from '@angular/router' 3 | import { Store } from '@ngrx/store' 4 | import { getAuthUser, logout } from '@beehive/web/auth/data-access' 5 | import { delay, tap } from 'rxjs/operators' 6 | 7 | @Component({ 8 | template: `
Logging out...
`, 9 | }) 10 | export class LogoutComponent { 11 | getAuthUser = this.store.select(getAuthUser) 12 | 13 | constructor(private readonly store: Store, private readonly router: Router) { 14 | this.getAuthUser 15 | .pipe( 16 | delay(300), 17 | tap(() => this.store.dispatch(logout())), 18 | ) 19 | .subscribe(() => this.router.navigate(['/'])) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /apps/web/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | displayName: 'web', 3 | preset: '../../jest.preset.js', 4 | setupFilesAfterEnv: ['/src/test-setup.ts'], 5 | globals: { 6 | 'ts-jest': { 7 | tsConfig: '/tsconfig.spec.json', 8 | stringifyContentPathRegex: '\\.(html|svg)$', 9 | astTransformers: { 10 | before: [ 11 | 'jest-preset-angular/build/InlineFilesTransformer', 12 | 'jest-preset-angular/build/StripStylesTransformer', 13 | ], 14 | }, 15 | }, 16 | }, 17 | coverageDirectory: '../../coverage/apps/web', 18 | snapshotSerializers: [ 19 | 'jest-preset-angular/build/AngularNoNgAttributesSnapshotSerializer.js', 20 | 'jest-preset-angular/build/AngularSnapshotSerializer.js', 21 | 'jest-preset-angular/build/HTMLCommentSerializer.js', 22 | ], 23 | } 24 | -------------------------------------------------------------------------------- /libs/web/layout/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | displayName: 'web-layout', 3 | preset: '../../../jest.preset.js', 4 | setupFilesAfterEnv: ['/src/test-setup.ts'], 5 | globals: { 6 | 'ts-jest': { 7 | tsConfig: '/tsconfig.spec.json', 8 | stringifyContentPathRegex: '\\.(html|svg)$', 9 | astTransformers: { 10 | before: [ 11 | 'jest-preset-angular/build/InlineFilesTransformer', 12 | 'jest-preset-angular/build/StripStylesTransformer', 13 | ], 14 | }, 15 | }, 16 | }, 17 | coverageDirectory: '../../../coverage/libs/web/layout', 18 | snapshotSerializers: [ 19 | 'jest-preset-angular/build/AngularNoNgAttributesSnapshotSerializer.js', 20 | 'jest-preset-angular/build/AngularSnapshotSerializer.js', 21 | 'jest-preset-angular/build/HTMLCommentSerializer.js', 22 | ], 23 | } 24 | -------------------------------------------------------------------------------- /libs/web/ui-form/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | displayName: 'web-ui-form', 3 | preset: '../../../jest.preset.js', 4 | setupFilesAfterEnv: ['/src/test-setup.ts'], 5 | globals: { 6 | 'ts-jest': { 7 | tsConfig: '/tsconfig.spec.json', 8 | stringifyContentPathRegex: '\\.(html|svg)$', 9 | astTransformers: { 10 | before: [ 11 | 'jest-preset-angular/build/InlineFilesTransformer', 12 | 'jest-preset-angular/build/StripStylesTransformer', 13 | ], 14 | }, 15 | }, 16 | }, 17 | coverageDirectory: '../../../coverage/libs/web/ui-form', 18 | snapshotSerializers: [ 19 | 'jest-preset-angular/build/AngularNoNgAttributesSnapshotSerializer.js', 20 | 'jest-preset-angular/build/AngularSnapshotSerializer.js', 21 | 'jest-preset-angular/build/HTMLCommentSerializer.js', 22 | ], 23 | } 24 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "ignorePatterns": ["**/*"], 4 | "plugins": ["@nrwl/nx"], 5 | "overrides": [ 6 | { 7 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 8 | "rules": { 9 | "@nrwl/nx/enforce-module-boundaries": [ 10 | "error", 11 | { 12 | "enforceBuildableLibDependency": true, 13 | "allow": [], 14 | "depConstraints": [{ "sourceTag": "*", "onlyDependOnLibsWithTags": ["*"] }] 15 | } 16 | ] 17 | } 18 | }, 19 | { 20 | "files": ["*.ts", "*.tsx"], 21 | "extends": ["plugin:@nrwl/nx/typescript"], 22 | "parserOptions": { "project": "./tsconfig.*?.json" }, 23 | "rules": {} 24 | }, 25 | { 26 | "files": ["*.js", "*.jsx"], 27 | "extends": ["plugin:@nrwl/nx/javascript"], 28 | "rules": {} 29 | } 30 | ] 31 | } 32 | -------------------------------------------------------------------------------- /libs/web/auth/data-access/src/lib/web-auth-data-access.module.ts: -------------------------------------------------------------------------------- 1 | import { CommonModule } from '@angular/common' 2 | import { NgModule } from '@angular/core' 3 | import { RouterModule } from '@angular/router' 4 | import { EffectsModule } from '@ngrx/effects' 5 | import { StoreModule } from '@ngrx/store' 6 | import { AuthEffects } from './+state/auth/auth.effects' 7 | import * as fromAuth from './+state/auth/auth.reducer' 8 | import { WebAuthDataAccessService } from './web-auth-data-access.service' 9 | import { IsLoggedInGuard } from './guards/is-logged-in.guard' 10 | 11 | @NgModule({ 12 | imports: [ 13 | CommonModule, 14 | RouterModule, 15 | StoreModule.forFeature(fromAuth.AUTH_FEATURE_KEY, fromAuth.reducer), 16 | EffectsModule.forFeature([AuthEffects]), 17 | ], 18 | providers: [WebAuthDataAccessService, IsLoggedInGuard], 19 | }) 20 | export class WebAuthDataAccessModule {} 21 | -------------------------------------------------------------------------------- /apps/api/src/main.ts: -------------------------------------------------------------------------------- 1 | import { ApiCoreFeatureService } from '@beehive/api/core/feature' 2 | import { Logger } from '@nestjs/common' 3 | import { NestFactory } from '@nestjs/core' 4 | import * as cookieParser from 'cookie-parser' 5 | 6 | import { AppModule } from './app/app.module' 7 | 8 | async function bootstrap() { 9 | const app = await NestFactory.create(AppModule) 10 | const config = app.get(ApiCoreFeatureService) 11 | const globalPrefix = 'api' 12 | app.setGlobalPrefix(globalPrefix) 13 | app.enableCors({ 14 | credentials: true, 15 | origin: config.apiCorsOrigins, 16 | }) 17 | app.use(cookieParser()) 18 | const port = process.env.PORT || 3333 19 | await app.listen(port, () => { 20 | Logger.log('Listening at http://localhost:' + port + '/' + globalPrefix) 21 | Logger.log('Listening at http://localhost:' + port + '/graphql') 22 | }) 23 | } 24 | 25 | bootstrap() 26 | -------------------------------------------------------------------------------- /libs/api/auth/data-access/src/lib/api-auth-data-access.module.ts: -------------------------------------------------------------------------------- 1 | import { ApiCoreDataAccessModule } from '@beehive/api/core/data-access' 2 | import { ApiCoreFeatureModule } from '@beehive/api/core/feature' 3 | import { Module } from '@nestjs/common' 4 | import { JwtModule } from '@nestjs/jwt' 5 | import { PassportModule } from '@nestjs/passport' 6 | 7 | import { ApiAuthDataAccessService } from './api-auth-data-access.service' 8 | import { JwtStrategy } from './strategies/jwt.strategy' 9 | 10 | @Module({ 11 | imports: [ 12 | ApiCoreDataAccessModule, 13 | ApiCoreFeatureModule, 14 | PassportModule.register({ defaultStrategy: 'jwt' }), 15 | JwtModule.register({ 16 | secret: 'NXPM_STACK_SECRET1062508', 17 | }), 18 | ], 19 | exports: [ApiAuthDataAccessService], 20 | providers: [ApiAuthDataAccessService, JwtStrategy], 21 | }) 22 | export class ApiAuthDataAccessModule {} 23 | -------------------------------------------------------------------------------- /libs/web/about/feature/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | displayName: 'web-about-feature', 3 | preset: '../../../../jest.preset.js', 4 | setupFilesAfterEnv: ['/src/test-setup.ts'], 5 | globals: { 6 | 'ts-jest': { 7 | tsConfig: '/tsconfig.spec.json', 8 | stringifyContentPathRegex: '\\.(html|svg)$', 9 | astTransformers: { 10 | before: [ 11 | 'jest-preset-angular/build/InlineFilesTransformer', 12 | 'jest-preset-angular/build/StripStylesTransformer', 13 | ], 14 | }, 15 | }, 16 | }, 17 | coverageDirectory: '../../../../coverage/libs/web/about/feature', 18 | snapshotSerializers: [ 19 | 'jest-preset-angular/build/AngularNoNgAttributesSnapshotSerializer.js', 20 | 'jest-preset-angular/build/AngularSnapshotSerializer.js', 21 | 'jest-preset-angular/build/HTMLCommentSerializer.js', 22 | ], 23 | } 24 | -------------------------------------------------------------------------------- /libs/web/auth/feature/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | displayName: 'web-auth-feature', 3 | preset: '../../../../jest.preset.js', 4 | setupFilesAfterEnv: ['/src/test-setup.ts'], 5 | globals: { 6 | 'ts-jest': { 7 | tsConfig: '/tsconfig.spec.json', 8 | stringifyContentPathRegex: '\\.(html|svg)$', 9 | astTransformers: { 10 | before: [ 11 | 'jest-preset-angular/build/InlineFilesTransformer', 12 | 'jest-preset-angular/build/StripStylesTransformer', 13 | ], 14 | }, 15 | }, 16 | }, 17 | coverageDirectory: '../../../../coverage/libs/web/auth/feature', 18 | snapshotSerializers: [ 19 | 'jest-preset-angular/build/AngularNoNgAttributesSnapshotSerializer.js', 20 | 'jest-preset-angular/build/AngularSnapshotSerializer.js', 21 | 'jest-preset-angular/build/HTMLCommentSerializer.js', 22 | ], 23 | } 24 | -------------------------------------------------------------------------------- /libs/web/core/feature/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | displayName: 'web-core-feature', 3 | preset: '../../../../jest.preset.js', 4 | setupFilesAfterEnv: ['/src/test-setup.ts'], 5 | globals: { 6 | 'ts-jest': { 7 | tsConfig: '/tsconfig.spec.json', 8 | stringifyContentPathRegex: '\\.(html|svg)$', 9 | astTransformers: { 10 | before: [ 11 | 'jest-preset-angular/build/InlineFilesTransformer', 12 | 'jest-preset-angular/build/StripStylesTransformer', 13 | ], 14 | }, 15 | }, 16 | }, 17 | coverageDirectory: '../../../../coverage/libs/web/core/feature', 18 | snapshotSerializers: [ 19 | 'jest-preset-angular/build/AngularNoNgAttributesSnapshotSerializer.js', 20 | 'jest-preset-angular/build/AngularSnapshotSerializer.js', 21 | 'jest-preset-angular/build/HTMLCommentSerializer.js', 22 | ], 23 | } 24 | -------------------------------------------------------------------------------- /libs/web/shell/feature/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | displayName: 'web-shell-feature', 3 | preset: '../../../../jest.preset.js', 4 | setupFilesAfterEnv: ['/src/test-setup.ts'], 5 | globals: { 6 | 'ts-jest': { 7 | tsConfig: '/tsconfig.spec.json', 8 | stringifyContentPathRegex: '\\.(html|svg)$', 9 | astTransformers: { 10 | before: [ 11 | 'jest-preset-angular/build/InlineFilesTransformer', 12 | 'jest-preset-angular/build/StripStylesTransformer', 13 | ], 14 | }, 15 | }, 16 | }, 17 | coverageDirectory: '../../../../coverage/libs/web/shell/feature', 18 | snapshotSerializers: [ 19 | 'jest-preset-angular/build/AngularNoNgAttributesSnapshotSerializer.js', 20 | 'jest-preset-angular/build/AngularSnapshotSerializer.js', 21 | 'jest-preset-angular/build/HTMLCommentSerializer.js', 22 | ], 23 | } 24 | -------------------------------------------------------------------------------- /libs/web/auth/data-access/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | displayName: 'web-auth-data-access', 3 | preset: '../../../../jest.preset.js', 4 | setupFilesAfterEnv: ['/src/test-setup.ts'], 5 | globals: { 6 | 'ts-jest': { 7 | tsConfig: '/tsconfig.spec.json', 8 | stringifyContentPathRegex: '\\.(html|svg)$', 9 | astTransformers: { 10 | before: [ 11 | 'jest-preset-angular/build/InlineFilesTransformer', 12 | 'jest-preset-angular/build/StripStylesTransformer', 13 | ], 14 | }, 15 | }, 16 | }, 17 | coverageDirectory: '../../../../coverage/libs/web/auth/data-access', 18 | snapshotSerializers: [ 19 | 'jest-preset-angular/build/AngularNoNgAttributesSnapshotSerializer.js', 20 | 'jest-preset-angular/build/AngularSnapshotSerializer.js', 21 | 'jest-preset-angular/build/HTMLCommentSerializer.js', 22 | ], 23 | } 24 | -------------------------------------------------------------------------------- /libs/web/core/data-access/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | displayName: 'web-core-data-access', 3 | preset: '../../../../jest.preset.js', 4 | setupFilesAfterEnv: ['/src/test-setup.ts'], 5 | globals: { 6 | 'ts-jest': { 7 | tsConfig: '/tsconfig.spec.json', 8 | stringifyContentPathRegex: '\\.(html|svg)$', 9 | astTransformers: { 10 | before: [ 11 | 'jest-preset-angular/build/InlineFilesTransformer', 12 | 'jest-preset-angular/build/StripStylesTransformer', 13 | ], 14 | }, 15 | }, 16 | }, 17 | coverageDirectory: '../../../../coverage/libs/web/core/data-access', 18 | snapshotSerializers: [ 19 | 'jest-preset-angular/build/AngularNoNgAttributesSnapshotSerializer.js', 20 | 'jest-preset-angular/build/AngularSnapshotSerializer.js', 21 | 'jest-preset-angular/build/HTMLCommentSerializer.js', 22 | ], 23 | } 24 | -------------------------------------------------------------------------------- /libs/web/dashboard/feature/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | displayName: 'web-dashboard-feature', 3 | preset: '../../../../jest.preset.js', 4 | setupFilesAfterEnv: ['/src/test-setup.ts'], 5 | globals: { 6 | 'ts-jest': { 7 | tsConfig: '/tsconfig.spec.json', 8 | stringifyContentPathRegex: '\\.(html|svg)$', 9 | astTransformers: { 10 | before: [ 11 | 'jest-preset-angular/build/InlineFilesTransformer', 12 | 'jest-preset-angular/build/StripStylesTransformer', 13 | ], 14 | }, 15 | }, 16 | }, 17 | coverageDirectory: '../../../../coverage/libs/web/dashboard/feature', 18 | snapshotSerializers: [ 19 | 'jest-preset-angular/build/AngularNoNgAttributesSnapshotSerializer.js', 20 | 'jest-preset-angular/build/AngularSnapshotSerializer.js', 21 | 'jest-preset-angular/build/HTMLCommentSerializer.js', 22 | ], 23 | } 24 | -------------------------------------------------------------------------------- /libs/api/auth/data-access/src/lib/strategies/jwt.strategy.ts: -------------------------------------------------------------------------------- 1 | import { Injectable, UnauthorizedException } from '@nestjs/common' 2 | import { PassportStrategy } from '@nestjs/passport' 3 | import { ExtractJwt, Strategy } from 'passport-jwt' 4 | import { cookieExtractor } from '../api-auth-data-access.helper' 5 | import { ApiAuthDataAccessService } from '../api-auth-data-access.service' 6 | import { JwtDto } from '../dto/jwt.dto' 7 | 8 | @Injectable() 9 | export class JwtStrategy extends PassportStrategy(Strategy) { 10 | constructor(private readonly auth: ApiAuthDataAccessService) { 11 | super({ 12 | jwtFromRequest: cookieExtractor, 13 | secretOrKey: 'NXPM_STACK_SECRET1062508', 14 | }) 15 | } 16 | 17 | async validate(payload: JwtDto) { 18 | const user = await this.auth.validateUser(payload.userId) 19 | if (!user) { 20 | throw new UnauthorizedException() 21 | } 22 | return user 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /apps/web-e2e/src/plugins/index.js: -------------------------------------------------------------------------------- 1 | // *********************************************************** 2 | // This example plugins/index.js can be used to load plugins 3 | // 4 | // You can change the location of this file or turn off loading 5 | // the plugins file with the 'pluginsFile' configuration option. 6 | // 7 | // You can read more here: 8 | // https://on.cypress.io/plugins-guide 9 | // *********************************************************** 10 | 11 | // This function is called when a project is opened or re-opened (e.g. due to 12 | // the project's config changing) 13 | 14 | const { preprocessTypescript } = require('@nrwl/cypress/plugins/preprocessor') 15 | 16 | module.exports = (on, config) => { 17 | // `on` is used to hook into various events Cypress emits 18 | // `config` is the resolved Cypress config 19 | 20 | // Preprocess Typescript file using Nx helper 21 | on('file:preprocessor', preprocessTypescript(config)) 22 | } 23 | -------------------------------------------------------------------------------- /libs/api/auth/data-access/src/lib/models/user.ts: -------------------------------------------------------------------------------- 1 | import { Field, ObjectType } from '@nestjs/graphql' 2 | import { Role } from './role' 3 | 4 | @ObjectType() 5 | export class User { 6 | @Field({ nullable: true }) 7 | id: string 8 | 9 | @Field({ nullable: true }) 10 | createdAt: Date 11 | 12 | @Field({ nullable: true }) 13 | updatedAt: Date 14 | 15 | @Field({ nullable: true }) 16 | email: string 17 | 18 | @Field({ nullable: true }) 19 | phone: string 20 | 21 | @Field({ nullable: true }) 22 | username?: string 23 | 24 | @Field({ nullable: true }) 25 | firstName?: string 26 | 27 | @Field({ nullable: true }) 28 | lastName?: string 29 | 30 | @Field({ nullable: true }) 31 | avatarUrl?: string 32 | 33 | @Field({ nullable: true }) 34 | location?: string 35 | 36 | @Field({ nullable: true }) 37 | bio?: string 38 | 39 | @Field(() => Role, { nullable: true }) 40 | role: Role 41 | 42 | password?: string 43 | } 44 | -------------------------------------------------------------------------------- /libs/web/auth/data-access/src/lib/+state/auth/auth.reducer.spec.ts: -------------------------------------------------------------------------------- 1 | import * as AuthActions from './auth.actions' 2 | import { initialState, reducer, State } from './auth.reducer' 3 | 4 | describe('Auth Reducer', () => { 5 | beforeEach(() => {}) 6 | 7 | describe('valid Auth actions', () => { 8 | it('loginSuccess should set the user and token', () => { 9 | const action = AuthActions.loginSuccess({ 10 | data: { user: { id: 'test' }, token: 'test-token' }, 11 | }) 12 | 13 | const result: State = reducer(initialState, action) 14 | 15 | expect(result.token).toEqual('test-token') 16 | expect(result.user.id).toBe('test') 17 | }) 18 | }) 19 | 20 | describe('unknown action', () => { 21 | it('should return the previous state', () => { 22 | const action = {} as any 23 | 24 | const result = reducer(initialState, action) 25 | 26 | expect(result).toBe(initialState) 27 | }) 28 | }) 29 | }) 30 | -------------------------------------------------------------------------------- /libs/web/ui-form/src/lib/web-ui-form.validators.ts: -------------------------------------------------------------------------------- 1 | import { Validators, FormControl, ValidationErrors } from '@angular/forms' 2 | 3 | export function minlengthValidationMessage(err, field) { 4 | return `Should have at least ${field.templateOptions.minLength} characters` 5 | } 6 | 7 | export function maxlengthValidationMessage(err, field) { 8 | return `This value should be less than ${field.templateOptions.maxLength} characters` 9 | } 10 | 11 | export function minValidationMessage(err, field) { 12 | return `This value should be more than ${field.templateOptions.min}` 13 | } 14 | 15 | export function maxValidationMessage(err, field) { 16 | return `This value should be less than ${field.templateOptions.max}` 17 | } 18 | 19 | export function emailValidatorMessage(err, field) { 20 | return `"${field.formControl.value}" is not a valid email address` 21 | } 22 | 23 | export function emailValidator(control: FormControl): ValidationErrors { 24 | return Validators.email(control) 25 | } 26 | -------------------------------------------------------------------------------- /libs/web/core/feature/src/lib/web-core-feature.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core' 2 | import { HttpClientModule } from '@angular/common/http' 3 | 4 | import { WebCoreFeatureGraphQLModule } from './web-core-feature-graphql.module' 5 | import { StoreModule } from '@ngrx/store' 6 | import { EffectsModule } from '@ngrx/effects' 7 | import { StoreDevtoolsModule } from '@ngrx/store-devtools' 8 | import { environment } from '../environments/environment' 9 | 10 | @NgModule({ 11 | imports: [ 12 | HttpClientModule, 13 | WebCoreFeatureGraphQLModule, 14 | StoreModule.forRoot( 15 | {}, 16 | { 17 | metaReducers: !environment.production ? [] : [], 18 | runtimeChecks: { 19 | strictActionImmutability: true, 20 | strictStateImmutability: true, 21 | }, 22 | }, 23 | ), 24 | EffectsModule.forRoot([]), 25 | !environment.production ? StoreDevtoolsModule.instrument() : [], 26 | ], 27 | }) 28 | export class WebCoreFeatureModule {} 29 | -------------------------------------------------------------------------------- /.github/workflows/build-test.yml: -------------------------------------------------------------------------------- 1 | name: build-test 2 | 3 | on: 4 | pull_request: 5 | paths-ignore: 6 | - '**.md' 7 | push: 8 | branches: 9 | - main 10 | paths-ignore: 11 | - '**.md' 12 | 13 | env: 14 | NX_BRANCH: ${{ github.event.number }} 15 | NX_RUN_GROUP: ${{ github.run_id }} 16 | 17 | jobs: 18 | build: 19 | runs-on: ${{ matrix.operating-system }} 20 | strategy: 21 | matrix: 22 | node-version: [14.x] 23 | operating-system: [ubuntu-latest] 24 | steps: 25 | - uses: actions/checkout@v2 26 | - uses: actions/cache@v2 27 | with: 28 | path: '**/node_modules' 29 | key: ${{ runner.os }}-modules-${{ hashFiles('**/yarn.lock') }} 30 | - name: Setup node ${{ matrix.node-version }} 31 | uses: actions/setup-node@v1 32 | with: 33 | node-version: ${{ matrix.node-version }} 34 | - run: yarn install --frozen-lockfile 35 | - run: yarn build 36 | - run: yarn format:check 37 | - run: yarn test:ci 38 | -------------------------------------------------------------------------------- /apps/web-e2e/src/support/commands.ts: -------------------------------------------------------------------------------- 1 | // *********************************************** 2 | // This example commands.js shows you how to 3 | // create various custom commands and overwrite 4 | // existing commands. 5 | // 6 | // For more comprehensive examples of custom 7 | // commands please read more here: 8 | // https://on.cypress.io/custom-commands 9 | // *********************************************** 10 | 11 | declare namespace Cypress { 12 | interface Chainable { 13 | login(email: string, password: string): void 14 | } 15 | } 16 | // 17 | // -- This is a parent command -- 18 | Cypress.Commands.add('login', (email, password) => { 19 | console.log('Custom command example: Login', email, password) 20 | }) 21 | // 22 | // -- This is a child command -- 23 | // Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... }) 24 | // 25 | // 26 | // -- This is a dual command -- 27 | // Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... }) 28 | // 29 | // 30 | // -- This will overwrite an existing command -- 31 | // Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) 32 | -------------------------------------------------------------------------------- /libs/web/dashboard/feature/src/lib/web-dashboard-feature.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core' 2 | import { CommonModule } from '@angular/common' 3 | import { RouterModule } from '@angular/router' 4 | import { WebCoreDataAccessModule } from '@beehive/web/core/data-access' 5 | 6 | import { WebSettingsFeatureComponent } from './settings/web-settings-feature.component' 7 | import { WebPostsFeatureComponent } from './posts/web-posts-feature.component' 8 | import { WebMessagesFeatureComponent } from './messages/web-messages-feature.component' 9 | 10 | @NgModule({ 11 | declarations: [WebSettingsFeatureComponent, WebPostsFeatureComponent, WebMessagesFeatureComponent], 12 | imports: [ 13 | CommonModule, 14 | WebCoreDataAccessModule, 15 | RouterModule.forChild([ 16 | { path: '', pathMatch: 'full', redirectTo: 'posts' }, 17 | { path: 'posts', pathMatch: 'full', component: WebPostsFeatureComponent }, 18 | { path: 'messages', pathMatch: 'full', component: WebMessagesFeatureComponent }, 19 | { path: 'settings', pathMatch: 'full', component: WebSettingsFeatureComponent }, 20 | ]), 21 | ], 22 | }) 23 | export class WebDashboardFeatureModule {} 24 | -------------------------------------------------------------------------------- /libs/web/auth/data-access/src/lib/+state/auth/auth.actions.ts: -------------------------------------------------------------------------------- 1 | import { createAction, props } from '@ngrx/store' 2 | import { LoginInput, RegisterInput, User } from '@beehive/web/core/data-access' 3 | 4 | export const ensureLogin = createAction('[Auth] EnsureLogin') 5 | 6 | export const login = createAction('[Auth] Login', props<{ input: LoginInput }>()) 7 | 8 | export const loginFailure = createAction('[Auth] Login Failure', props<{ error: any }>()) 9 | 10 | export const loginSuccess = createAction('[Auth] Login Success', props<{ user: User }>()) 11 | 12 | export const logout = createAction('[Auth] Logout') 13 | 14 | export const logoutFailure = createAction('[Auth] Logout Failure', props<{ error: any }>()) 15 | 16 | export const logoutSuccess = createAction('[Auth] Logout Success') 17 | 18 | export const redirectToLogin = createAction('[Auth] RedirectToLogin', props<{ url?: string }>()) 19 | 20 | export const register = createAction('[Auth] Register', props<{ input: RegisterInput }>()) 21 | 22 | export const registerFailure = createAction('[Auth] Register Failure', props<{ error: any }>()) 23 | 24 | export const registerSuccess = createAction('[Auth] Register Success', props<{ user: User }>()) 25 | -------------------------------------------------------------------------------- /libs/web/core/data-access/src/lib/web-core-data-access.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core' 2 | import { Observable } from 'rxjs' 3 | import { map } from 'rxjs/operators' 4 | import { ApolloAngularSDK, IntercomMessage } from '../generated/graphql' 5 | 6 | @Injectable() 7 | export class WebCoreDataAccessService { 8 | constructor(public readonly sdk: ApolloAngularSDK) {} 9 | 10 | public uptime(): Observable { 11 | return this.sdk.uptime(null, { fetchPolicy: 'network-only' }).pipe(map((res) => res?.data?.uptime)) 12 | } 13 | 14 | public uptimeWatch(): Observable { 15 | return this.sdk.uptimeWatch(null, { pollInterval: 1000 }).valueChanges.pipe(map((res) => res?.data?.uptime)) 16 | } 17 | 18 | public intercomPub(type: string, scope: string, payload: any): Observable { 19 | return this.sdk.intercomPub({ type, scope, payload }).pipe(map((res) => res?.data?.intercomPub)) 20 | } 21 | 22 | public intercomSub(): Observable { 23 | return this.sdk.intercomSub().pipe(map((res) => res?.data?.intercomSub)) 24 | } 25 | 26 | public me() { 27 | return this.sdk.me().pipe(map((res) => res?.data?.me)) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /apps/api-e2e/src/integration/core.spec.ts: -------------------------------------------------------------------------------- 1 | import { AppModule } from '@beehive/api-app-module' 2 | import { Test, TestingModule } from '@nestjs/testing' 3 | import { INestApplication } from '@nestjs/common' 4 | import * as request from 'supertest' 5 | 6 | describe('CoreModule (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('/graphql (POST)', () => { 19 | return request(app.getHttpServer()) 20 | .post('/graphql') 21 | .send({ query: `query { uptime }` }) 22 | .expect(200) 23 | .expect((res) => { 24 | const body = res.body 25 | 26 | if (!body.data) { 27 | throw Error(`Data prop not found`) 28 | } 29 | 30 | if (!body.data.uptime) { 31 | throw Error(`Data prop not found`) 32 | } 33 | 34 | if (typeof body.data.uptime !== 'number') { 35 | throw Error(`Uptime not a number`) 36 | } 37 | return true 38 | }) 39 | }) 40 | }) 41 | -------------------------------------------------------------------------------- /libs/api/auth/data-access/src/lib/guards/gql-auth-web.guard.ts: -------------------------------------------------------------------------------- 1 | import { ExecutionContext, ForbiddenException, Injectable } from '@nestjs/common' 2 | import { GqlExecutionContext } from '@nestjs/graphql' 3 | import { AuthGuard } from '@nestjs/passport' 4 | 5 | @Injectable() 6 | export class GqlAuthWebGuard extends AuthGuard('jwt') { 7 | private readonly _roles: string[] = ['Web'] 8 | 9 | getRequest(context: ExecutionContext) { 10 | const ctx = GqlExecutionContext.create(context) 11 | 12 | return ctx.getContext().req 13 | } 14 | 15 | constructor() { 16 | super() 17 | } 18 | 19 | async canActivate(context: ExecutionContext): Promise { 20 | await super.canActivate(context) 21 | const ctx = GqlExecutionContext.create(context) 22 | const req = ctx.getContext().req 23 | 24 | if (!req || !req.user) { 25 | return false 26 | } 27 | const hasAccess = this.hasAccess(req.user) 28 | 29 | if (!hasAccess) { 30 | throw new ForbiddenException(`You need to have Web access`) 31 | } 32 | return req && req.user && this.hasAccess(req.user) 33 | } 34 | 35 | private hasAccess(user): boolean { 36 | return user.role && this._roles.includes(user.role) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /libs/web/auth/feature/src/lib/register/register.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core' 2 | import { FormGroup } from '@angular/forms' 3 | import { Store } from '@ngrx/store' 4 | import { register } from '@beehive/web/auth/data-access' 5 | import { WebUiFormField } from '@beehive/web/ui-form' 6 | 7 | @Component({ 8 | template: ` 9 | 10 | Log in 11 | 12 | `, 13 | }) 14 | export class RegisterComponent { 15 | form = new FormGroup({}) 16 | fields = [ 17 | WebUiFormField.email('email', { label: 'Email', required: true }, { focus: true }), 18 | WebUiFormField.password('password', { label: 'Password', required: true }), 19 | WebUiFormField.input('username', { label: 'Username', required: false }), 20 | WebUiFormField.input('firstName', { label: 'First name', required: false }), 21 | WebUiFormField.input('lastName', { label: 'Last name', required: false }), 22 | ] 23 | 24 | constructor(private readonly store: Store) {} 25 | 26 | public submit(input) { 27 | this.store.dispatch(register({ input })) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /libs/web/auth/data-access/src/lib/+state/auth/auth.effects.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, async } from '@angular/core/testing' 2 | 3 | import { Observable } from 'rxjs' 4 | 5 | import { provideMockActions } from '@ngrx/effects/testing' 6 | import { provideMockStore } from '@ngrx/store/testing' 7 | 8 | import { NxModule, DataPersistence } from '@nrwl/angular' 9 | import { hot } from '@nrwl/angular/testing' 10 | 11 | import { AuthEffects } from './auth.effects' 12 | import * as AuthActions from './auth.actions' 13 | 14 | describe('AuthEffects', () => { 15 | let actions: Observable 16 | let effects: AuthEffects 17 | 18 | beforeEach(() => { 19 | TestBed.configureTestingModule({ 20 | imports: [NxModule.forRoot()], 21 | providers: [AuthEffects, DataPersistence, provideMockActions(() => actions), provideMockStore()], 22 | }) 23 | 24 | effects = TestBed.get(AuthEffects) 25 | }) 26 | 27 | describe('loadAuth$', () => { 28 | it('should work', () => { 29 | actions = hot('-a-|', { a: AuthActions.loadAuth() }) 30 | 31 | const expected = hot('-a-|', { 32 | a: AuthActions.loadAuthSuccess({ auth: [] }), 33 | }) 34 | 35 | expect(effects.loadAuth$).toBeObservable(expected) 36 | }) 37 | }) 38 | }) 39 | -------------------------------------------------------------------------------- /libs/web/auth/data-access/src/lib/+state/auth/auth.reducer.ts: -------------------------------------------------------------------------------- 1 | import { Action, createReducer, on } from '@ngrx/store' 2 | import { User } from '@beehive/web/core/data-access' 3 | 4 | import * as AuthActions from './auth.actions' 5 | 6 | export const AUTH_FEATURE_KEY = 'auth' 7 | 8 | export interface State { 9 | user?: User 10 | error?: string 11 | } 12 | 13 | export interface AuthPartialState { 14 | readonly [AUTH_FEATURE_KEY]: State 15 | } 16 | 17 | export const initialState: State = {} 18 | 19 | const authReducer = createReducer( 20 | initialState, 21 | on(AuthActions.loginSuccess, (state, { user }) => ({ 22 | ...state, 23 | user: user, 24 | })), 25 | on(AuthActions.loginFailure, (state, { error }) => ({ ...state, error })), 26 | on(AuthActions.registerSuccess, (state, { user }) => ({ 27 | ...state, 28 | user: user, 29 | })), 30 | on(AuthActions.registerFailure, (state, { error }) => ({ ...state, error })), 31 | on(AuthActions.logoutFailure, (state, { error }) => ({ ...state, error })), 32 | on(AuthActions.logoutSuccess, (state) => ({ 33 | ...state, 34 | user: null, 35 | error: null, 36 | })), 37 | ) 38 | 39 | export function reducer(state: State | undefined, action: Action) { 40 | return authReducer(state, action) 41 | } 42 | -------------------------------------------------------------------------------- /libs/web/auth/data-access/src/lib/guards/is-logged-in.guard.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core' 2 | import { CanActivate, UrlTree } from '@angular/router' 3 | import { Store } from '@ngrx/store' 4 | import { Observable } from 'rxjs' 5 | import { filter, switchMap, take, tap } from 'rxjs/operators' 6 | import { ensureLogin } from '../+state/auth/auth.actions' 7 | import { isLoggedIn } from '../+state/auth/auth.selectors' 8 | 9 | @Injectable() 10 | export class IsLoggedInGuard implements CanActivate { 11 | constructor(private readonly store: Store) {} 12 | 13 | ensureLogin(): Observable { 14 | return this.store.select(isLoggedIn).pipe( 15 | tap((loggedIn) => { 16 | if (!loggedIn) { 17 | this.store.dispatch(ensureLogin()) 18 | } 19 | }), 20 | filter((loggedIn) => !loggedIn), 21 | take(1), 22 | ) 23 | } 24 | 25 | isLoggedIn(): Observable { 26 | return this.store.select(isLoggedIn).pipe( 27 | filter((loggedIn) => { 28 | return !!loggedIn 29 | }), 30 | take(1), 31 | ) 32 | } 33 | 34 | canActivate(): Observable | Promise | boolean | UrlTree { 35 | return this.ensureLogin().pipe(switchMap(() => this.isLoggedIn())) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /libs/web/auth/data-access/src/lib/+state/auth/auth.selectors.spec.ts: -------------------------------------------------------------------------------- 1 | import * as AuthSelectors from './auth.selectors' 2 | 3 | describe('Auth Selectors', () => { 4 | const ERROR_MSG = 'No Error Available' 5 | const getAuthId = (it) => it['id'] 6 | 7 | let state 8 | 9 | beforeEach(() => { 10 | state = { 11 | auth: {}, 12 | } 13 | }) 14 | 15 | describe('Auth Selectors', () => { 16 | it('getAllAuth() should return the list of Auth', () => { 17 | const results = AuthSelectors.getAllAuth(state) 18 | const selId = getAuthId(results[1]) 19 | 20 | expect(results.length).toBe(3) 21 | expect(selId).toBe('PRODUCT-BBB') 22 | }) 23 | 24 | it('getSelected() should return the selected Entity', () => { 25 | const result = AuthSelectors.getSelected(state) 26 | const selId = getAuthId(result) 27 | 28 | expect(selId).toBe('PRODUCT-BBB') 29 | }) 30 | 31 | it("getAuthLoaded() should return the current 'loaded' status", () => { 32 | const result = AuthSelectors.getAuthLoaded(state) 33 | 34 | expect(result).toBe(true) 35 | }) 36 | 37 | it("getAuthError() should return the current 'error' state", () => { 38 | const result = AuthSelectors.getAuthError(state) 39 | 40 | expect(result).toBe(ERROR_MSG) 41 | }) 42 | }) 43 | }) 44 | -------------------------------------------------------------------------------- /libs/web/ui-form/src/lib/web-ui-form.component.ts: -------------------------------------------------------------------------------- 1 | import { ChangeDetectionStrategy, Component, EventEmitter, Input, OnInit, Output } from '@angular/core' 2 | import { FormGroup } from '@angular/forms' 3 | import { FormlyFieldConfig, FormlyFormBuilder, FormlyFormOptions } from '@ngx-formly/core' 4 | 5 | @Component({ 6 | selector: 'web-ui-form', 7 | template: ` 8 |
9 |
10 | 11 | 12 |
13 |
14 | `, 15 | changeDetection: ChangeDetectionStrategy.OnPush, 16 | }) 17 | export class WebUiFormComponent implements OnInit { 18 | @Input() fields: FormlyFieldConfig[] = [] 19 | @Input() form = new FormGroup({}) 20 | @Input() model: Record = {} 21 | @Input() options: FormlyFormOptions 22 | @Output() action = new EventEmitter() 23 | 24 | constructor(private builder: FormlyFormBuilder) {} 25 | 26 | ngOnInit(): void { 27 | this.builder.buildForm(this.form, this.fields, this.model, this.options) 28 | } 29 | 30 | submit() { 31 | this.action.emit({ 32 | type: 'SUBMIT', 33 | payload: this.model, 34 | }) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /libs/web/shell/feature/src/lib/web-shell-feature.module.ts: -------------------------------------------------------------------------------- 1 | import { CommonModule } from '@angular/common' 2 | import { NgModule } from '@angular/core' 3 | import { RouterModule, Routes } from '@angular/router' 4 | import { WebAuthDataAccessModule, IsLoggedInGuard } from '@beehive/web/auth/data-access' 5 | import { WebCoreDataAccessModule } from '@beehive/web/core/data-access' 6 | import { WebLayoutComponent } from '@beehive/web/layout' 7 | 8 | const routes: Routes = [ 9 | { 10 | path: '', 11 | component: WebLayoutComponent, 12 | canActivate: [IsLoggedInGuard], 13 | children: [ 14 | { 15 | path: '', 16 | loadChildren: () => import('@beehive/web/dashboard/feature').then((m) => m.WebDashboardFeatureModule), 17 | }, 18 | { 19 | path: 'about', 20 | loadChildren: () => import('@beehive/web/about/feature').then((m) => m.WebAboutFeatureModule), 21 | }, 22 | ], 23 | }, 24 | { 25 | path: 'not-found', 26 | loadChildren: () => import('./not-found/not-found.module').then((m) => m.NotFoundModule), 27 | }, 28 | { 29 | path: '', 30 | loadChildren: () => import('@beehive/web/auth/feature').then((m) => m.WebAuthFeatureModule), 31 | }, 32 | { path: '**', redirectTo: '/not-found' }, 33 | ] 34 | 35 | @NgModule({ 36 | imports: [CommonModule, RouterModule.forRoot(routes), WebCoreDataAccessModule, WebAuthDataAccessModule], 37 | }) 38 | export class WebShellFeatureModule {} 39 | -------------------------------------------------------------------------------- /libs/api/core/feature/src/lib/api-core-feature.module.ts: -------------------------------------------------------------------------------- 1 | import { GraphQLIntercomModule } from '@kikstart-playground/graphql-intercom' 2 | import { Module } from '@nestjs/common' 3 | import { ConfigModule } from '@nestjs/config' 4 | import { GraphQLModule } from '@nestjs/graphql' 5 | import { PubSub } from 'graphql-subscriptions' 6 | import { join } from 'path' 7 | 8 | import { configuration } from './config/configuration' 9 | import { validationSchema } from './config/validation' 10 | import { ApiCoreFeatureController } from './api-core-feature.controller' 11 | import { ApiCoreFeatureResolver } from './api-core-feature.resolver' 12 | import { ApiCoreFeatureService } from './api-core-feature.service' 13 | 14 | @Module({ 15 | imports: [ 16 | ConfigModule.forRoot({ 17 | isGlobal: true, 18 | load: [configuration], 19 | validationSchema, 20 | }), 21 | GraphQLModule.forRoot({ 22 | autoSchemaFile: join(process.cwd(), 'api-schema.graphql'), 23 | context: ({ req, res }) => ({ req, res }), 24 | installSubscriptionHandlers: true, 25 | playground: { 26 | settings: { 27 | 'request.credentials': 'include', 28 | }, 29 | }, 30 | sortSchema: true, 31 | }), 32 | GraphQLIntercomModule.forRoot({ pubSub: new PubSub() }), 33 | ], 34 | controllers: [ApiCoreFeatureController], 35 | providers: [ApiCoreFeatureResolver, ApiCoreFeatureService], 36 | exports: [ApiCoreFeatureService], 37 | }) 38 | export class ApiCoreFeatureModule {} 39 | -------------------------------------------------------------------------------- /libs/api/auth/feature/src/lib/api-auth-feature.resolver.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ApiAuthDataAccessService, 3 | CtxUser, 4 | GqlAuthGuard, 5 | LoginInput, 6 | RegisterInput, 7 | User, 8 | UserToken, 9 | } from '@beehive/api/auth/data-access' 10 | import { Float, Context, Query, Resolver, Mutation, Args, ResolveField, Parent } from '@nestjs/graphql' 11 | import { UseGuards } from '@nestjs/common' 12 | 13 | @Resolver(() => UserToken) 14 | export class ApiAuthFeatureResolver { 15 | constructor(private readonly service: ApiAuthDataAccessService) {} 16 | 17 | @Query(() => User, { nullable: true }) 18 | @UseGuards(GqlAuthGuard) 19 | async me(@CtxUser() user: User) { 20 | return user 21 | } 22 | 23 | @Mutation(() => UserToken, { nullable: true }) 24 | async login(@Context() context, @Args('input') input: LoginInput) { 25 | const userToken = await this.service.login(input) 26 | this.service.setCookie(context.res, userToken.token) 27 | return userToken 28 | } 29 | 30 | @Mutation(() => Boolean, { nullable: true }) 31 | async logout(@Context() context) { 32 | this.service.clearCookie(context.res) 33 | return true 34 | } 35 | 36 | @Mutation(() => UserToken, { nullable: true }) 37 | async register(@Context() context, @Args('input') input: RegisterInput) { 38 | const userToken = await this.service.register(input) 39 | this.service.setCookie(context.res, userToken.token) 40 | return userToken 41 | } 42 | 43 | @ResolveField('user') 44 | user(@Parent() auth: UserToken) { 45 | return this.service.getUserFromToken(auth.token) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /libs/web/dashboard/feature/src/lib/settings/web-settings-feature.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core' 2 | 3 | @Component({ 4 | templateUrl: './web-settings-feature.component.html', 5 | }) 6 | export class WebSettingsFeatureComponent { 7 | menu = [ 8 | { label: 'Your account', path: '' }, 9 | { label: 'Security and account access', path: 'security' }, 10 | { label: 'Privacy and Safety', path: 'privacy' }, 11 | { label: 'Notifications', path: 'notifications' }, 12 | { label: 'Accessibility, display, and languages', path: 'accessibility' }, 13 | { label: 'Additional Resources', path: 'resources' }, 14 | ] 15 | 16 | description = 17 | 'See information about your account, download an archive of your data, or learn about your account deactivation options' 18 | options = [ 19 | { 20 | path: 'n/e', 21 | label: 'Account information', 22 | description: 'See your account information like your phone number and email address.', 23 | }, 24 | { path: 'n/e', label: 'Change your password', description: 'Change your password at any time.' }, 25 | { 26 | path: 'n/e', 27 | label: 'Download an archive of your data', 28 | description: 'Get insights into the type of information stored for your account.', 29 | }, 30 | { 31 | path: 'n/e', 32 | label: 'TweetDeck’s Team', 33 | description: 'Invite anyone to Tweet from this account using TweetDeck’s Teams.', 34 | }, 35 | { path: 'n/e', label: 'Deactivate your account', description: 'Find out how you can deactivate your account.' }, 36 | ] 37 | } 38 | -------------------------------------------------------------------------------- /libs/web/auth/feature/src/lib/login/login.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core' 2 | import { FormGroup } from '@angular/forms' 3 | import { Router } from '@angular/router' 4 | import { Store } from '@ngrx/store' 5 | import { getAuthError, getAuthUser, login } from '@beehive/web/auth/data-access' 6 | import { WebUiFormField } from '@beehive/web/ui-form' 7 | import { filter, take } from 'rxjs/operators' 8 | 9 | @Component({ 10 | template: ` 11 | 20 |
21 | {{ error }} 22 |
23 | Register 24 |
25 | `, 26 | }) 27 | export class LoginComponent { 28 | getAuthError = this.store.select(getAuthError) 29 | getAuthUser = this.store.select(getAuthUser) 30 | form = new FormGroup({}) 31 | model = {} 32 | fields = [ 33 | WebUiFormField.email('email', { label: 'Email', required: true }, { focus: true }), 34 | WebUiFormField.password('password', { label: 'Password', required: true }), 35 | ] 36 | constructor(private readonly store: Store, private readonly router: Router) { 37 | this.getAuthUser 38 | .pipe( 39 | filter((user) => !!user), 40 | take(1), 41 | ) 42 | .subscribe(() => this.router.navigate(['/'])) 43 | } 44 | 45 | public submit(input) { 46 | this.store.dispatch(login({ input })) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /libs/api/auth/data-access/src/lib/api-auth-data-access.helper.ts: -------------------------------------------------------------------------------- 1 | import { compareSync, hashSync } from 'bcryptjs' 2 | import { createHash } from 'crypto' 3 | import { Request } from 'express' 4 | 5 | const getHash = (str) => createHash('md5').update(str).digest('hex') 6 | 7 | const gravatarUrl = 'https://www.gravatar.com/avatar/' 8 | const gravatarSize = 460 9 | 10 | export const getGravatarUrl = (email = '') => `${gravatarUrl}${getHash(email)}?s=${gravatarSize}&d=mp` 11 | 12 | export function validatePassword(password: string, hashedPassword: string): boolean { 13 | return compareSync(password, hashedPassword) 14 | } 15 | 16 | export function hashPassword(password: string): string { 17 | return hashSync(password, 10) 18 | } 19 | 20 | export function generateMd5Hash(input: string) { 21 | return createHash('md5').update(input).digest('hex') 22 | } 23 | 24 | export function generateToken() { 25 | return generateMd5Hash(randomId(24)) 26 | } 27 | 28 | export function generateExpireDate(days = 1) { 29 | return new Date(Date.now() + 60 * 60 * 24 * 1000 * days) 30 | } 31 | 32 | export function randomId(length = 8) { 33 | return new Date().getTime().toString().substr(0, 8) 34 | } 35 | 36 | export function rand(items) { 37 | return items[Math.floor(Math.random() * items.length)] 38 | } 39 | 40 | export function uniqueSuffix(input, length = 5) { 41 | const suffix = generateMd5Hash(Date.now() + input).slice(0, length) 42 | return `${input}-${suffix}` 43 | } 44 | 45 | export function cookieExtractor(req: Request) { 46 | const name = process.env.API_COOKIE_NAME || '__session' 47 | return req?.cookies?.[name] ? req.cookies[name] : undefined 48 | } 49 | -------------------------------------------------------------------------------- /libs/web/core/feature/src/lib/web-core-feature-graphql.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core' 2 | import { ApolloClientOptions, InMemoryCache, split } from '@apollo/client/core' 3 | import { WebSocketLink } from '@apollo/client/link/ws' 4 | import { getMainDefinition } from '@apollo/client/utilities' 5 | import { APOLLO_OPTIONS } from 'apollo-angular' 6 | import { HttpLink } from 'apollo-angular/http' 7 | 8 | import { environment } from '../environments/environment' 9 | 10 | function httpToWs(path: string): string { 11 | return [ 12 | // Replace 'http*' with 'ws*' 13 | location.protocol.replace('http', 'ws'), 14 | // Get the current hostname 15 | `//${location.hostname}`, 16 | // Get the current port 17 | `:${location.port}`, 18 | // Add the path 19 | path, 20 | ].join('') 21 | } 22 | 23 | export function createApollo(httpLink: HttpLink): ApolloClientOptions { 24 | const http = httpLink.create({ uri: environment.graphql }) 25 | const ws = new WebSocketLink({ 26 | uri: httpToWs(environment.graphql), 27 | options: { 28 | reconnect: true, 29 | }, 30 | }) 31 | const link = split( 32 | ({ query }) => { 33 | const { kind, operation }: any = getMainDefinition(query) 34 | return kind === 'OperationDefinition' && operation === 'subscription' 35 | }, 36 | ws, 37 | http, 38 | ) 39 | return { 40 | link, 41 | cache: new InMemoryCache(), 42 | } 43 | } 44 | 45 | @NgModule({ 46 | providers: [ 47 | { 48 | provide: APOLLO_OPTIONS, 49 | useFactory: createApollo, 50 | deps: [HttpLink], 51 | }, 52 | ], 53 | }) 54 | export class WebCoreFeatureGraphQLModule {} 55 | -------------------------------------------------------------------------------- /tsconfig.base.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "rootDir": ".", 5 | "sourceMap": true, 6 | "declaration": false, 7 | "moduleResolution": "node", 8 | "emitDecoratorMetadata": true, 9 | "experimentalDecorators": true, 10 | "importHelpers": true, 11 | "target": "es2015", 12 | "module": "esnext", 13 | "lib": ["es2017", "dom"], 14 | "skipLibCheck": true, 15 | "skipDefaultLibCheck": true, 16 | "baseUrl": ".", 17 | "paths": { 18 | "@beehive/api-app-module": ["apps/api/src/app/app.module.ts"], 19 | "@beehive/api/auth/data-access": ["libs/api/auth/data-access/src/index.ts"], 20 | "@beehive/api/auth/feature": ["libs/api/auth/feature/src/index.ts"], 21 | "@beehive/api/core/data-access": ["libs/api/core/data-access/src/index.ts"], 22 | "@beehive/api/core/feature": ["libs/api/core/feature/src/index.ts"], 23 | "@beehive/web/about/feature": ["libs/web/about/feature/src/index.ts"], 24 | "@beehive/web/assets": ["libs/web/assets/src/index.ts"], 25 | "@beehive/web/auth/data-access": ["libs/web/auth/data-access/src/index.ts"], 26 | "@beehive/web/auth/feature": ["libs/web/auth/feature/src/index.ts"], 27 | "@beehive/web/core/data-access": ["libs/web/core/data-access/src/index.ts"], 28 | "@beehive/web/core/feature": ["libs/web/core/feature/src/index.ts"], 29 | "@beehive/web/dashboard/feature": ["libs/web/dashboard/feature/src/index.ts"], 30 | "@beehive/web/layout": ["libs/web/layout/src/index.ts"], 31 | "@beehive/web/shell/feature": ["libs/web/shell/feature/src/index.ts"], 32 | "@beehive/web/style": ["libs/web/style/src/index.ts"], 33 | "@beehive/web/ui-form": ["libs/web/ui-form/src/index.ts"] 34 | } 35 | }, 36 | "exclude": ["node_modules", "tmp"] 37 | } 38 | -------------------------------------------------------------------------------- /api-schema.graphql: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------ 2 | # THIS FILE WAS AUTOMATICALLY GENERATED (DO NOT MODIFY) 3 | # ------------------------------------------------------ 4 | 5 | """ 6 | A date-time string at UTC, such as 2019-12-03T09:54:33Z, compliant with the date-time format. 7 | """ 8 | scalar DateTime 9 | 10 | type IntercomMessage { 11 | payload: JSON 12 | scope: String 13 | type: String 14 | } 15 | 16 | """ 17 | The `JSON` scalar type represents JSON values as specified by [ECMA-404](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf). 18 | """ 19 | scalar JSON @specifiedBy(url: "http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf") 20 | 21 | input LoginInput { 22 | email: String! 23 | password: String! 24 | } 25 | 26 | type Mutation { 27 | intercomPub(payload: JSON, scope: String, type: String!): IntercomMessage 28 | login(input: LoginInput!): UserToken 29 | logout: Boolean 30 | register(input: RegisterInput!): UserToken 31 | } 32 | 33 | type Query { 34 | me: User 35 | uptime: Float 36 | } 37 | 38 | input RegisterInput { 39 | avatarUrl: String 40 | email: String! 41 | firstName: String 42 | lastName: String 43 | password: String! 44 | phone: String 45 | username: String 46 | } 47 | 48 | """User role""" 49 | enum Role { 50 | User 51 | Web 52 | } 53 | 54 | type Subscription { 55 | intercomSub(scope: String, type: String): IntercomMessage 56 | } 57 | 58 | type User { 59 | avatarUrl: String 60 | bio: String 61 | createdAt: DateTime 62 | email: String 63 | firstName: String 64 | id: String 65 | lastName: String 66 | location: String 67 | phone: String 68 | role: Role 69 | updatedAt: DateTime 70 | username: String 71 | } 72 | 73 | type UserToken { 74 | """JWT Bearer token""" 75 | token: String! 76 | user: User! 77 | } 78 | -------------------------------------------------------------------------------- /libs/api/core/data-access/src/lib/api-core-data-access.service.ts: -------------------------------------------------------------------------------- 1 | import { BadRequestException, Injectable, OnModuleDestroy, OnModuleInit } from '@nestjs/common' 2 | import { PrismaClient, UserCreateInput } from '@prisma/client' 3 | import { getGravatarUrl, hashPassword } from './api-core-data-access.helper' 4 | 5 | @Injectable() 6 | export class ApiCoreDataAccessService extends PrismaClient implements OnModuleInit, OnModuleDestroy { 7 | constructor() { 8 | super() 9 | } 10 | 11 | public async onModuleDestroy() { 12 | await this.$disconnect() 13 | } 14 | 15 | public async onModuleInit() { 16 | await this.$connect() 17 | } 18 | 19 | async createUser(input: Partial) { 20 | const email = input.email.trim() 21 | const existing = await this.findUserByEmail(email) 22 | if (existing) { 23 | throw new BadRequestException(`Can't create user with email ${email}`) 24 | } 25 | const password = hashPassword(input.password) 26 | 27 | // The first user will get the Web role 28 | const hasWeb = await this.user.count({ where: { role: 'Web' } }) 29 | const role = hasWeb ? 'User' : 'Web' 30 | 31 | return this.user.create({ 32 | data: { 33 | firstName: input.firstName, 34 | lastName: input.lastName, 35 | email, 36 | username: email, 37 | avatarUrl: input.avatarUrl || getGravatarUrl(input.email.toLowerCase()), 38 | password, 39 | role, 40 | }, 41 | }) 42 | } 43 | 44 | public findUserByEmail(email: string) { 45 | return this.user.findUnique({ where: { email } }) 46 | } 47 | 48 | public findUserById(userId: string) { 49 | return this.user.findUnique({ where: { id: userId } }) 50 | } 51 | 52 | public findUserByUsername(username: string) { 53 | return this.user.findUnique({ where: { username } }) 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /libs/web/ui-form/src/lib/web-ui-form.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core' 2 | import { ReactiveFormsModule } from '@angular/forms' 3 | import { FormlyModule } from '@ngx-formly/core' 4 | import { FormlyBootstrapModule } from '@ngx-formly/bootstrap' 5 | import { 6 | emailValidator, 7 | emailValidatorMessage, 8 | maxlengthValidationMessage, 9 | maxValidationMessage, 10 | minlengthValidationMessage, 11 | minValidationMessage, 12 | } from './web-ui-form.validators' 13 | import { WebUiFormFieldRepeatComponent } from './web-ui-form-field-repeat.component' 14 | import { CommonModule } from '@angular/common' 15 | import { WebUiFormComponent } from './web-ui-form.component' 16 | 17 | @NgModule({ 18 | declarations: [WebUiFormComponent, WebUiFormFieldRepeatComponent], 19 | imports: [ 20 | CommonModule, 21 | ReactiveFormsModule, 22 | FormlyModule.forRoot({ 23 | types: [ 24 | { name: 'repeat', component: WebUiFormFieldRepeatComponent }, 25 | { 26 | name: 'color', 27 | extends: 'input', 28 | defaultOptions: { 29 | templateOptions: { 30 | type: 'color', 31 | }, 32 | }, 33 | }, 34 | ], 35 | wrappers: [], 36 | validationMessages: [ 37 | { name: 'required', message: 'This field is required!' }, 38 | { name: 'minlength', message: minlengthValidationMessage }, 39 | { name: 'maxlength', message: maxlengthValidationMessage }, 40 | { name: 'min', message: minValidationMessage }, 41 | { name: 'max', message: maxValidationMessage }, 42 | { name: 'email', message: emailValidatorMessage }, 43 | ], 44 | validators: [{ name: 'email', validation: emailValidator }], 45 | }), 46 | FormlyBootstrapModule, 47 | ], 48 | exports: [ReactiveFormsModule, FormlyModule, FormlyBootstrapModule, WebUiFormComponent], 49 | }) 50 | export class WebUiFormModule {} 51 | -------------------------------------------------------------------------------- /libs/web/auth/feature/src/lib/components/auth-page/auth-page.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, EventEmitter, Input, Output } from '@angular/core' 2 | import { FormGroup } from '@angular/forms' 3 | 4 | @Component({ 5 | selector: 'auth-page', 6 | template: ` 7 |
8 |
9 |
10 |
11 |
12 |
13 | logo 14 |
15 | 16 |
17 |
18 |
19 |

{{ pageTitle }}

20 |
21 | 22 |
23 |
24 |
25 | 28 |
29 |
30 | 31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 | `, 40 | }) 41 | export class AuthPageComponent { 42 | @Input() buttonTitle: string 43 | @Input() form = new FormGroup({}) 44 | @Input() fields = [] 45 | @Input() model = {} 46 | @Input() pageTitle: string 47 | @Output() submit = new EventEmitter() 48 | 49 | public submitForm() { 50 | this.submit.next(this.model) 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /nx.json: -------------------------------------------------------------------------------- 1 | { 2 | "npmScope": "beehive", 3 | "affected": { 4 | "defaultBase": "main" 5 | }, 6 | "implicitDependencies": { 7 | "workspace.json": "*", 8 | "package.json": { 9 | "dependencies": "*", 10 | "devDependencies": "*" 11 | }, 12 | "tsconfig.base.json": "*", 13 | "tslint.json": "*", 14 | ".eslintrc.json": "*", 15 | "nx.json": "*" 16 | }, 17 | "tasksRunnerOptions": { 18 | "default": { 19 | "runner": "@nrwl/workspace/tasks-runners/default", 20 | "options": { 21 | "cacheableOperations": ["build", "lint", "test", "e2e"] 22 | } 23 | } 24 | }, 25 | "projects": { 26 | "api": { 27 | "tags": [] 28 | }, 29 | "api-auth-data-access": { 30 | "tags": ["scope:api", "type:data-access"] 31 | }, 32 | "api-auth-feature": { 33 | "tags": ["scope:api", "type:feature"] 34 | }, 35 | "api-core-data-access": { 36 | "tags": ["scope:api", "type:data-access"] 37 | }, 38 | "api-core-feature": { 39 | "tags": ["scope:api", "type:feature"] 40 | }, 41 | "api-e2e": { 42 | "tags": [] 43 | }, 44 | "web": { 45 | "tags": [] 46 | }, 47 | "web-about-feature": { 48 | "tags": ["scope:web", "type:feature"] 49 | }, 50 | "web-assets": { 51 | "tags": ["scope:web", "type:assets"] 52 | }, 53 | "web-auth-data-access": { 54 | "tags": ["scope:web", "type:data-access"] 55 | }, 56 | "web-auth-feature": { 57 | "tags": ["scope:web", "type:feature"] 58 | }, 59 | "web-core-data-access": { 60 | "tags": ["scope:web", "type:data-access"] 61 | }, 62 | "web-core-feature": { 63 | "tags": ["scope:web", "type:feature"] 64 | }, 65 | "web-dashboard-feature": { 66 | "tags": ["scope:web", "type:feature"] 67 | }, 68 | "web-e2e": { 69 | "tags": [], 70 | "implicitDependencies": ["web"] 71 | }, 72 | "web-layout": { 73 | "tags": ["scope:web", "type:layout"] 74 | }, 75 | "web-shell-feature": { 76 | "tags": ["scope:web", "type:feature"] 77 | }, 78 | "web-style": { 79 | "tags": ["scope:web", "type:style"] 80 | }, 81 | "web-ui-form": { 82 | "tags": ["scope:web", "type:ui"] 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /libs/web/layout/src/lib/web-layout.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 | 38 |
39 | 40 |
41 |
42 |
43 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rulesDirectory": ["node_modules/@nrwl/workspace/src/tslint", "node_modules/codelyzer"], 3 | "linterOptions": { 4 | "exclude": ["**/*"] 5 | }, 6 | "rules": { 7 | "arrow-return-shorthand": true, 8 | "callable-types": true, 9 | "class-name": true, 10 | "deprecation": { 11 | "severity": "warn" 12 | }, 13 | "forin": true, 14 | "import-blacklist": [true, "rxjs/Rx"], 15 | "interface-over-type-literal": true, 16 | "member-access": false, 17 | "member-ordering": [ 18 | true, 19 | { 20 | "order": ["static-field", "instance-field", "static-method", "instance-method"] 21 | } 22 | ], 23 | "no-arg": true, 24 | "no-bitwise": true, 25 | "no-console": [true, "debug", "info", "time", "timeEnd", "trace"], 26 | "no-construct": true, 27 | "no-debugger": true, 28 | "no-duplicate-super": true, 29 | "no-empty": false, 30 | "no-empty-interface": true, 31 | "no-eval": true, 32 | "no-inferrable-types": [true, "ignore-params"], 33 | "no-misused-new": true, 34 | "no-non-null-assertion": true, 35 | "no-shadowed-variable": true, 36 | "no-string-literal": false, 37 | "no-string-throw": true, 38 | "no-switch-case-fall-through": true, 39 | "no-unnecessary-initializer": true, 40 | "no-unused-expression": true, 41 | "no-var-keyword": true, 42 | "object-literal-sort-keys": false, 43 | "prefer-const": true, 44 | "radix": true, 45 | "triple-equals": [true, "allow-null-check"], 46 | "unified-signatures": true, 47 | "variable-name": false, 48 | "nx-enforce-module-boundaries": [ 49 | true, 50 | { 51 | "enforceBuildableLibDependency": true, 52 | "allow": [], 53 | "depConstraints": [ 54 | { 55 | "sourceTag": "*", 56 | "onlyDependOnLibsWithTags": ["*"] 57 | } 58 | ] 59 | } 60 | ], 61 | "directive-selector": [true, "attribute", "app", "camelCase"], 62 | "component-selector": [true, "element", "app", "kebab-case"], 63 | "no-conflicting-lifecycle": true, 64 | "no-host-metadata-property": true, 65 | "no-input-rename": true, 66 | "no-inputs-metadata-property": true, 67 | "no-output-native": true, 68 | "no-output-on-prefix": true, 69 | "no-output-rename": true, 70 | "no-outputs-metadata-property": true, 71 | "template-banana-in-box": true, 72 | "template-no-negated-async": true, 73 | "use-lifecycle-interface": true, 74 | "use-pipe-transform-interface": true 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /libs/web/dashboard/feature/src/lib/settings/web-settings-feature.component.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 |
5 | 6 | 7 |
8 | 9 |
10 |
Settings
11 |
12 |
13 |
14 | 15 |
16 | 17 | 27 | 28 |
29 |
30 |
31 | 32 |
33 | 34 | 35 |
36 | 37 |
38 |
Your Account
39 |
40 |
41 |
42 |
43 | {{ description }} 44 |
45 | 69 |
70 |
71 |
72 | -------------------------------------------------------------------------------- /apps/web/src/polyfills.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file includes polyfills needed by Angular and is loaded before the app. 3 | * You can add your own extra polyfills to this file. 4 | * 5 | * This file is divided into 2 sections: 6 | * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. 7 | * 2. Application imports. Files imported after ZoneJS that should be loaded before your main 8 | * file. 9 | * 10 | * The current setup is for so-called "evergreen" browsers; the last versions of browsers that 11 | * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), 12 | * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. 13 | * 14 | * Learn more in https://angular.io/guide/browser-support 15 | */ 16 | 17 | /*************************************************************************************************** 18 | * BROWSER POLYFILLS 19 | */ 20 | 21 | /** IE11 requires the following for NgClass support on SVG elements */ 22 | // import 'classlist.js'; // Run `npm install --save classlist.js`. 23 | 24 | /** 25 | * Web Animations `@angular/platform-browser/animations` 26 | * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari. 27 | * Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0). 28 | */ 29 | // import 'web-animations-js'; // Run `npm install --save web-animations-js`. 30 | 31 | /** 32 | * By default, zone.js will patch all possible macroTask and DomEvents 33 | * user can disable parts of macroTask/DomEvents patch by setting following flags 34 | * because those flags need to be set before `zone.js` being loaded, and webpack 35 | * will put import in the top of bundle, so user need to create a separate file 36 | * in this directory (for example: zone-flags.ts), and put the following flags 37 | * into that file, and then add the following code before importing zone.js. 38 | * import './zone-flags'; 39 | * 40 | * The flags allowed in zone-flags.ts are listed here. 41 | * 42 | * The following flags will work for all browsers. 43 | * 44 | * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame 45 | * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick 46 | * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames 47 | * 48 | * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js 49 | * with the following flag, it will bypass `zone.js` patch for IE/Edge 50 | * 51 | * (window as any).__Zone_enable_cross_context_check = true; 52 | * 53 | */ 54 | 55 | /*************************************************************************************************** 56 | * Zone JS is required by default for Angular itself. 57 | */ 58 | import 'zone.js/dist/zone' // Included with Angular CLI. 59 | 60 | /*************************************************************************************************** 61 | * APPLICATION IMPORTS 62 | */ 63 | -------------------------------------------------------------------------------- /libs/api/auth/data-access/src/lib/api-auth-data-access.service.ts: -------------------------------------------------------------------------------- 1 | import { BadRequestException, Injectable, NotFoundException } from '@nestjs/common' 2 | import { JwtService } from '@nestjs/jwt' 3 | import { UserCreateInput } from '@prisma/client' 4 | import { ApiCoreDataAccessService } from '@beehive/api/core/data-access' 5 | import { ApiCoreFeatureService } from '@beehive/api/core/feature' 6 | import { Response } from 'express' 7 | import { getGravatarUrl, hashPassword, validatePassword } from './api-auth-data-access.helper' 8 | import { LoginInput } from './dto/login.input' 9 | import { RegisterInput } from './dto/register.input' 10 | import { UserToken } from './models/user-token' 11 | import { Role } from './models/role' 12 | 13 | @Injectable() 14 | export class ApiAuthDataAccessService { 15 | constructor( 16 | private readonly data: ApiCoreDataAccessService, 17 | private readonly core: ApiCoreFeatureService, 18 | private readonly jwtService: JwtService, 19 | ) {} 20 | 21 | async register(payload: RegisterInput) { 22 | const user = await this.createUser({ 23 | ...payload, 24 | }) 25 | 26 | return this.signUser(user) 27 | } 28 | 29 | async login(input: LoginInput) { 30 | const email = input.email.trim() 31 | const password = input.password.trim() 32 | const user = await this.findUserByEmail(email) 33 | 34 | if (!user) { 35 | throw new NotFoundException(`No user found for email: ${email}`) 36 | } 37 | 38 | const passwordValid = await validatePassword(password, user.password) 39 | 40 | if (!passwordValid) { 41 | throw new BadRequestException('Invalid password') 42 | } 43 | 44 | return this.signUser(user) 45 | } 46 | 47 | signUser(user): UserToken { 48 | const token = this.jwtService.sign({ userId: user?.id }) 49 | return { token, user } 50 | } 51 | 52 | validateUser(userId: string) { 53 | return this.findUserById(userId) 54 | } 55 | 56 | getUserFromToken(token: string) { 57 | const userId = this.jwtService.decode(token)['userId'] 58 | 59 | return this.findUserById(userId) 60 | } 61 | 62 | public findUserByEmail(email: string) { 63 | return this.data.user.findUnique({ where: { email } }) 64 | } 65 | 66 | public findUserById(userId: string) { 67 | return this.data.user.findUnique({ where: { id: userId } }) 68 | } 69 | 70 | public findUserByUsername(username: string) { 71 | return this.data.user.findUnique({ where: { username } }) 72 | } 73 | 74 | async createUser(input: Partial) { 75 | const submittedPassword = !!input.password 76 | const password = input.password 77 | const hashedPassword = hashPassword(password) 78 | const email = input.email.trim() 79 | const username = input.username || email 80 | 81 | return this.data.user.create({ 82 | data: { 83 | firstName: input.firstName, 84 | lastName: input.lastName, 85 | email, 86 | phone: input.phone, 87 | username, 88 | avatarUrl: input.avatarUrl || getGravatarUrl(input.email.toLowerCase()), 89 | password: hashedPassword, 90 | role: Role.User, 91 | }, 92 | }) 93 | } 94 | 95 | public setCookie(res: Response, token: string) { 96 | return res?.cookie(this.core.cookie.name, token, this.core.cookie.options) 97 | } 98 | 99 | public clearCookie(res: Response) { 100 | return res.clearCookie(this.core.cookie.name, this.core.cookie.options) 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Beehive 2 | 3 | This project was generated using [Nx](https://nx.dev). 4 | 5 |

6 | 7 | 🔎 **Nx is a set of Extensible Dev Tools for Monorepos.** 8 | 9 | ## Adding capabilities to your workspace 10 | 11 | Nx supports many plugins which add capabilities for developing different types of applications and different tools. 12 | 13 | These capabilities include generating applications, libraries, etc as well as the devtools to test, and build projects as well. 14 | 15 | Below are our core plugins: 16 | 17 | - [React](https://reactjs.org) 18 | - `npm install --save-dev @nrwl/react` 19 | - Web (no framework frontends) 20 | - `npm install --save-dev @nrwl/web` 21 | - [Angular](https://angular.io) 22 | - `npm install --save-dev @nrwl/angular` 23 | - [Nest](https://nestjs.com) 24 | - `npm install --save-dev @nrwl/nest` 25 | - [Express](https://expressjs.com) 26 | - `npm install --save-dev @nrwl/express` 27 | - [Node](https://nodejs.org) 28 | - `npm install --save-dev @nrwl/node` 29 | 30 | There are also many [community plugins](https://nx.dev/nx-community) you could add. 31 | 32 | ## Generate an application 33 | 34 | Run `nx g @nrwl/react:app my-app` to generate an application. 35 | 36 | > You can use any of the plugins above to generate applications as well. 37 | 38 | When using Nx, you can create multiple applications and libraries in the same workspace. 39 | 40 | ## Generate a library 41 | 42 | Run `nx g @nrwl/react:lib my-lib` to generate a library. 43 | 44 | > You can also use any of the plugins above to generate libraries as well. 45 | 46 | Libraries are sharable across libraries and applications. They can be imported from `@beehive/mylib`. 47 | 48 | ## Development server 49 | 50 | Run `nx serve my-app` for a dev server. Navigate to http://localhost:4200/. The app will automatically reload if you change any of the source files. 51 | 52 | ## Code scaffolding 53 | 54 | Run `nx g @nrwl/react:component my-component --project=my-app` to generate a new component. 55 | 56 | ## Build 57 | 58 | Run `nx build my-app` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build. 59 | 60 | ## Running unit tests 61 | 62 | Run `nx test my-app` to execute the unit tests via [Jest](https://jestjs.io). 63 | 64 | Run `nx affected:test` to execute the unit tests affected by a change. 65 | 66 | ## Running end-to-end tests 67 | 68 | Run `ng e2e my-app` to execute the end-to-end tests via [Cypress](https://www.cypress.io). 69 | 70 | Run `nx affected:e2e` to execute the end-to-end tests affected by a change. 71 | 72 | ## Understand your workspace 73 | 74 | Run `nx dep-graph` to see a diagram of the dependencies of your projects. 75 | 76 | ## Further help 77 | 78 | Visit the [Nx Documentation](https://nx.dev) to learn more. 79 | 80 | ## ☁ Nx Cloud 81 | 82 | ### Computation Memoization in the Cloud 83 | 84 |

85 | 86 | Nx Cloud pairs with Nx in order to enable you to build and test code more rapidly, by up to 10 times. Even teams that are new to Nx can connect to Nx Cloud and start saving time instantly. 87 | 88 | Teams using Nx gain the advantage of building full-stack applications with their preferred framework alongside Nx’s advanced code generation and project dependency graph, plus a unified experience for both frontend and backend developers. 89 | 90 | Visit [Nx Cloud](https://nx.app/) to learn more. 91 | -------------------------------------------------------------------------------- /libs/web/auth/data-access/src/lib/+state/auth/auth.effects.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core' 2 | import { Router } from '@angular/router' 3 | import { Actions, createEffect, ofType } from '@ngrx/effects' 4 | import { fetch } from '@nrwl/angular' 5 | import { of } from 'rxjs' 6 | import { map, switchMap, tap } from 'rxjs/operators' 7 | import { WebAuthDataAccessService } from '../../web-auth-data-access.service' 8 | import * as AuthActions from './auth.actions' 9 | 10 | @Injectable() 11 | export class AuthEffects { 12 | ensureLogin$ = createEffect(() => { 13 | return this.actions$.pipe( 14 | ofType(AuthActions.ensureLogin), 15 | fetch({ 16 | run: () => 17 | this.service.me().pipe( 18 | map((res) => { 19 | if (!res.data.me) { 20 | return AuthActions.redirectToLogin({ 21 | url: this.router?.routerState?.snapshot?.url || '/', 22 | }) 23 | } 24 | return AuthActions.loginSuccess({ user: res.data.me }) 25 | }), 26 | ), 27 | onError: (action, error) => { 28 | return AuthActions.logoutFailure({ error: error.message }) 29 | }, 30 | }), 31 | ) 32 | }) 33 | 34 | login$ = createEffect(() => { 35 | return this.actions$.pipe( 36 | ofType(AuthActions.login), 37 | fetch({ 38 | run: ({ input }) => 39 | this.service.login(input).pipe( 40 | map((res) => { 41 | return AuthActions.loginSuccess({ user: res.data?.login?.user }) 42 | }), 43 | ), 44 | onError: (action, error) => AuthActions.registerFailure({ error: error.message }), 45 | }), 46 | ) 47 | }) 48 | 49 | logout$ = createEffect(() => { 50 | return this.actions$.pipe( 51 | ofType(AuthActions.logout), 52 | fetch({ 53 | run: () => 54 | this.service.logout().pipe( 55 | map((res) => { 56 | return AuthActions.logoutSuccess() 57 | }), 58 | ), 59 | onError: (action, error) => AuthActions.logoutFailure({ error: error.message }), 60 | }), 61 | ) 62 | }) 63 | 64 | logoutFailure$ = createEffect(() => { 65 | return this.actions$.pipe( 66 | ofType(AuthActions.logoutFailure), 67 | map(() => 68 | AuthActions.redirectToLogin({ 69 | url: this.router?.routerState?.snapshot?.url || '/', 70 | }), 71 | ), 72 | ) 73 | }) 74 | 75 | redirectToLogin$ = createEffect( 76 | () => { 77 | return this.actions$.pipe( 78 | ofType(AuthActions.redirectToLogin), 79 | tap(({ url }) => { 80 | this.router.navigate(['/login'], url && url !== '/' ? { queryParams: { url } } : {}) 81 | }), 82 | ) 83 | }, 84 | { dispatch: false }, 85 | ) 86 | 87 | register$ = createEffect(() => { 88 | return this.actions$.pipe( 89 | ofType(AuthActions.register), 90 | fetch({ 91 | run: ({ input }) => 92 | this.service.register(input).pipe( 93 | map((res) => { 94 | return AuthActions.registerSuccess({ 95 | user: res.data?.register?.user, 96 | }) 97 | }), 98 | ), 99 | onError: (action, error) => AuthActions.registerFailure({ error: error.message }), 100 | }), 101 | ) 102 | }) 103 | 104 | constructor( 105 | private readonly actions$: Actions, 106 | private readonly service: WebAuthDataAccessService, 107 | private readonly router: Router, 108 | ) {} 109 | } 110 | -------------------------------------------------------------------------------- /libs/web/dashboard/feature/src/lib/messages/web-messages-feature.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core' 2 | 3 | @Component({ 4 | templateUrl: './web-messages-feature.component.html', 5 | }) 6 | export class WebMessagesFeatureComponent { 7 | chats: { text: string; createdAt: string; author: { avatarUrl: string; username: string; name: string } }[] = [ 8 | { 9 | author: { 10 | avatarUrl: 'https://avatars3.githubusercontent.com/u/36491?v=4', 11 | name: 'beeman 🐝', 12 | username: 'beeman_nl', 13 | }, 14 | createdAt: '36m', 15 | text: 'He there, how are you doing?', 16 | }, 17 | { 18 | author: { 19 | avatarUrl: 'https://avatars3.githubusercontent.com/u/36491?v=4', 20 | name: 'beeman 🐝', 21 | username: 'beeman_nl', 22 | }, 23 | createdAt: '36m', 24 | text: 'He there, how are you doing?', 25 | }, 26 | { 27 | author: { 28 | avatarUrl: 'https://avatars3.githubusercontent.com/u/36491?v=4', 29 | name: 'beeman 🐝', 30 | username: 'beeman_nl', 31 | }, 32 | createdAt: '36m', 33 | text: 'He there, how are you doing?', 34 | }, 35 | { 36 | author: { 37 | avatarUrl: 'https://avatars3.githubusercontent.com/u/36491?v=4', 38 | name: 'beeman 🐝', 39 | username: 'beeman_nl', 40 | }, 41 | createdAt: '36m', 42 | text: 'He there, how are you doing?', 43 | }, 44 | { 45 | author: { 46 | avatarUrl: 'https://avatars3.githubusercontent.com/u/36491?v=4', 47 | name: 'beeman 🐝', 48 | username: 'beeman_nl', 49 | }, 50 | createdAt: '36m', 51 | text: 'He there, how are you doing?', 52 | }, 53 | { 54 | author: { 55 | avatarUrl: 'https://avatars3.githubusercontent.com/u/36491?v=4', 56 | name: 'beeman 🐝', 57 | username: 'beeman_nl', 58 | }, 59 | createdAt: '36m', 60 | text: 'He there, how are you doing?', 61 | }, 62 | { 63 | author: { 64 | avatarUrl: 'https://avatars3.githubusercontent.com/u/36491?v=4', 65 | name: 'beeman 🐝', 66 | username: 'beeman_nl', 67 | }, 68 | createdAt: '36m', 69 | text: 'He there, how are you doing?', 70 | }, 71 | { 72 | author: { 73 | avatarUrl: 'https://avatars3.githubusercontent.com/u/36491?v=4', 74 | name: 'beeman 🐝', 75 | username: 'beeman_nl', 76 | }, 77 | createdAt: '36m', 78 | text: 'He there, how are you doing?', 79 | }, 80 | { 81 | author: { 82 | avatarUrl: 'https://avatars3.githubusercontent.com/u/36491?v=4', 83 | name: 'beeman 🐝', 84 | username: 'beeman_nl', 85 | }, 86 | createdAt: '36m', 87 | text: 'He there, how are you doing?', 88 | }, 89 | { 90 | author: { 91 | avatarUrl: 'https://avatars3.githubusercontent.com/u/36491?v=4', 92 | name: 'beeman 🐝', 93 | username: 'beeman_nl', 94 | }, 95 | createdAt: '36m', 96 | text: 'He there, how are you doing?', 97 | }, 98 | { 99 | author: { 100 | avatarUrl: 'https://avatars3.githubusercontent.com/u/36491?v=4', 101 | name: 'beeman 🐝', 102 | username: 'beeman_nl', 103 | }, 104 | createdAt: '36m', 105 | text: 'He there, how are you doing?', 106 | }, 107 | { 108 | author: { 109 | avatarUrl: 'https://avatars3.githubusercontent.com/u/36491?v=4', 110 | name: 'beeman 🐝', 111 | username: 'beeman_nl', 112 | }, 113 | createdAt: '36m', 114 | text: 'He there, how are you doing?', 115 | }, 116 | { 117 | author: { 118 | avatarUrl: 'https://avatars3.githubusercontent.com/u/36491?v=4', 119 | name: 'beeman 🐝', 120 | username: 'beeman_nl', 121 | }, 122 | createdAt: '36m', 123 | text: 'He there, how are you doing?', 124 | }, 125 | { 126 | author: { 127 | avatarUrl: 'https://avatars3.githubusercontent.com/u/36491?v=4', 128 | name: 'beeman 🐝', 129 | username: 'beeman_nl', 130 | }, 131 | createdAt: '36m', 132 | text: 'He there, how are you doing?', 133 | }, 134 | ] 135 | } 136 | -------------------------------------------------------------------------------- /libs/web/ui-form/src/lib/web-ui-form.field.ts: -------------------------------------------------------------------------------- 1 | import { FormlyFieldConfig, FormlyTemplateOptions } from '@ngx-formly/core' 2 | 3 | export class WebUiFormField implements FormlyFieldConfig { 4 | public static map(f: string) { 5 | const map = { 6 | input: WebUiFormField.input, 7 | email: WebUiFormField.email, 8 | password: WebUiFormField.password, 9 | number: WebUiFormField.number, 10 | checkbox: WebUiFormField.checkbox, 11 | radio: WebUiFormField.radio, 12 | select: WebUiFormField.select, 13 | textarea: WebUiFormField.textarea, 14 | group: WebUiFormField.group, 15 | template: WebUiFormField.template, 16 | date: WebUiFormField.date, 17 | time: WebUiFormField.time, 18 | } 19 | return map[f] ? map[f] : WebUiFormField.input 20 | } 21 | 22 | public static field( 23 | type: string, 24 | key: string, 25 | templateOptions?: FormlyTemplateOptions, 26 | options?: any, 27 | ): FormlyFieldConfig { 28 | return { 29 | type, 30 | key, 31 | templateOptions, 32 | ...options, 33 | } 34 | } 35 | 36 | public static input(key: string, templateOptions?: FormlyTemplateOptions, options?: any): FormlyFieldConfig { 37 | return WebUiFormField.field('input', key, templateOptions, options) 38 | } 39 | 40 | public static email(key: string, templateOptions?: FormlyTemplateOptions, options?: any): FormlyFieldConfig { 41 | const defaults = { 42 | type: 'email', 43 | label: 'Email', 44 | } 45 | const defaultOptions = { validators: { validation: ['email'] } } 46 | 47 | return WebUiFormField.input(key, { ...templateOptions, ...defaults }, { ...options, ...defaultOptions }) 48 | } 49 | 50 | public static password(key: string, templateOptions?: FormlyTemplateOptions, options?: any): FormlyFieldConfig { 51 | const defaults = { 52 | label: 'Password', 53 | type: 'password', 54 | minLength: 8, 55 | required: true, 56 | } 57 | 58 | return WebUiFormField.input(key, { ...templateOptions, ...defaults }, options) 59 | } 60 | 61 | public static number(key: string, templateOptions?: FormlyTemplateOptions, options?: any): FormlyFieldConfig { 62 | return WebUiFormField.input(key, { ...templateOptions, type: 'number' }, { ...options }) 63 | } 64 | 65 | public static checkbox(key: string, templateOptions?: FormlyTemplateOptions, options?: any): FormlyFieldConfig { 66 | return WebUiFormField.field('checkbox', key, templateOptions, options) 67 | } 68 | 69 | public static radio(key: string, templateOptions?: FormlyTemplateOptions, options?: any): FormlyFieldConfig { 70 | return WebUiFormField.field('radio', key, templateOptions, options) 71 | } 72 | 73 | public static select(key: string, templateOptions?: FormlyTemplateOptions, options?: any): FormlyFieldConfig { 74 | return WebUiFormField.field('select', key, templateOptions, options) 75 | } 76 | 77 | public static typeahead(key: string, templateOptions?: FormlyTemplateOptions, options?: any): FormlyFieldConfig { 78 | return WebUiFormField.field('typeahead', key, templateOptions, options) 79 | } 80 | 81 | public static textarea(key: string, templateOptions?: FormlyTemplateOptions, options?: any): FormlyFieldConfig { 82 | const defaultTemplateOptions = { rows: 5 } 83 | 84 | return WebUiFormField.field('textarea', key, { ...defaultTemplateOptions, ...templateOptions }, options) 85 | } 86 | 87 | public static group(fieldGroupClassName: string, fieldGroup: FormlyFieldConfig[]): FormlyFieldConfig { 88 | return { fieldGroupClassName, fieldGroup } 89 | } 90 | 91 | public static template(template: string): FormlyFieldConfig { 92 | return { type: 'formly-template', template } 93 | } 94 | 95 | public static date(key: string, templateOptions?: FormlyTemplateOptions, options?: any): FormlyFieldConfig { 96 | return WebUiFormField.input(key, { ...templateOptions, type: 'date' }, { ...options }) 97 | } 98 | 99 | public static time(key: string, templateOptions?: FormlyTemplateOptions, options?: any): FormlyFieldConfig { 100 | return WebUiFormField.input(key, { ...templateOptions, type: 'time' }, { ...options }) 101 | } 102 | 103 | public static datetime(key: string, templateOptions?: FormlyTemplateOptions, options?: any): FormlyFieldConfig { 104 | return WebUiFormField.field('datetime', key, { ...templateOptions }, { ...options }) 105 | } 106 | 107 | public static rating(key: string, templateOptions?: FormlyTemplateOptions, options?: any): FormlyFieldConfig { 108 | return WebUiFormField.field('rating', key, { ...templateOptions }, { ...options }) 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /libs/web/dashboard/feature/src/lib/messages/web-messages-feature.component.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 |
5 | 6 | 7 |
8 | 9 |
10 |
Messages
11 |
12 | 13 |
14 |
15 |
16 |
17 |
18 | 19 |
20 | 25 | 26 |
27 | 28 |
29 | 30 |
31 | 32 |
33 | User Avatar 34 |
35 | 36 |
37 | 38 |
39 |
40 | 41 | {{ chat.author.name }} 42 |
43 |
44 | 45 | @{{ chat.author.username }} 46 | · 47 | 48 | {{ chat.createdAt }} 49 |
50 |
51 |
52 | 53 | {{ chat.text }} 54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 | 62 |
63 | 64 | 65 |
66 | 67 |
68 | User Avatar 69 |
70 | 71 |
72 |
Beeman
73 |
74 | 75 |
76 |
77 |
78 |
79 |
80 | 81 |
82 | 83 |
84 | 85 |
86 | User Avatar 87 |
88 | 89 |
90 | 91 |
92 |
93 | 94 | {{ chat.author.name }} 95 |
96 |
97 | 98 | @{{ chat.author.username }} 99 | · 100 | 101 | {{ chat.createdAt }} 102 |
103 |
104 |
105 | 106 | {{ chat.text }} 107 |
108 |
109 |
110 |
111 |
112 | 113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 | 125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "beehive", 3 | "version": "0.0.0", 4 | "license": "MIT", 5 | "scripts": { 6 | "dev:web": "nx serve web --hmr", 7 | "build:web": "nx build web --prod", 8 | "sdk:web": "graphql-codegen --config libs/web/core/data-access/src/codegen.yml", 9 | "sdk:web:watch": "yarn sdk:web --watch", 10 | "dev:api": "nx serve api", 11 | "build:api": "nx build api --prod", 12 | "setup": "yarn prisma:apply", 13 | "prisma:apply": "yarn prisma:format && yarn prisma db push --preview-feature", 14 | "prisma:format": "yarn prisma format", 15 | "prisma:generate": "yarn prisma generate", 16 | "prisma:migrate": "yarn prisma migrate save --experimental && yarn prisma migrate up --experimental", 17 | "prisma:studio": "yarn prisma studio", 18 | "build": "yarn build:web && yarn build:api", 19 | "start": "node dist/apps/api/main.js", 20 | "docker:build": "docker build . -t beehive/api", 21 | "docker:run": "docker run -it -p 8000:3000 beehive/api", 22 | "docker:push": "docker push beehive/api", 23 | "nx": "nx", 24 | "test": "nx test", 25 | "lint": "nx workspace-lint && nx lint", 26 | "e2e": "nx e2e", 27 | "affected:apps": "nx affected:apps", 28 | "affected:libs": "nx affected:libs", 29 | "affected:build": "nx affected:build", 30 | "affected:e2e": "nx affected:e2e", 31 | "affected:test": "nx affected:test", 32 | "affected:lint": "nx affected:lint", 33 | "affected:dep-graph": "nx affected:dep-graph", 34 | "affected": "nx affected", 35 | "format": "nx format:write", 36 | "format:write": "nx format:write", 37 | "format:check": "nx format:check", 38 | "update": "nx migrate latest", 39 | "workspace-generator": "nx workspace-generator", 40 | "dep-graph": "nx dep-graph", 41 | "help": "nx help", 42 | "postinstall": "ngcc --properties es2015 browser module main --first-only --create-ivy-entry-points" 43 | }, 44 | "private": true, 45 | "dependencies": { 46 | "@angular/animations": "^11.0.0", 47 | "@angular/common": "^11.0.0", 48 | "@angular/compiler": "^11.0.0", 49 | "@angular/core": "^11.0.0", 50 | "@angular/forms": "^11.0.0", 51 | "@angular/platform-browser": "^11.0.0", 52 | "@angular/platform-browser-dynamic": "^11.0.0", 53 | "@angular/router": "^11.0.0", 54 | "@apollo/client": "^3.2.9", 55 | "@kikstart-playground/graphql-intercom": "1.4.1", 56 | "@nestjs/common": "^7.0.0", 57 | "@nestjs/config": "^0.5.0", 58 | "@nestjs/core": "^7.0.0", 59 | "@nestjs/graphql": "^7.7.0", 60 | "@nestjs/jwt": "^7.1.0", 61 | "@nestjs/passport": "^7.1.0", 62 | "@nestjs/platform-express": "^7.0.0", 63 | "@ngrx/effects": "10.0.0", 64 | "@ngrx/entity": "10.0.0", 65 | "@ngrx/router-store": "10.0.0", 66 | "@ngrx/store": "10.0.0", 67 | "@ngx-formly/bootstrap": "5.10.3", 68 | "@ngx-formly/core": "5.10.3", 69 | "@prisma/cli": "^2.12.0", 70 | "@prisma/client": "^2.12.0", 71 | "@tailwindcss/forms": "^0.2.1", 72 | "apollo-angular": "^2.1.0", 73 | "apollo-server-express": "^2.18.0", 74 | "bcryptjs": "^2.4.3", 75 | "bootstrap": "^4.5.2", 76 | "bootswatch": "^4.5.2", 77 | "class-transformer": "^0.3.1", 78 | "class-validator": "^0.12.2", 79 | "cookie-parser": "1.4.5", 80 | "graphql": "^15.3.0", 81 | "graphql-tools": "^6.2.3", 82 | "graphql-type-json": "^0.3.2", 83 | "joi": "^17.2.1", 84 | "passport": "^0.4.1", 85 | "passport-jwt": "^4.0.0", 86 | "reflect-metadata": "^0.1.13", 87 | "rxjs": "~6.5.5", 88 | "supertest": "^5.0.0", 89 | "tslib": "^2.0.0", 90 | "zone.js": "^0.10.2" 91 | }, 92 | "devDependencies": { 93 | "@angular-builders/custom-webpack": "11.0.0-beta.1", 94 | "@angular-devkit/build-angular": "~0.1100.1", 95 | "@angular/compiler-cli": "^11.0.0", 96 | "@angular/language-service": "^11.0.0", 97 | "@graphql-codegen/cli": "1.19.3", 98 | "@graphql-codegen/introspection": "1.18.1", 99 | "@graphql-codegen/typescript": "1.18.1", 100 | "@graphql-codegen/typescript-apollo-angular": "^2.2.1", 101 | "@graphql-codegen/typescript-operations": "1.17.12", 102 | "@nestjs/schematics": "^7.0.0", 103 | "@nestjs/testing": "^7.0.0", 104 | "@ngneat/tailwind": "^3.0.6", 105 | "@ngrx/schematics": "10.0.0", 106 | "@ngrx/store-devtools": "10.0.0", 107 | "@nrwl/angular": "^11.0.2", 108 | "@nrwl/cli": "11.0.2", 109 | "@nrwl/cypress": "11.0.2", 110 | "@nrwl/eslint-plugin-nx": "11.0.2", 111 | "@nrwl/jest": "11.0.2", 112 | "@nrwl/nest": "^11.0.2", 113 | "@nrwl/node": "11.0.2", 114 | "@nrwl/tao": "11.0.2", 115 | "@nrwl/workspace": "11.0.2", 116 | "@nxpm/cli": "^1.9.0", 117 | "@nxpm/stack": "^4.1.2", 118 | "@types/jest": "26.0.8", 119 | "@types/node": "12.12.38", 120 | "@typescript-eslint/eslint-plugin": "4.3.0", 121 | "@typescript-eslint/parser": "4.3.0", 122 | "autoprefixer": "10.1.0", 123 | "codelyzer": "^6.0.0", 124 | "cypress": "^5.5.0", 125 | "dotenv": "6.2.0", 126 | "eslint": "7.10.0", 127 | "eslint-config-prettier": "6.0.0", 128 | "husky": "^4.3.0", 129 | "jest": "26.2.2", 130 | "jest-preset-angular": "8.3.1", 131 | "lint-staged": "^10.4.0", 132 | "postcss": "8.2.1", 133 | "postcss-import": "13.0.0", 134 | "postcss-loader": "4.1.0", 135 | "postcss-scss": "3.0.4", 136 | "prettier": "2.1.2", 137 | "tailwindcss": "2.0.2", 138 | "ts-jest": "26.4.0", 139 | "ts-node": "~7.0.0", 140 | "tslint": "~6.0.0", 141 | "typescript": "~4.0.3" 142 | }, 143 | "husky": { 144 | "hooks": { 145 | "pre-commit": "lint-staged", 146 | "pre-push": "yarn format:check" 147 | } 148 | }, 149 | "lint-staged": { 150 | "nx.json": [ 151 | "yarn nxpm-stack lint", 152 | "yarn format:write" 153 | ], 154 | "*.{js,json,css,scss,md,ts,html,graphql}": [ 155 | "yarn format --uncommitted" 156 | ] 157 | }, 158 | "prisma": { 159 | "schema": "libs/api/core/data-access/src/prisma/schema.prisma" 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /libs/web/dashboard/feature/src/lib/posts/web-posts-feature.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core' 2 | 3 | @Component({ 4 | templateUrl: './web-posts-feature.component.html', 5 | }) 6 | export class WebPostsFeatureComponent { 7 | whatsHappening = [ 8 | { 9 | header: 'Trending in Web Development', 10 | time: 'Yesterday', 11 | text: 'TailwindCSS Is Taking Over the World!', 12 | footer: 'Trending with @code', 13 | }, 14 | { 15 | header: 'Trending in Web Development', 16 | time: 'Yesterday', 17 | text: 'Nrwl releases V11 of @NxDevTools', 18 | footer: 'Trending with @code', 19 | }, 20 | ] 21 | whoToFollow = [ 22 | { 23 | username: 'NxDevTools', 24 | name: 'Nrlw Nx', 25 | avatarUrl: '', 26 | }, 27 | { 28 | username: 'BeeSoftLabs', 29 | name: 'BeeSoft Labs', 30 | avatarUrl: '', 31 | }, 32 | { 33 | username: 'connectamind', 34 | name: 'Connect a Mind', 35 | avatarUrl: '', 36 | }, 37 | ] 38 | posts = [ 39 | { 40 | author: { 41 | avatarUrl: 'https://avatars3.githubusercontent.com/u/36491?v=4', 42 | name: 'beeman 🐝', 43 | username: 'beeman_nl', 44 | }, 45 | createdAt: '36m', 46 | text: 'We are live now!! 🚀', 47 | retweetCount: 6, 48 | likeCount: 4, 49 | }, 50 | { 51 | author: { 52 | avatarUrl: 'https://avatars3.githubusercontent.com/u/36491?v=4', 53 | name: 'beeman 🐝', 54 | username: 'beeman_nl', 55 | }, 56 | createdAt: '36m', 57 | text: 'We are live now!! 🚀', 58 | retweetCount: 6, 59 | likeCount: 4, 60 | }, 61 | { 62 | author: { 63 | avatarUrl: 'https://avatars3.githubusercontent.com/u/36491?v=4', 64 | name: 'beeman 🐝', 65 | username: 'beeman_nl', 66 | }, 67 | createdAt: '36m', 68 | text: 'We are live now!! 🚀', 69 | retweetCount: 6, 70 | likeCount: 4, 71 | }, 72 | { 73 | author: { 74 | avatarUrl: 'https://avatars3.githubusercontent.com/u/36491?v=4', 75 | name: 'beeman 🐝', 76 | username: 'beeman_nl', 77 | }, 78 | createdAt: '36m', 79 | text: 'We are live now!! 🚀', 80 | retweetCount: 6, 81 | likeCount: 4, 82 | }, 83 | { 84 | author: { 85 | avatarUrl: 'https://avatars3.githubusercontent.com/u/36491?v=4', 86 | name: 'beeman 🐝', 87 | username: 'beeman_nl', 88 | }, 89 | createdAt: '36m', 90 | text: 'We are live now!! 🚀', 91 | retweetCount: 6, 92 | likeCount: 4, 93 | }, 94 | { 95 | author: { 96 | avatarUrl: 'https://avatars3.githubusercontent.com/u/36491?v=4', 97 | name: 'beeman 🐝', 98 | username: 'beeman_nl', 99 | }, 100 | createdAt: '36m', 101 | text: 'We are live now!! 🚀', 102 | retweetCount: 6, 103 | likeCount: 4, 104 | }, 105 | { 106 | author: { 107 | avatarUrl: 'https://avatars3.githubusercontent.com/u/36491?v=4', 108 | name: 'beeman 🐝', 109 | username: 'beeman_nl', 110 | }, 111 | createdAt: '36m', 112 | text: 'We are live now!! 🚀', 113 | retweetCount: 6, 114 | likeCount: 4, 115 | }, 116 | { 117 | author: { 118 | avatarUrl: 'https://avatars3.githubusercontent.com/u/36491?v=4', 119 | name: 'beeman 🐝', 120 | username: 'beeman_nl', 121 | }, 122 | createdAt: '36m', 123 | text: 'We are live now!! 🚀', 124 | retweetCount: 6, 125 | likeCount: 4, 126 | }, 127 | { 128 | author: { 129 | avatarUrl: 'https://avatars3.githubusercontent.com/u/36491?v=4', 130 | name: 'beeman 🐝', 131 | username: 'beeman_nl', 132 | }, 133 | createdAt: '36m', 134 | text: 'We are live now!! 🚀', 135 | retweetCount: 6, 136 | likeCount: 4, 137 | }, 138 | { 139 | author: { 140 | avatarUrl: 'https://avatars3.githubusercontent.com/u/36491?v=4', 141 | name: 'beeman 🐝', 142 | username: 'beeman_nl', 143 | }, 144 | createdAt: '36m', 145 | text: 'We are live now!! 🚀', 146 | retweetCount: 6, 147 | likeCount: 4, 148 | }, 149 | { 150 | author: { 151 | avatarUrl: 'https://avatars3.githubusercontent.com/u/36491?v=4', 152 | name: 'beeman 🐝', 153 | username: 'beeman_nl', 154 | }, 155 | createdAt: '36m', 156 | text: 'We are live now!! 🚀', 157 | retweetCount: 6, 158 | likeCount: 4, 159 | }, 160 | { 161 | author: { 162 | avatarUrl: 'https://avatars3.githubusercontent.com/u/36491?v=4', 163 | name: 'beeman 🐝', 164 | username: 'beeman_nl', 165 | }, 166 | createdAt: '36m', 167 | text: 'We are live now!! 🚀', 168 | retweetCount: 6, 169 | likeCount: 4, 170 | }, 171 | { 172 | author: { 173 | avatarUrl: 'https://avatars3.githubusercontent.com/u/36491?v=4', 174 | name: 'beeman 🐝', 175 | username: 'beeman_nl', 176 | }, 177 | createdAt: '36m', 178 | text: 'We are live now!! 🚀', 179 | retweetCount: 6, 180 | likeCount: 4, 181 | }, 182 | { 183 | author: { 184 | avatarUrl: 'https://avatars3.githubusercontent.com/u/36491?v=4', 185 | name: 'beeman 🐝', 186 | username: 'beeman_nl', 187 | }, 188 | createdAt: '36m', 189 | text: 'We are live now!! 🚀', 190 | retweetCount: 6, 191 | likeCount: 4, 192 | }, 193 | { 194 | author: { 195 | avatarUrl: 'https://avatars3.githubusercontent.com/u/36491?v=4', 196 | name: 'beeman 🐝', 197 | username: 'beeman_nl', 198 | }, 199 | createdAt: '36m', 200 | text: 'We are live now!! 🚀', 201 | retweetCount: 6, 202 | likeCount: 4, 203 | }, 204 | { 205 | author: { 206 | avatarUrl: 'https://avatars3.githubusercontent.com/u/36491?v=4', 207 | name: 'beeman 🐝', 208 | username: 'beeman_nl', 209 | }, 210 | createdAt: '36m', 211 | text: 'We are live now!! 🚀', 212 | retweetCount: 6, 213 | likeCount: 4, 214 | }, 215 | { 216 | author: { 217 | avatarUrl: 'https://avatars3.githubusercontent.com/u/36491?v=4', 218 | name: 'beeman 🐝', 219 | username: 'beeman_nl', 220 | }, 221 | createdAt: '36m', 222 | text: 'We are live now!! 🚀', 223 | retweetCount: 6, 224 | likeCount: 4, 225 | }, 226 | ] 227 | } 228 | -------------------------------------------------------------------------------- /libs/web/dashboard/feature/src/lib/posts/web-posts-feature.component.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 |
7 | 8 |
9 | 10 |
11 | User Avatar 12 |
13 | 14 |
15 |
Latest Tweets
16 |
17 | 18 |
19 |
20 |
21 |
22 | 23 |
24 | 25 | 65 | 66 | 67 |
68 | 69 |
70 | User Avatar 71 |
72 | 73 |
74 | 75 |
76 |
77 | 78 | {{ post.author.name }} 79 |
80 |
81 | 82 | @{{ post.author.username }} 83 | · 84 | 85 | {{ post.createdAt }} 86 |
87 |
88 |
89 | 90 | {{ post.text }} 91 |
92 | 93 |
94 | 95 |
96 | 97 |
98 | 99 |
100 | 101 |
102 |
103 |
104 |
105 |
106 |
107 | 108 |
109 | 110 | 111 |
112 |
113 | 114 | 115 |
116 |
117 | 118 | 119 |
120 |
121 | 122 | 123 |
124 |
125 |
126 |
127 | 128 | 181 |
182 | -------------------------------------------------------------------------------- /libs/web/core/data-access/src/generated/graphql.ts: -------------------------------------------------------------------------------- 1 | import { gql } from 'apollo-angular' 2 | import { Injectable } from '@angular/core' 3 | import * as Apollo from 'apollo-angular' 4 | import * as ApolloCore from '@apollo/client/core' 5 | export type Maybe = T | null 6 | export type Exact = { 7 | [K in keyof T]: T[K] 8 | } 9 | export type MakeOptional = Omit & { [SubKey in K]?: Maybe } 10 | export type MakeMaybe = Omit & { [SubKey in K]: Maybe } 11 | /** All built-in and custom scalars, mapped to their actual values */ 12 | export type Scalars = { 13 | ID: string 14 | String: string 15 | Boolean: boolean 16 | Int: number 17 | Float: number 18 | /** A date-time string at UTC, such as 2019-12-03T09:54:33Z, compliant with the date-time format. */ 19 | DateTime: any 20 | /** The `JSON` scalar type represents JSON values as specified by [ECMA-404](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf). */ 21 | JSON: any 22 | } 23 | 24 | export type IntercomMessage = { 25 | __typename?: 'IntercomMessage' 26 | payload?: Maybe 27 | scope?: Maybe 28 | type?: Maybe 29 | } 30 | 31 | export type LoginInput = { 32 | email: Scalars['String'] 33 | password: Scalars['String'] 34 | } 35 | 36 | export type Mutation = { 37 | __typename?: 'Mutation' 38 | intercomPub?: Maybe 39 | login?: Maybe 40 | logout?: Maybe 41 | register?: Maybe 42 | } 43 | 44 | export type MutationIntercomPubArgs = { 45 | payload?: Maybe 46 | scope?: Maybe 47 | type: Scalars['String'] 48 | } 49 | 50 | export type MutationLoginArgs = { 51 | input: LoginInput 52 | } 53 | 54 | export type MutationRegisterArgs = { 55 | input: RegisterInput 56 | } 57 | 58 | export type Query = { 59 | __typename?: 'Query' 60 | me?: Maybe 61 | uptime?: Maybe 62 | } 63 | 64 | export type RegisterInput = { 65 | avatarUrl?: Maybe 66 | email: Scalars['String'] 67 | firstName?: Maybe 68 | lastName?: Maybe 69 | password: Scalars['String'] 70 | phone?: Maybe 71 | username?: Maybe 72 | } 73 | 74 | /** User role */ 75 | export enum Role { 76 | Web = 'Web', 77 | User = 'User', 78 | } 79 | 80 | export type Subscription = { 81 | __typename?: 'Subscription' 82 | intercomSub?: Maybe 83 | } 84 | 85 | export type SubscriptionIntercomSubArgs = { 86 | scope?: Maybe 87 | type?: Maybe 88 | } 89 | 90 | export type User = { 91 | __typename?: 'User' 92 | avatarUrl?: Maybe 93 | bio?: Maybe 94 | createdAt?: Maybe 95 | email?: Maybe 96 | firstName?: Maybe 97 | id?: Maybe 98 | lastName?: Maybe 99 | location?: Maybe 100 | phone?: Maybe 101 | role?: Maybe 102 | updatedAt?: Maybe 103 | username?: Maybe 104 | } 105 | 106 | export type UserToken = { 107 | __typename?: 'UserToken' 108 | /** JWT Bearer token */ 109 | token: Scalars['String'] 110 | user: User 111 | } 112 | 113 | export type UserTokenDetailsFragment = { __typename?: 'UserToken' } & Pick & { 114 | user: { __typename?: 'User' } & UserDetailsFragment 115 | } 116 | 117 | export type UserDetailsFragment = { __typename?: 'User' } & Pick< 118 | User, 119 | 'id' | 'firstName' | 'lastName' | 'username' | 'avatarUrl' | 'email' 120 | > 121 | 122 | export type MeQueryVariables = Exact<{ [key: string]: never }> 123 | 124 | export type MeQuery = { __typename?: 'Query' } & { 125 | me?: Maybe<{ __typename?: 'User' } & UserDetailsFragment> 126 | } 127 | 128 | export type LogoutMutationVariables = Exact<{ [key: string]: never }> 129 | 130 | export type LogoutMutation = { __typename?: 'Mutation' } & Pick 131 | 132 | export type LoginMutationVariables = Exact<{ 133 | input: LoginInput 134 | }> 135 | 136 | export type LoginMutation = { __typename?: 'Mutation' } & { 137 | login?: Maybe<{ __typename?: 'UserToken' } & UserTokenDetailsFragment> 138 | } 139 | 140 | export type RegisterMutationVariables = Exact<{ 141 | input: RegisterInput 142 | }> 143 | 144 | export type RegisterMutation = { __typename?: 'Mutation' } & { 145 | register?: Maybe<{ __typename?: 'UserToken' } & UserTokenDetailsFragment> 146 | } 147 | 148 | export type UptimeQueryVariables = Exact<{ [key: string]: never }> 149 | 150 | export type UptimeQuery = { __typename?: 'Query' } & Pick 151 | 152 | export type IntercomDetailsFragment = { __typename?: 'IntercomMessage' } & Pick< 153 | IntercomMessage, 154 | 'type' | 'scope' | 'payload' 155 | > 156 | 157 | export type IntercomPubMutationVariables = Exact<{ 158 | type: Scalars['String'] 159 | scope?: Maybe 160 | payload?: Maybe 161 | }> 162 | 163 | export type IntercomPubMutation = { __typename?: 'Mutation' } & { 164 | intercomPub?: Maybe<{ __typename?: 'IntercomMessage' } & IntercomDetailsFragment> 165 | } 166 | 167 | export type IntercomSubSubscriptionVariables = Exact<{ [key: string]: never }> 168 | 169 | export type IntercomSubSubscription = { __typename?: 'Subscription' } & { 170 | intercomSub?: Maybe<{ __typename?: 'IntercomMessage' } & IntercomDetailsFragment> 171 | } 172 | 173 | export const UserDetailsFragmentDoc = gql` 174 | fragment UserDetails on User { 175 | id 176 | firstName 177 | lastName 178 | username 179 | avatarUrl 180 | email 181 | } 182 | ` 183 | export const UserTokenDetailsFragmentDoc = gql` 184 | fragment UserTokenDetails on UserToken { 185 | token 186 | user { 187 | ...UserDetails 188 | } 189 | } 190 | ${UserDetailsFragmentDoc} 191 | ` 192 | export const IntercomDetailsFragmentDoc = gql` 193 | fragment IntercomDetails on IntercomMessage { 194 | type 195 | scope 196 | payload 197 | } 198 | ` 199 | export const MeDocument = gql` 200 | query me { 201 | me { 202 | ...UserDetails 203 | } 204 | } 205 | ${UserDetailsFragmentDoc} 206 | ` 207 | 208 | @Injectable({ 209 | providedIn: 'root', 210 | }) 211 | export class MeGQL extends Apollo.Query { 212 | document = MeDocument 213 | 214 | constructor(apollo: Apollo.Apollo) { 215 | super(apollo) 216 | } 217 | } 218 | export const LogoutDocument = gql` 219 | mutation Logout { 220 | logout 221 | } 222 | ` 223 | 224 | @Injectable({ 225 | providedIn: 'root', 226 | }) 227 | export class LogoutGQL extends Apollo.Mutation { 228 | document = LogoutDocument 229 | 230 | constructor(apollo: Apollo.Apollo) { 231 | super(apollo) 232 | } 233 | } 234 | export const LoginDocument = gql` 235 | mutation Login($input: LoginInput!) { 236 | login(input: $input) { 237 | ...UserTokenDetails 238 | } 239 | } 240 | ${UserTokenDetailsFragmentDoc} 241 | ` 242 | 243 | @Injectable({ 244 | providedIn: 'root', 245 | }) 246 | export class LoginGQL extends Apollo.Mutation { 247 | document = LoginDocument 248 | 249 | constructor(apollo: Apollo.Apollo) { 250 | super(apollo) 251 | } 252 | } 253 | export const RegisterDocument = gql` 254 | mutation Register($input: RegisterInput!) { 255 | register(input: $input) { 256 | ...UserTokenDetails 257 | } 258 | } 259 | ${UserTokenDetailsFragmentDoc} 260 | ` 261 | 262 | @Injectable({ 263 | providedIn: 'root', 264 | }) 265 | export class RegisterGQL extends Apollo.Mutation { 266 | document = RegisterDocument 267 | 268 | constructor(apollo: Apollo.Apollo) { 269 | super(apollo) 270 | } 271 | } 272 | export const UptimeDocument = gql` 273 | query Uptime { 274 | uptime 275 | } 276 | ` 277 | 278 | @Injectable({ 279 | providedIn: 'root', 280 | }) 281 | export class UptimeGQL extends Apollo.Query { 282 | document = UptimeDocument 283 | 284 | constructor(apollo: Apollo.Apollo) { 285 | super(apollo) 286 | } 287 | } 288 | export const IntercomPubDocument = gql` 289 | mutation IntercomPub($type: String!, $scope: String, $payload: JSON) { 290 | intercomPub(type: $type, scope: $scope, payload: $payload) { 291 | ...IntercomDetails 292 | } 293 | } 294 | ${IntercomDetailsFragmentDoc} 295 | ` 296 | 297 | @Injectable({ 298 | providedIn: 'root', 299 | }) 300 | export class IntercomPubGQL extends Apollo.Mutation { 301 | document = IntercomPubDocument 302 | 303 | constructor(apollo: Apollo.Apollo) { 304 | super(apollo) 305 | } 306 | } 307 | export const IntercomSubDocument = gql` 308 | subscription IntercomSub { 309 | intercomSub { 310 | ...IntercomDetails 311 | } 312 | } 313 | ${IntercomDetailsFragmentDoc} 314 | ` 315 | 316 | @Injectable({ 317 | providedIn: 'root', 318 | }) 319 | export class IntercomSubGQL extends Apollo.Subscription { 320 | document = IntercomSubDocument 321 | 322 | constructor(apollo: Apollo.Apollo) { 323 | super(apollo) 324 | } 325 | } 326 | 327 | type Omit = Pick> 328 | 329 | interface WatchQueryOptionsAlone extends Omit, 'query' | 'variables'> {} 330 | 331 | interface QueryOptionsAlone extends Omit, 'query' | 'variables'> {} 332 | 333 | interface MutationOptionsAlone extends Omit, 'mutation' | 'variables'> {} 334 | 335 | interface SubscriptionOptionsAlone extends Omit, 'query' | 'variables'> {} 336 | 337 | @Injectable({ providedIn: 'root' }) 338 | export class ApolloAngularSDK { 339 | constructor( 340 | private meGql: MeGQL, 341 | private logoutGql: LogoutGQL, 342 | private loginGql: LoginGQL, 343 | private registerGql: RegisterGQL, 344 | private uptimeGql: UptimeGQL, 345 | private intercomPubGql: IntercomPubGQL, 346 | private intercomSubGql: IntercomSubGQL, 347 | ) {} 348 | 349 | me(variables?: MeQueryVariables, options?: QueryOptionsAlone) { 350 | return this.meGql.fetch(variables, options) 351 | } 352 | 353 | meWatch(variables?: MeQueryVariables, options?: WatchQueryOptionsAlone) { 354 | return this.meGql.watch(variables, options) 355 | } 356 | 357 | logout(variables?: LogoutMutationVariables, options?: MutationOptionsAlone) { 358 | return this.logoutGql.mutate(variables, options) 359 | } 360 | 361 | login(variables: LoginMutationVariables, options?: MutationOptionsAlone) { 362 | return this.loginGql.mutate(variables, options) 363 | } 364 | 365 | register( 366 | variables: RegisterMutationVariables, 367 | options?: MutationOptionsAlone, 368 | ) { 369 | return this.registerGql.mutate(variables, options) 370 | } 371 | 372 | uptime(variables?: UptimeQueryVariables, options?: QueryOptionsAlone) { 373 | return this.uptimeGql.fetch(variables, options) 374 | } 375 | 376 | uptimeWatch(variables?: UptimeQueryVariables, options?: WatchQueryOptionsAlone) { 377 | return this.uptimeGql.watch(variables, options) 378 | } 379 | 380 | intercomPub( 381 | variables: IntercomPubMutationVariables, 382 | options?: MutationOptionsAlone, 383 | ) { 384 | return this.intercomPubGql.mutate(variables, options) 385 | } 386 | 387 | intercomSub( 388 | variables?: IntercomSubSubscriptionVariables, 389 | options?: SubscriptionOptionsAlone, 390 | ) { 391 | return this.intercomSubGql.subscribe(variables, options) 392 | } 393 | } 394 | --------------------------------------------------------------------------------