From 3bdefd6e04c2cf3dbf794a56d0d3a77175b54e8e Mon Sep 17 00:00:00 2001 From: pagarevijayy Date: Thu, 18 Mar 2021 00:18:27 +0530 Subject: [PATCH 1/4] added: base-provider(REST + GraphQL), interceptor [error handler] --- package-lock.json | 199 +++++++++++++++++- package.json | 5 +- src/app/app.module.ts | 23 +- src/app/graphql.module.ts | 24 +++ .../base-provider.service.spec.ts | 16 ++ .../base-provider/base-provider.service.ts | 43 ++++ src/app/services/index.ts | 4 +- .../interceptor/interceptor.service.spec.ts | 16 ++ .../interceptor/interceptor.service.ts | 39 ++++ tsconfig.json | 15 +- 10 files changed, 358 insertions(+), 26 deletions(-) create mode 100644 src/app/graphql.module.ts create mode 100644 src/app/services/base-provider/base-provider.service.spec.ts create mode 100644 src/app/services/base-provider/base-provider.service.ts create mode 100644 src/app/services/interceptor/interceptor.service.spec.ts create mode 100644 src/app/services/interceptor/interceptor.service.ts diff --git a/package-lock.json b/package-lock.json index a7a08ec..7540e82 100644 --- a/package-lock.json +++ b/package-lock.json @@ -562,6 +562,38 @@ "tslib": "^2.0.0" } }, + "@apollo/client": { + "version": "3.3.12", + "resolved": "https://registry.npmjs.org/@apollo/client/-/client-3.3.12.tgz", + "integrity": "sha512-1wLVqRpujzbLRWmFPnRCDK65xapOe2txY0sTI+BaqEbumMUVNS3vxojT6hRHf9ODFEK+F6MLrud2HGx0mB3eQw==", + "requires": { + "@graphql-typed-document-node/core": "^3.0.0", + "@types/zen-observable": "^0.8.0", + "@wry/context": "^0.5.2", + "@wry/equality": "^0.3.0", + "fast-json-stable-stringify": "^2.0.0", + "graphql-tag": "^2.12.0", + "hoist-non-react-statics": "^3.3.2", + "optimism": "^0.14.0", + "prop-types": "^15.7.2", + "symbol-observable": "^2.0.0", + "ts-invariant": "^0.6.2", + "tslib": "^1.10.0", + "zen-observable": "^0.8.14" + }, + "dependencies": { + "symbol-observable": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-2.0.3.tgz", + "integrity": "sha512-sQV7phh2WCYAn81oAkakC5qjq2Ml0g8ozqz03wOGnx9dDlG1de6yrF+0RAzSJD8fPUow3PTSMf2SAbOGxb93BA==" + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + } + } + }, "@babel/code-frame": { "version": "7.12.11", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", @@ -1648,6 +1680,11 @@ "to-fast-properties": "^2.0.0" } }, + "@graphql-typed-document-node/core": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@graphql-typed-document-node/core/-/core-3.1.0.tgz", + "integrity": "sha512-wYn6r8zVZyQJ6rQaALBEln5B1pzxb9shV5Ef97kTvn6yVGrqyXVnDqnU24MXnFubR+rZjBY9NWuxX3FB2sTsjg==" + }, "@istanbuljs/schema": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.2.tgz", @@ -1809,6 +1846,11 @@ "integrity": "sha512-K5K+yml8LTo9bWJI/rECfIPrGgxdpeNbj+d53lwN4QjW1MCwlkhUms+gtdzigTeUyBr09+u8BwOIY3MXvHdcsA==", "dev": true }, + "@types/ungap__global-this": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@types/ungap__global-this/-/ungap__global-this-0.3.1.tgz", + "integrity": "sha512-+/DsiV4CxXl6ZWefwHZDXSe1Slitz21tom38qPCaG0DYCS1NnDPIQDTKcmQ/tvK/edJUKkmuIDBJbmKDiB0r/g==" + }, "@types/webpack-sources": { "version": "0.1.8", "resolved": "https://registry.npmjs.org/@types/webpack-sources/-/webpack-sources-0.1.8.tgz", @@ -1828,6 +1870,16 @@ } } }, + "@types/zen-observable": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/@types/zen-observable/-/zen-observable-0.8.2.tgz", + "integrity": "sha512-HrCIVMLjE1MOozVoD86622S7aunluLb2PJdPfb3nYiEtohm8mIB/vyv0Fd37AdeMFrTUQXEunw78YloMA3Qilg==" + }, + "@ungap/global-this": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/@ungap/global-this/-/global-this-0.4.4.tgz", + "integrity": "sha512-mHkm6FvepJECMNthFuIgpAEFmPOk71UyXuIxYfjytvFTnSDBIz7jmViO+LfHI/AjrazWije0PnSP3+/NlwzqtA==" + }, "@webassemblyjs/ast": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.9.0.tgz", @@ -2003,6 +2055,51 @@ "@xtuc/long": "4.2.2" } }, + "@wry/context": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/@wry/context/-/context-0.5.4.tgz", + "integrity": "sha512-/pktJKHUXDr4D6TJqWgudOPJW2Z+Nb+bqk40jufA3uTkLbnCRKdJPiYDIa/c7mfcPH8Hr6O8zjCERpg5Sq04Zg==", + "requires": { + "tslib": "^1.14.1" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + } + } + }, + "@wry/equality": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/@wry/equality/-/equality-0.3.4.tgz", + "integrity": "sha512-1gQQhCPenzxw/1HzLlvSIs/59eBHJf9ZDIussjjZhqNSqQuPKQIzN6SWt4kemvlBPDi7RqMuUa03pId7MAE93g==", + "requires": { + "tslib": "^1.14.1" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + } + } + }, + "@wry/trie": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@wry/trie/-/trie-0.2.2.tgz", + "integrity": "sha512-OxqBB39x6MfHaa2HpMiRMfhuUnQTddD32Ko020eBeJXq87ivX6xnSSnzKHVbA21p7iqBASz8n/07b6W5wW1BVQ==", + "requires": { + "tslib": "^1.14.1" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + } + } + }, "@xtuc/ieee754": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", @@ -2216,6 +2313,16 @@ "picomatch": "^2.0.4" } }, + "apollo-angular": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/apollo-angular/-/apollo-angular-2.4.0.tgz", + "integrity": "sha512-pgxd+3el59T/KAwkNzHTLxlwh+aHBQqtJqnAk91DBiBP6LILlTC1VwOkBhJ4KjYcdsDAgA0Usq4sezyAwxbnLw==", + "requires": { + "extract-files": "^9.0.0", + "semver": "^7.0.0", + "tslib": "^2.0.0" + } + }, "app-root-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/app-root-path/-/app-root-path-3.0.0.tgz", @@ -5024,6 +5131,11 @@ } } }, + "extract-files": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/extract-files/-/extract-files-9.0.0.tgz", + "integrity": "sha512-CvdFfHkC95B4bBBk36hcEmvdR2awOdhhVUYH6S/zrVj3477zven/fJMYg7121h4T1xHZC+tetUpubpAhxwI7hQ==" + }, "extsprintf": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", @@ -5053,8 +5165,7 @@ "fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" }, "fastparse": { "version": "1.1.2", @@ -5455,6 +5566,26 @@ "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", "dev": true }, + "graphql": { + "version": "15.5.0", + "resolved": "https://registry.npmjs.org/graphql/-/graphql-15.5.0.tgz", + "integrity": "sha512-OmaM7y0kaK31NKG31q4YbD2beNYa6jBBKtMFT6gLYJljHLJr42IqJ8KX08u3Li/0ifzTU5HjmoOOrwa5BRLeDA==" + }, + "graphql-tag": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/graphql-tag/-/graphql-tag-2.12.1.tgz", + "integrity": "sha512-LPewEE1vzGkHnCO8zdOGogKsHHBdtpGyihow1UuMwp6RnZa0lAS7NcbvltLOuo4pi5diQCPASAXZkQq44ffixA==", + "requires": { + "tslib": "^1.14.1" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + } + } + }, "handle-thing": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", @@ -5639,6 +5770,14 @@ "minimalistic-crypto-utils": "^1.0.1" } }, + "hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "requires": { + "react-is": "^16.7.0" + } + }, "hosted-git-info": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-3.0.7.tgz", @@ -6739,8 +6878,7 @@ "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" }, "js-yaml": { "version": "3.14.1", @@ -7344,7 +7482,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dev": true, "requires": { "js-tokens": "^3.0.0 || ^4.0.0" } @@ -8172,8 +8309,7 @@ "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "dev": true + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" }, "object-copy": { "version": "0.1.0", @@ -8353,6 +8489,15 @@ } } }, + "optimism": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/optimism/-/optimism-0.14.1.tgz", + "integrity": "sha512-7+1lSN+LJEtaj3uBLLFk8uFCFKy3txLvcvln5Dh1szXjF9yghEMeWclmnk0qdtYZ+lcMNyu48RmQQRw+LRYKSQ==", + "requires": { + "@wry/context": "^0.5.2", + "@wry/trie": "^0.2.1" + } + }, "ora": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/ora/-/ora-5.0.0.tgz", @@ -9592,6 +9737,16 @@ } } }, + "prop-types": { + "version": "15.7.2", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", + "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", + "requires": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.8.1" + } + }, "protoduck": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/protoduck/-/protoduck-5.0.1.tgz", @@ -10150,6 +10305,11 @@ "schema-utils": "^2.6.5" } }, + "react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, "read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", @@ -10780,8 +10940,7 @@ "semver": { "version": "7.3.2", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", - "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", - "dev": true + "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==" }, "semver-dsl": { "version": "1.0.1", @@ -12121,6 +12280,23 @@ "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", "dev": true }, + "ts-invariant": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/ts-invariant/-/ts-invariant-0.6.2.tgz", + "integrity": "sha512-hsVurayufl1gXg8CHtgZkB7X0KtA3TrI3xcJ9xkRr8FeJHnM/TIEQkgBq9XkpduyBWWUdlRIR9xWf4Lxq3LJTg==", + "requires": { + "@types/ungap__global-this": "^0.3.1", + "@ungap/global-this": "^0.4.2", + "tslib": "^1.9.3" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + } + } + }, "ts-node": { "version": "8.3.0", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.3.0.tgz", @@ -13725,6 +13901,11 @@ "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "dev": true }, + "zen-observable": { + "version": "0.8.15", + "resolved": "https://registry.npmjs.org/zen-observable/-/zen-observable-0.8.15.tgz", + "integrity": "sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ==" + }, "zone.js": { "version": "0.10.3", "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.10.3.tgz", diff --git a/package.json b/package.json index fae39c1..a2b4efb 100644 --- a/package.json +++ b/package.json @@ -22,11 +22,14 @@ "@angular/platform-browser": "~10.1.1", "@angular/platform-browser-dynamic": "~10.1.1", "@angular/router": "~10.1.1", + "apollo-angular": "^2.4.0", "bootstrap": "^4.5.3", "jquery": "^3.5.1", "rxjs": "~6.6.0", "tslib": "^2.0.0", - "zone.js": "~0.10.2" + "zone.js": "~0.10.2", + "@apollo/client": "^3.0.0", + "graphql": "^15.0.0" }, "devDependencies": { "@angular-devkit/build-angular": "~0.1001.1", diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 29ae8d0..c735253 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -4,6 +4,7 @@ import { NgModule } from '@angular/core'; import { AppRoutingModule } from './app-routing.module'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { CommonModule } from '@angular/common'; +import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http'; // material import { LayoutModule } from '@angular/cdk/layout'; @@ -12,10 +13,10 @@ import { MatButtonModule } from '@angular/material/button'; import { MatSidenavModule } from '@angular/material/sidenav'; import { MatIconModule } from '@angular/material/icon'; import { MatListModule } from '@angular/material/list'; -import {MatFormFieldModule} from '@angular/material/form-field'; -import {MatSelectModule} from '@angular/material/select'; -import {MatCardModule} from '@angular/material/card'; -import {MatProgressSpinnerModule} from '@angular/material/progress-spinner'; +import { MatFormFieldModule } from '@angular/material/form-field'; +import { MatSelectModule } from '@angular/material/select'; +import { MatCardModule } from '@angular/material/card'; +import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; // components import { AppComponent } from './app.component'; @@ -24,6 +25,8 @@ import { HomepageComponent } from './components/homepage/homepage.component'; import { ProductsComponent } from './components/products/products.component'; import { ProductDetailsComponent } from './components/product-details/product-details.component'; import { ProductCardComponent } from './components/utils/product-card/product-card.component'; +import { InterceptorService } from './services'; +import { GraphQLModule } from './graphql.module'; @NgModule({ declarations: [ @@ -38,6 +41,7 @@ import { ProductCardComponent } from './components/utils/product-card/product-ca BrowserModule, AppRoutingModule, BrowserAnimationsModule, + HttpClientModule, CommonModule, LayoutModule, MatToolbarModule, @@ -48,9 +52,16 @@ import { ProductCardComponent } from './components/utils/product-card/product-ca MatFormFieldModule, MatSelectModule, MatCardModule, - MatProgressSpinnerModule + MatProgressSpinnerModule, + GraphQLModule + ], + providers: [ + { + provide: HTTP_INTERCEPTORS, + useClass: InterceptorService, + multi: true + } ], - providers: [], bootstrap: [AppComponent] }) export class AppModule { } diff --git a/src/app/graphql.module.ts b/src/app/graphql.module.ts new file mode 100644 index 0000000..762d6cc --- /dev/null +++ b/src/app/graphql.module.ts @@ -0,0 +1,24 @@ +import { NgModule } from '@angular/core'; +import { APOLLO_OPTIONS } from 'apollo-angular'; +import { ApolloClientOptions, InMemoryCache } from '@apollo/client/core'; +import { HttpLink } from 'apollo-angular/http'; + +const uri = '/graphql'; // <-- add the URL of the GraphQL server here + +export function createApollo(httpLink: HttpLink): ApolloClientOptions { + return { + link: httpLink.create({ uri }), + cache: new InMemoryCache(), + }; +} + +@NgModule({ + providers: [ + { + provide: APOLLO_OPTIONS, + useFactory: createApollo, + deps: [HttpLink], + }, + ], +}) +export class GraphQLModule { } diff --git a/src/app/services/base-provider/base-provider.service.spec.ts b/src/app/services/base-provider/base-provider.service.spec.ts new file mode 100644 index 0000000..e9de040 --- /dev/null +++ b/src/app/services/base-provider/base-provider.service.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import { BaseProviderService } from './base-provider.service'; + +describe('BaseProviderService', () => { + let service: BaseProviderService; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(BaseProviderService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/src/app/services/base-provider/base-provider.service.ts b/src/app/services/base-provider/base-provider.service.ts new file mode 100644 index 0000000..c7f3bb1 --- /dev/null +++ b/src/app/services/base-provider/base-provider.service.ts @@ -0,0 +1,43 @@ +import { Injectable } from '@angular/core'; +import { HttpClient, HttpResponse } from "@angular/common/http"; +import { Observable } from 'rxjs'; + +import { Apollo } from "apollo-angular"; +import gql from "graphql-tag"; + + +@Injectable({ + providedIn: 'root' +}) +export class BaseProviderService { + + constructor( + private _http: HttpClient, + private _apollo: Apollo + ) { } + + // 1. HTTP REST requests + + // make a GET call + httpGETrequest(urlString: string, httpOptions?: object): Observable<{} | HttpResponse> { + return this._http.get(urlString, httpOptions) + } + + // make a POST call + httpPOSTrequest(urlString: string, requestObject: object, httpOptions?: object): Observable<{} | HttpResponse> { + return this._http.post(urlString, requestObject, httpOptions) + } + + // make a PUT call + httpPUTrequest(urlString: string, requestObject: object, httpOptions?: object): Observable<{} | HttpResponse> { + return this._http.put(urlString, requestObject, httpOptions) + } + + + // 2. GraphQL request + + graphqlRequest(queryObject: object): Observable { + return this._apollo.query({ query: gql` ${queryObject}` }) + } + +} diff --git a/src/app/services/index.ts b/src/app/services/index.ts index 9439740..16a856b 100644 --- a/src/app/services/index.ts +++ b/src/app/services/index.ts @@ -1,2 +1,4 @@ export * from './utils/utils.service'; -export * from './state-management/state-management.service'; \ No newline at end of file +export * from './state-management/state-management.service'; +export * from './interceptor/interceptor.service'; +export * from './base-provider/base-provider.service'; \ No newline at end of file diff --git a/src/app/services/interceptor/interceptor.service.spec.ts b/src/app/services/interceptor/interceptor.service.spec.ts new file mode 100644 index 0000000..fa4d00a --- /dev/null +++ b/src/app/services/interceptor/interceptor.service.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import { InterceptorService } from './interceptor.service'; + +describe('InterceptorService', () => { + let service: InterceptorService; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(InterceptorService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/src/app/services/interceptor/interceptor.service.ts b/src/app/services/interceptor/interceptor.service.ts new file mode 100644 index 0000000..5815e88 --- /dev/null +++ b/src/app/services/interceptor/interceptor.service.ts @@ -0,0 +1,39 @@ +import { HttpErrorResponse, HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { Observable, throwError } from 'rxjs'; +import { catchError, retry } from 'rxjs/operators'; + +@Injectable({ + providedIn: 'root' +}) +export class InterceptorService implements HttpInterceptor { + + constructor() { } + + intercept(request: HttpRequest, next: HttpHandler): Observable> { + return next.handle(request) + .pipe( + retry(3), // retry a failed request up to 3 times + catchError(this.handleError) // then handle the error + ) + } + + handleError(error: HttpErrorResponse) { + if (error.error instanceof ErrorEvent) { + // A client-side or network error occurred. + console.log('this is a client side error'); + console.error('Error:', error.error.message); + } + else { + // The backend returned an unsuccessful response code. + console.log('this is server side error'); + const errorMsg = `Error Code: ${error.status}, Message: ${error.message}`; + console.log(errorMsg); + console.error(`Error body: ${error.error}`); + } + + // Return an observable with a user-facing error message. + return throwError('Something bad happened; please try again later.'); + } + +} diff --git a/tsconfig.json b/tsconfig.json index 0ddbffc..c6dc621 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,4 +1,3 @@ -/* To learn more about this file see: https://angular.io/config/tsconfig. */ { "compileOnSave": false, "compilerOptions": { @@ -15,11 +14,9 @@ "module": "es2020", "lib": [ "es2018", - "dom" - ] - }, - // "angularCompilerOptions": { - // "fullTemplateTypeCheck": true, - // "strictTemplates": true - // } -} + "dom", + "esnext.asynciterable" + ], + "allowSyntheticDefaultImports": true + } +} \ No newline at end of file From c08a040a5cfa229fa154d956c1d7ed8eee1860df Mon Sep 17 00:00:00 2001 From: pagarevijayy Date: Thu, 18 Mar 2021 05:05:49 +0530 Subject: [PATCH 2/4] 1. sortMaxWeight method updated 2. updated gql wrapper 3. using env var 4. started unified service --- src/app/app.component.ts | 42 ++++++++++++++----- .../product-details.component.ts | 4 +- .../components/products/products.component.ts | 2 +- .../product-card/product-card.component.ts | 10 ++--- src/app/graphql.module.ts | 3 +- .../base-provider/base-provider.service.ts | 5 +-- src/app/services/index.ts | 3 +- .../unified-api/unified-api.service.spec.ts | 16 +++++++ .../unified-api/unified-api.service.ts | 38 +++++++++++++++++ src/app/services/utils/utils.service.ts | 4 +- src/environments/environment.prod.ts | 5 ++- src/environments/environment.ts | 5 ++- 12 files changed, 110 insertions(+), 27 deletions(-) create mode 100644 src/app/services/unified-api/unified-api.service.spec.ts create mode 100644 src/app/services/unified-api/unified-api.service.ts diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 648615c..7f9d11c 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -1,7 +1,7 @@ import { Component, OnInit } from '@angular/core'; import { Title } from '@angular/platform-browser'; import { browserData, ProductInformation } from 'src/assets/data/inbrowser-data' -import { StateManagementService, UtilsService } from './services'; +import { StateManagementService, UnifiedApiService, UtilsService } from './services'; @Component({ selector: 'app-root', @@ -19,7 +19,8 @@ export class AppComponent implements OnInit { constructor( private _utilService: UtilsService, private _stateManagementService: StateManagementService, - private _titleService: Title + private _titleService: Title, + private _unifiedService: UnifiedApiService ) { } ngOnInit(): void { @@ -34,11 +35,11 @@ export class AppComponent implements OnInit { this.homepageItems = await this.getHomepageData(); // sort the category data as per its weightage - this._utilService.sortWeightageMaximum(this.homepageItems, 'weightage'); + this.homepageItems = this._utilService.sortWeightageMaximum(this.homepageItems, 'weightage'); // assign the data to a BS [also store in session storage] this._stateManagementService.updateHomepageItems(this.homepageItems, 'homepageItems'); - + } // actual async request @@ -46,17 +47,36 @@ export class AppComponent implements OnInit { return new Promise((resolve, reject) => { // actual http api-call here [async] - setTimeout(() => { - const dataPlaceholder = ProductInformation?.productCategories; - resolve(dataPlaceholder); - }, 2000) + this._unifiedService.graphqlGetHomepageData().subscribe((gqlResponse: any) => { + console.log('graphql data:', gqlResponse); + console.log('graphql data length:', gqlResponse?.data?.productCategories?.length); + + + if (gqlResponse?.data?.productCategories && gqlResponse?.data?.productCategories?.length > 0) { + const categoryData = gqlResponse?.data?.productCategories; + resolve(categoryData); + } + + //else some error condition + // @todo: handle it later + + }, (error) => { + // @todo: do a better error handling + console.log('graphql error:', error); + }) + + // In-browser data: + // setTimeout(() => { + // const dataPlaceholder = ProductInformation?.productCategories; + // resolve(dataPlaceholder); + // }, 2000) }); } getProjectFooterText() { // @todo: move this kinda stuff into data service. - + const currentYear = new Date().getFullYear(); const copyrightSymbol = browserData?.footerContent?.copyright; const copyrightClaimName = browserData?.footerContent?.claimName; @@ -66,13 +86,13 @@ export class AppComponent implements OnInit { } setIndexHtmlHeaderElements() { - + // set title const newTitle = browserData?.storeInformation?.storeName; this._titleService.setTitle(newTitle); //set favicon [use either url or emoji svg] - const faviconURL = browserData?.storeInformation?.faviconURL; + const faviconURL = browserData?.storeInformation?.faviconURL; this.favIcon.href = faviconURL; } } diff --git a/src/app/components/product-details/product-details.component.ts b/src/app/components/product-details/product-details.component.ts index defa2b1..f20562c 100644 --- a/src/app/components/product-details/product-details.component.ts +++ b/src/app/components/product-details/product-details.component.ts @@ -66,8 +66,8 @@ export class ProductDetailsComponent implements OnInit { this.productQtyPrice = productData?.QtyPrice; this.productSubcategoryLabel = productData?.product_subcategory?.subcategoryLabel; - this._utilService.sortWeightageMaximum(this.productQtyPrice, 'weightage'); - this._utilService.sortWeightageMaximum(this.productImageURL, 'weightage'); + this.productQtyPrice = this._utilService.sortWeightageMaximum(this.productQtyPrice, 'weightage'); + this.productImageURL = this._utilService.sortWeightageMaximum(this.productImageURL, 'weightage'); // @fix later: this arrray[0] will give error if array is undefined/null this.currentProductQuantityApplied = this.productQtyPrice[0]?.qty; diff --git a/src/app/components/products/products.component.ts b/src/app/components/products/products.component.ts index 9891e4b..45af1d1 100644 --- a/src/app/components/products/products.component.ts +++ b/src/app/components/products/products.component.ts @@ -72,7 +72,7 @@ export class ProductsComponent implements OnInit, OnDestroy { // sort the subcategory data as per its weightage - this._utilService.sortWeightageMaximum(this.currentSubcategoryInfo, 'subcategoryWeightage'); + this.currentSubcategoryInfo = this._utilService.sortWeightageMaximum(this.currentSubcategoryInfo, 'subcategoryWeightage'); // assign default drop-down value [available slug or max weight subcategory] (!!this.activeSubcategorySlug) ? this.currentSubcategoryValue = this.activeSubcategorySlug : this.currentSubcategoryValue = this.currentSubcategoryInfo[0]?.subcategorySlug; diff --git a/src/app/components/utils/product-card/product-card.component.ts b/src/app/components/utils/product-card/product-card.component.ts index 76ad433..20c3297 100644 --- a/src/app/components/utils/product-card/product-card.component.ts +++ b/src/app/components/utils/product-card/product-card.component.ts @@ -41,16 +41,16 @@ export class ProductCardComponent implements OnInit { this.activeProductSlug = this.productDetail?.productSlug; // sort the price-quantity and image url data as per its weightage - this._utilService.sortWeightageMaximum(this.productDetail?.QtyPrice, 'weightage'); - this._utilService.sortWeightageMaximum(this.productDetail?.ImageUrl, 'weightage'); + let productDetailQtyPrice = this._utilService.sortWeightageMaximum(this.productDetail?.QtyPrice, 'weightage'); + let productDetailImageUrl = this._utilService.sortWeightageMaximum(this.productDetail?.ImageUrl, 'weightage'); // price and image data - this.productPrice = this.productDetail?.QtyPrice[0]?.price; - this.productImageURL = this.productDetail?.ImageUrl[0]?.imgURL; + this.productPrice = productDetailQtyPrice[0]?.price; + this.productImageURL = productDetailImageUrl[0]?.imgURL; } navigateProductDetailsPage() { - + const routeURL = `products/${this.currentCategoryRoute}/${this.currentSubcategorySlug}/${this.activeProductSlug}` this._utilService.navigationRoute(routeURL); } diff --git a/src/app/graphql.module.ts b/src/app/graphql.module.ts index 762d6cc..9397f9d 100644 --- a/src/app/graphql.module.ts +++ b/src/app/graphql.module.ts @@ -2,8 +2,9 @@ import { NgModule } from '@angular/core'; import { APOLLO_OPTIONS } from 'apollo-angular'; import { ApolloClientOptions, InMemoryCache } from '@apollo/client/core'; import { HttpLink } from 'apollo-angular/http'; +import { environment } from './../environments/environment'; -const uri = '/graphql'; // <-- add the URL of the GraphQL server here +const uri = `${environment.baseURL}/${environment.graphqlEndpoint}`; // <-- add the URL of the GraphQL server here export function createApollo(httpLink: HttpLink): ApolloClientOptions { return { diff --git a/src/app/services/base-provider/base-provider.service.ts b/src/app/services/base-provider/base-provider.service.ts index c7f3bb1..726fe38 100644 --- a/src/app/services/base-provider/base-provider.service.ts +++ b/src/app/services/base-provider/base-provider.service.ts @@ -3,7 +3,6 @@ import { HttpClient, HttpResponse } from "@angular/common/http"; import { Observable } from 'rxjs'; import { Apollo } from "apollo-angular"; -import gql from "graphql-tag"; @Injectable({ @@ -36,8 +35,8 @@ export class BaseProviderService { // 2. GraphQL request - graphqlRequest(queryObject: object): Observable { - return this._apollo.query({ query: gql` ${queryObject}` }) + graphqlRequest(queryObject: any): Observable { + return this._apollo.query(queryObject) } } diff --git a/src/app/services/index.ts b/src/app/services/index.ts index 16a856b..5a51a93 100644 --- a/src/app/services/index.ts +++ b/src/app/services/index.ts @@ -1,4 +1,5 @@ export * from './utils/utils.service'; export * from './state-management/state-management.service'; export * from './interceptor/interceptor.service'; -export * from './base-provider/base-provider.service'; \ No newline at end of file +export * from './base-provider/base-provider.service'; +export * from './unified-api/unified-api.service'; diff --git a/src/app/services/unified-api/unified-api.service.spec.ts b/src/app/services/unified-api/unified-api.service.spec.ts new file mode 100644 index 0000000..ceb4ea0 --- /dev/null +++ b/src/app/services/unified-api/unified-api.service.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import { UnifiedApiService } from './unified-api.service'; + +describe('UnifiedApiService', () => { + let service: UnifiedApiService; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(UnifiedApiService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/src/app/services/unified-api/unified-api.service.ts b/src/app/services/unified-api/unified-api.service.ts new file mode 100644 index 0000000..1179b4a --- /dev/null +++ b/src/app/services/unified-api/unified-api.service.ts @@ -0,0 +1,38 @@ +import gql from "graphql-tag"; +import { Injectable } from '@angular/core'; +import { BaseProviderService } from '../base-provider/base-provider.service'; + + +@Injectable({ + providedIn: 'root' +}) +export class UnifiedApiService { + + // REST and GraphQL backend server calls for data using base-provider + + constructor( + private _baseProviderService: BaseProviderService + ) { } + + graphqlGetHomepageData() { + const queryObject = { + query: gql` + { + productCategories { + categoryLabel + route + displayTitle + weightage + product_subcategories{ + subcategoryLabel + displayPictureUrl + subcategorySlug + weightage + } + } + }` + } + + return this._baseProviderService.graphqlRequest(queryObject) + } +} diff --git a/src/app/services/utils/utils.service.ts b/src/app/services/utils/utils.service.ts index 91c1a2f..2976bfa 100644 --- a/src/app/services/utils/utils.service.ts +++ b/src/app/services/utils/utils.service.ts @@ -24,7 +24,9 @@ export class UtilsService { // sort an array according to maximum weightage sortWeightageMaximum( sortDataArray: Array, comparisionKeyLabel: string){ if (sortDataArray?.length > 1) - return sortDataArray.sort((firstElement, secondElement) => secondElement[comparisionKeyLabel] - firstElement[comparisionKeyLabel]); + return sortDataArray.slice().sort((firstElement, secondElement) => secondElement[comparisionKeyLabel] - firstElement[comparisionKeyLabel]); + else + return sortDataArray.slice(); } // encrypt and set data into session storage diff --git a/src/environments/environment.prod.ts b/src/environments/environment.prod.ts index 3612073..32eb7cc 100644 --- a/src/environments/environment.prod.ts +++ b/src/environments/environment.prod.ts @@ -1,3 +1,6 @@ export const environment = { - production: true + production: true, + baseURL: `https://ecom-backend-eragap.herokuapp.com`, + graphqlEndpoint: `graphql` + }; diff --git a/src/environments/environment.ts b/src/environments/environment.ts index 7b4f817..7508fb5 100644 --- a/src/environments/environment.ts +++ b/src/environments/environment.ts @@ -3,7 +3,10 @@ // The list of file replacements can be found in `angular.json`. export const environment = { - production: false + production: false, + baseURL: `http://localhost:1337`, + graphqlEndpoint: `graphql` + }; /* From ce165921244e6eabca76264774583b77adceb8ef Mon Sep 17 00:00:00 2001 From: pagarevijayy Date: Thu, 18 Mar 2021 05:50:15 +0530 Subject: [PATCH 3/4] graphql apis integrated --- src/app/app.component.ts | 10 +-- .../product-details.component.ts | 30 ++++++-- .../components/products/products.component.ts | 25 ++++-- .../unified-api/unified-api.service.ts | 76 +++++++++++++++++++ 4 files changed, 122 insertions(+), 19 deletions(-) diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 7f9d11c..326c8f1 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -48,21 +48,17 @@ export class AppComponent implements OnInit { // actual http api-call here [async] this._unifiedService.graphqlGetHomepageData().subscribe((gqlResponse: any) => { - console.log('graphql data:', gqlResponse); - console.log('graphql data length:', gqlResponse?.data?.productCategories?.length); - if (gqlResponse?.data?.productCategories && gqlResponse?.data?.productCategories?.length > 0) { const categoryData = gqlResponse?.data?.productCategories; resolve(categoryData); } - - //else some error condition - // @todo: handle it later + //else + // @todo: some error condition; handle it later }, (error) => { // @todo: do a better error handling - console.log('graphql error:', error); + console.log('graphql error [homepage]:', error); }) // In-browser data: diff --git a/src/app/components/product-details/product-details.component.ts b/src/app/components/product-details/product-details.component.ts index f20562c..11d785c 100644 --- a/src/app/components/product-details/product-details.component.ts +++ b/src/app/components/product-details/product-details.component.ts @@ -1,7 +1,7 @@ import { Component, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { Observable } from 'rxjs'; -import { UtilsService } from 'src/app/services'; +import { UnifiedApiService, UtilsService } from 'src/app/services'; import { browserData, ProductInformation } from 'src/assets/data/inbrowser-data' @Component({ @@ -33,7 +33,8 @@ export class ProductDetailsComponent implements OnInit { constructor( private _route: ActivatedRoute, - private _utilService: UtilsService + private _utilService: UtilsService, + private _unifiedService: UnifiedApiService ) { } ngOnInit(): void { @@ -102,11 +103,26 @@ export class ProductDetailsComponent implements OnInit { getProductDetails(productSlug: string) { return new Promise((resolve, reject) => { // actual http api-call here [async] - - setTimeout(() => { - const dataPlaceholder = ProductInformation?.products[productSlug]; - resolve(dataPlaceholder); - }, 1000) + this._unifiedService.graphqlGetProductDetails(productSlug).subscribe((gqlResponse: any) => { + + if (gqlResponse?.data?.products && gqlResponse?.data?.products?.length > 0) { + const productData = gqlResponse?.data?.products[0]; + resolve(productData); + } + + //else + // @todo: some error condition; handle it later + + }, (error) => { + // @todo: do a better error handling + console.log('graphql error[product subcategory]:', error); + }) + + // in-browser data usage + // setTimeout(() => { + // const dataPlaceholder = ProductInformation?.products[productSlug]; + // resolve(dataPlaceholder); + // }, 1000) }); } diff --git a/src/app/components/products/products.component.ts b/src/app/components/products/products.component.ts index 45af1d1..b1dd9e4 100644 --- a/src/app/components/products/products.component.ts +++ b/src/app/components/products/products.component.ts @@ -1,7 +1,7 @@ import { Component, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; import { Observable, Subscription } from 'rxjs'; -import { StateManagementService, UtilsService } from 'src/app/services'; +import { StateManagementService, UnifiedApiService, UtilsService } from 'src/app/services'; import { browserData, ProductInformation } from 'src/assets/data/inbrowser-data' @Component({ @@ -33,6 +33,7 @@ export class ProductsComponent implements OnInit, OnDestroy { private _router: Router, private _utilService: UtilsService, private _stateManagementService: StateManagementService, + private _unifiedService: UnifiedApiService ) { } ngOnInit(): void { @@ -125,11 +126,25 @@ export class ProductsComponent implements OnInit, OnDestroy { getSubcategoryProductsList(subcategorySlug: string) { return new Promise((resolve, reject) => { // actual http api-call here [async] + this._unifiedService.graphqlGetSubcategoryData(subcategorySlug).subscribe((gqlResponse: any) => { + + if (gqlResponse?.data?.productSubcategories && gqlResponse?.data?.productSubcategories?.length > 0) { + const subcategoryData = gqlResponse?.data?.productSubcategories[0]; + resolve(subcategoryData); + } + //else + // @todo: some error condition; handle it later + + }, (error) => { + // @todo: do a better error handling + console.log('graphql error[product subcategory]:', error); + }) - setTimeout(() => { - const dataPlaceholder = ProductInformation?.productSubcategories[subcategorySlug]; - resolve(dataPlaceholder); - }, 1000) + // in-browser data usage + // setTimeout(() => { + // const dataPlaceholder = ProductInformation?.productSubcategories[subcategorySlug]; + // resolve(dataPlaceholder); + // }, 1000) }); } diff --git a/src/app/services/unified-api/unified-api.service.ts b/src/app/services/unified-api/unified-api.service.ts index 1179b4a..ec2f770 100644 --- a/src/app/services/unified-api/unified-api.service.ts +++ b/src/app/services/unified-api/unified-api.service.ts @@ -9,6 +9,7 @@ import { BaseProviderService } from '../base-provider/base-provider.service'; export class UnifiedApiService { // REST and GraphQL backend server calls for data using base-provider + // Currently going live only with graphQL constructor( private _baseProviderService: BaseProviderService @@ -35,4 +36,79 @@ export class UnifiedApiService { return this._baseProviderService.graphqlRequest(queryObject) } + + graphqlGetSubcategoryData(subcategorySlug: string) { + const queryObject = { + query: gql` + { + productSubcategories( + where: { subcategorySlug: "${subcategorySlug}" } + ){ + subcategoryLabel + subcategorySlug + displayPictureUrl + description + weightage + products{ + title + description + productSlug + QtyPrice{ + qty + price + weightage + } + Color{ + colorTitle + colorCode + } + ImageUrl{ + imgURL + weightage + description + } + } + } + }` + } + + return this._baseProviderService.graphqlRequest(queryObject) + } + + graphqlGetProductDetails(productSlug: string) { + const queryObject = { + query: gql` + { + products ( + where: { productSlug: "${productSlug}" } + ){ + title + description + rating + productSlug + product_subcategory{ + subcategoryLabel + } + QtyPrice{ + qty + price + weightage + } + Color{ + colorTitle + colorCode + } + ImageUrl{ + imgURL + weightage + description + } + } + }` + } + + return this._baseProviderService.graphqlRequest(queryObject) + } + + } From 49abc139fa4d4825ece7febf82e55dc940e0ec6d Mon Sep 17 00:00:00 2001 From: pagarevijayy Date: Thu, 18 Mar 2021 06:06:23 +0530 Subject: [PATCH 4/4] in-browser vs api data toggle added --- src/app/app.component.ts | 45 +++++++++-------- .../product-details.component.ts | 50 ++++++++++--------- .../components/products/products.component.ts | 45 +++++++++-------- src/assets/data/inbrowser-data.ts | 1 + 4 files changed, 78 insertions(+), 63 deletions(-) diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 326c8f1..44e194f 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -46,26 +46,31 @@ export class AppComponent implements OnInit { getHomepageData() { return new Promise((resolve, reject) => { // actual http api-call here [async] - - this._unifiedService.graphqlGetHomepageData().subscribe((gqlResponse: any) => { - - if (gqlResponse?.data?.productCategories && gqlResponse?.data?.productCategories?.length > 0) { - const categoryData = gqlResponse?.data?.productCategories; - resolve(categoryData); - } - //else - // @todo: some error condition; handle it later - - }, (error) => { - // @todo: do a better error handling - console.log('graphql error [homepage]:', error); - }) - - // In-browser data: - // setTimeout(() => { - // const dataPlaceholder = ProductInformation?.productCategories; - // resolve(dataPlaceholder); - // }, 2000) + const shouldUseInBrowserData: boolean = !!browserData?.storeInformation?.useInBrowserProductData; + + if (shouldUseInBrowserData) { + // In-browser data: + setTimeout(() => { + const dataPlaceholder = ProductInformation?.productCategories; + resolve(dataPlaceholder); + }, 1000); + + } else { + this._unifiedService.graphqlGetHomepageData().subscribe((gqlResponse: any) => { + + if (gqlResponse?.data?.productCategories && gqlResponse?.data?.productCategories?.length > 0) { + const categoryData = gqlResponse?.data?.productCategories; + resolve(categoryData); + } + //else + // @todo: some error condition; handle it later + + }, (error) => { + // @todo: do a better error handling + console.log('graphql error [homepage]:', error); + }); + + } }); } diff --git a/src/app/components/product-details/product-details.component.ts b/src/app/components/product-details/product-details.component.ts index 11d785c..772dfbc 100644 --- a/src/app/components/product-details/product-details.component.ts +++ b/src/app/components/product-details/product-details.component.ts @@ -12,7 +12,7 @@ import { browserData, ProductInformation } from 'src/assets/data/inbrowser-data' export class ProductDetailsComponent implements OnInit { isHandset$: Observable = this._utilService.isHandset$; isLoading = true; - + productTitle: string; productDescription: string productSubcategoryLabel: string @@ -94,8 +94,8 @@ export class ProductDetailsComponent implements OnInit { const currentURL = location?.href; const whatsappBuyNowMessage = `Hi, I'm interested in buying the product '${this.productTitle}' from the '${this.productSubcategoryLabel}' subcategory. Price: ₹${this.currentProductPriceApplied}. Quantity: ${this.currentProductQuantityApplied} piece(s). The reference URL: ${currentURL}` - - window.open(`https://wa.me/${this.whatsAppContactNumber}?text=${whatsappBuyNowMessage}`, "_blank"); + + window.open(`https://wa.me/${this.whatsAppContactNumber}?text=${whatsappBuyNowMessage}`, "_blank"); } @@ -103,26 +103,30 @@ export class ProductDetailsComponent implements OnInit { getProductDetails(productSlug: string) { return new Promise((resolve, reject) => { // actual http api-call here [async] - this._unifiedService.graphqlGetProductDetails(productSlug).subscribe((gqlResponse: any) => { - - if (gqlResponse?.data?.products && gqlResponse?.data?.products?.length > 0) { - const productData = gqlResponse?.data?.products[0]; - resolve(productData); - } - - //else - // @todo: some error condition; handle it later - - }, (error) => { - // @todo: do a better error handling - console.log('graphql error[product subcategory]:', error); - }) - - // in-browser data usage - // setTimeout(() => { - // const dataPlaceholder = ProductInformation?.products[productSlug]; - // resolve(dataPlaceholder); - // }, 1000) + const shouldUseInBrowserData: boolean = !!browserData?.storeInformation?.useInBrowserProductData; + + if (shouldUseInBrowserData) { + // in-browser data usage + setTimeout(() => { + const dataPlaceholder = ProductInformation?.products[productSlug]; + resolve(dataPlaceholder); + }, 1000) + } else { + this._unifiedService.graphqlGetProductDetails(productSlug).subscribe((gqlResponse: any) => { + + if (gqlResponse?.data?.products && gqlResponse?.data?.products?.length > 0) { + const productData = gqlResponse?.data?.products[0]; + resolve(productData); + } + + //else + // @todo: some error condition; handle it later + + }, (error) => { + // @todo: do a better error handling + console.log('graphql error[product subcategory]:', error); + }) + } }); } diff --git a/src/app/components/products/products.component.ts b/src/app/components/products/products.component.ts index b1dd9e4..6b75252 100644 --- a/src/app/components/products/products.component.ts +++ b/src/app/components/products/products.component.ts @@ -113,7 +113,7 @@ export class ProductsComponent implements OnInit, OnDestroy { // products are available - generate products catlogue view this.isLoading = false; this.productsAvailable = true; - } else if (this.productsCatlogue?.length === 0){ + } else if (this.productsCatlogue?.length === 0) { // products unavailable - generate no product available view this.isLoading = false; this.productsAvailable = false; @@ -126,25 +126,30 @@ export class ProductsComponent implements OnInit, OnDestroy { getSubcategoryProductsList(subcategorySlug: string) { return new Promise((resolve, reject) => { // actual http api-call here [async] - this._unifiedService.graphqlGetSubcategoryData(subcategorySlug).subscribe((gqlResponse: any) => { - - if (gqlResponse?.data?.productSubcategories && gqlResponse?.data?.productSubcategories?.length > 0) { - const subcategoryData = gqlResponse?.data?.productSubcategories[0]; - resolve(subcategoryData); - } - //else - // @todo: some error condition; handle it later - - }, (error) => { - // @todo: do a better error handling - console.log('graphql error[product subcategory]:', error); - }) - - // in-browser data usage - // setTimeout(() => { - // const dataPlaceholder = ProductInformation?.productSubcategories[subcategorySlug]; - // resolve(dataPlaceholder); - // }, 1000) + const shouldUseInBrowserData: boolean = !!browserData?.storeInformation?.useInBrowserProductData; + + if (shouldUseInBrowserData) { + // in-browser data usage + setTimeout(() => { + const dataPlaceholder = ProductInformation?.productSubcategories[subcategorySlug]; + resolve(dataPlaceholder); + }, 1000) + + } else { + this._unifiedService.graphqlGetSubcategoryData(subcategorySlug).subscribe((gqlResponse: any) => { + + if (gqlResponse?.data?.productSubcategories && gqlResponse?.data?.productSubcategories?.length > 0) { + const subcategoryData = gqlResponse?.data?.productSubcategories[0]; + resolve(subcategoryData); + } + //else + // @todo: some error condition; handle it later + + }, (error) => { + // @todo: do a better error handling + console.log('graphql error[product subcategory]:', error); + }) + } }); } diff --git a/src/assets/data/inbrowser-data.ts b/src/assets/data/inbrowser-data.ts index d6e2b50..282cbb0 100644 --- a/src/assets/data/inbrowser-data.ts +++ b/src/assets/data/inbrowser-data.ts @@ -20,6 +20,7 @@ export class browserData { }; static storeInformation = { + useInBrowserProductData: true, storeName: "Eragap Co.", faviconURL: "data:image/svg+xml,🛍️", googleMapsLocationURL: "https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d1883.0353227697742!2d72.85859100051474!3d19.279293798848443!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x3be7b04e2398e9fd%3A0x7f02171ee4cd53d0!2sB-52%2C%20Mira%20Rd%2C%20Sector%201%2C%20Shanti%20Nagar%2C%20Mira%20Road%2C%20Mira%20Bhayandar%2C%20Maharashtra%20401107!5e0!3m2!1sen!2sin!4v1615579587841!5m2!1sen!2sin",