├── 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 |
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 | Remove
10 |
11 |
12 |
13 |
14 | {{ to.addText }}
15 |
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 |
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 |
14 |
15 |
16 |
17 |
18 |
19 |
{{ pageTitle }}
20 |
21 |
22 |
23 |
24 |
25 |
26 | {{ buttonTitle }}
27 |
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 |
31 |
32 |
33 |
34 |
35 |
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 |
17 |
18 |
19 |
20 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
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 |
69 |
70 |
71 |
74 |
75 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
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 |
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 |
12 |
13 |
14 |
17 |
18 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
34 |
35 |
36 |
37 |
38 |
39 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 | Tweet
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
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 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
What’s happening
136 |
137 |
138 |
{{ item.header }} · {{ item.time }}
139 |
140 | {{ item.text }}
141 |
142 |
143 | {{ item.footer }}
144 |
145 |
146 |
147 |
150 |
151 |
152 |
Who to follow
153 |
154 |
155 |
156 |
159 |
160 |
{{ item.name }}
161 |
@{{ item.username }}
162 |
163 |
164 |
165 | Follow
166 |
167 |
168 |
169 |
170 |
171 |
174 |
175 |
180 |
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 |
--------------------------------------------------------------------------------