Compare commits
12 Commits
spencer/ac
...
mono-repo-
| Author | SHA1 | Date | |
|---|---|---|---|
| 4163acfd84 | |||
| 85bd92a2fc | |||
|
|
e79afe3e88 | ||
|
|
473be6b641 | ||
| 742c589835 | |||
| 7ae0413991 | |||
| a4813152ed | |||
|
|
0acb94ce98 | ||
|
|
858e1e65bd | ||
|
|
6298f9a105 | ||
|
|
4ba9f959fe | ||
|
|
a6e80fba64 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -49,4 +49,3 @@ Thumbs.db
|
||||
|
||||
# Configuration Files
|
||||
.env
|
||||
/src/environments/environment.ts
|
||||
|
||||
@@ -13,8 +13,9 @@ RUN npm install
|
||||
|
||||
COPY . .
|
||||
|
||||
ARG FRONTEND_ENV=prod
|
||||
# running build script
|
||||
RUN npm run build:dev
|
||||
RUN npm run build:${FRONTEND_ENV}
|
||||
|
||||
### STAGE 2: Setup ###
|
||||
# defining nginx image version
|
||||
|
||||
30
angular.json
30
angular.json
@@ -24,11 +24,7 @@
|
||||
"polyfills": "src/polyfills.ts",
|
||||
"tsConfig": "tsconfig.app.json",
|
||||
"aot": true,
|
||||
"assets": [
|
||||
"src/favicon.ico",
|
||||
"src/assets",
|
||||
"src/manifest.webmanifest"
|
||||
],
|
||||
"assets": ["src/favicon.ico", "src/assets", "src/manifest.webmanifest"],
|
||||
"styles": [
|
||||
"./node_modules/@angular/material/prebuilt-themes/indigo-pink.css",
|
||||
"src/styles.scss",
|
||||
@@ -37,7 +33,8 @@
|
||||
"scripts": [
|
||||
"node_modules/jquery/dist/jquery.js",
|
||||
"node_modules/bootstrap/dist/js/bootstrap.js"
|
||||
]
|
||||
],
|
||||
"webWorkerTsConfig": "tsconfig.worker.json"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
@@ -77,6 +74,14 @@
|
||||
"with": "src/environments/environment.dev.ts"
|
||||
}
|
||||
]
|
||||
},
|
||||
"staging": {
|
||||
"fileReplacements": [
|
||||
{
|
||||
"replace": "src/environments/environment.ts",
|
||||
"with": "src/environments/environment.staging.ts"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -108,11 +113,7 @@
|
||||
"tsConfig": "tsconfig.spec.json",
|
||||
"karmaConfig": "karma.conf.js",
|
||||
"codeCoverage": true,
|
||||
"assets": [
|
||||
"src/favicon.ico",
|
||||
"src/assets",
|
||||
"src/manifest.webmanifest"
|
||||
],
|
||||
"assets": ["src/favicon.ico", "src/assets", "src/manifest.webmanifest"],
|
||||
"styles": [
|
||||
"./node_modules/@angular/material/prebuilt-themes/indigo-pink.css",
|
||||
"src/styles.scss"
|
||||
@@ -126,11 +127,10 @@
|
||||
"tsConfig": [
|
||||
"tsconfig.app.json",
|
||||
"tsconfig.spec.json",
|
||||
"e2e/tsconfig.json"
|
||||
"e2e/tsconfig.json",
|
||||
"tsconfig.worker.json"
|
||||
],
|
||||
"exclude": [
|
||||
"**/node_modules/**"
|
||||
]
|
||||
"exclude": ["**/node_modules/**"]
|
||||
}
|
||||
},
|
||||
"e2e": {
|
||||
|
||||
29002
package-lock.json
generated
29002
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -74,6 +74,7 @@
|
||||
"karma-jasmine-html-reporter": "^1.5.0",
|
||||
"karma-junit-reporter": "^2.0.1",
|
||||
"lint-staged": "^11.0.0",
|
||||
"openpgp": "^4.10.10",
|
||||
"prettier": "^2.3.1",
|
||||
"pretty-quick": "^3.1.0",
|
||||
"protractor": "~7.0.0",
|
||||
|
||||
@@ -10,3 +10,4 @@ export * from '@app/_helpers/read-csv';
|
||||
export * from '@app/_helpers/schema-validation';
|
||||
export * from '@app/_helpers/sync';
|
||||
export * from '@app/_helpers/online-status';
|
||||
export * from '@app/_helpers/to-hex';
|
||||
|
||||
9
src/app/_helpers/to-hex.ts
Normal file
9
src/app/_helpers/to-hex.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
function asciiToHex(str: string): string {
|
||||
const arr = [];
|
||||
for (let n = 0, l = str.length; n < l; n++) {
|
||||
arr.push(Number(str.charCodeAt(n)).toString(16));
|
||||
}
|
||||
return arr.join('');
|
||||
}
|
||||
|
||||
export { asciiToHex };
|
||||
@@ -176,7 +176,7 @@ export class TransactionService {
|
||||
const hash = hashFunction.digest();
|
||||
const methodSignature = hash.toString('hex').substring(0, 8);
|
||||
const abiCoder = new utils.AbiCoder();
|
||||
const abi = await abiCoder.encode(
|
||||
const abi = abiCoder.encode(
|
||||
['address', 'address', 'address', 'uint256'],
|
||||
[senderAddress, recipientAddress, tokenAddress, value]
|
||||
);
|
||||
|
||||
@@ -11,8 +11,9 @@ import { MutableKeyStore, PGPSigner, Signer } from '@app/_pgp';
|
||||
import { RegistryService } from '@app/_services/registry.service';
|
||||
import { CICRegistry } from '@cicnet/cic-client';
|
||||
import { personValidation, updateSyncable, vcardValidation } from '@app/_helpers';
|
||||
import { add0x } from '@src/assets/js/ethtx/dist/hex';
|
||||
import { add0x, strip0x } from '@src/assets/js/ethtx/dist/hex';
|
||||
import { KeystoreService } from '@app/_services/keystore.service';
|
||||
import * as Automerge from 'automerge';
|
||||
const vCard = require('vcard-parser');
|
||||
|
||||
@Injectable({
|
||||
@@ -38,6 +39,10 @@ export class UserService {
|
||||
private categoriesList: BehaviorSubject<object> = new BehaviorSubject<object>(this.categories);
|
||||
categoriesSubject: Observable<object> = this.categoriesList.asObservable();
|
||||
|
||||
history: Array<any> = [];
|
||||
private historyList: BehaviorSubject<any> = new BehaviorSubject<any>(this.history);
|
||||
historySubject: Observable<Array<any>> = this.historyList.asObservable();
|
||||
|
||||
constructor(
|
||||
private httpClient: HttpClient,
|
||||
private loggingService: LoggingService,
|
||||
@@ -75,49 +80,21 @@ export class UserService {
|
||||
businessCategory: string,
|
||||
userLocation: string,
|
||||
location: string,
|
||||
locationType: string
|
||||
locationType: string,
|
||||
oldPhoneNumber: string
|
||||
): Promise<any> {
|
||||
const accountInfo: any = {
|
||||
vcard: {
|
||||
fn: [{}],
|
||||
n: [{}],
|
||||
tel: [{}],
|
||||
},
|
||||
location: {},
|
||||
};
|
||||
if (name) {
|
||||
accountInfo.vcard.fn[0].value = name;
|
||||
accountInfo.vcard.n[0].value = name.split(' ');
|
||||
}
|
||||
if (phoneNumber) {
|
||||
accountInfo.vcard.tel[0].value = phoneNumber;
|
||||
}
|
||||
if (bio) {
|
||||
accountInfo.products = [bio];
|
||||
}
|
||||
if (gender) {
|
||||
accountInfo.gender = gender;
|
||||
}
|
||||
if (age) {
|
||||
accountInfo.age = age;
|
||||
}
|
||||
if (type) {
|
||||
accountInfo.type = type;
|
||||
}
|
||||
if (businessCategory) {
|
||||
accountInfo.category = businessCategory;
|
||||
}
|
||||
if (location) {
|
||||
accountInfo.location.area = location;
|
||||
}
|
||||
if (userLocation) {
|
||||
accountInfo.location.area_name = userLocation;
|
||||
}
|
||||
if (locationType) {
|
||||
accountInfo.location.area_type = locationType;
|
||||
}
|
||||
await vcardValidation(accountInfo.vcard);
|
||||
accountInfo.vcard = btoa(vCard.generate(accountInfo.vcard));
|
||||
const accountInfo = await this.loadChangesToAccountStructure(
|
||||
name,
|
||||
phoneNumber,
|
||||
age,
|
||||
type,
|
||||
bio,
|
||||
gender,
|
||||
businessCategory,
|
||||
userLocation,
|
||||
location,
|
||||
locationType
|
||||
);
|
||||
const accountKey: string = await User.toKey(address);
|
||||
this.getAccountDetailsFromMeta(accountKey)
|
||||
.pipe(first())
|
||||
@@ -142,6 +119,14 @@ export class UserService {
|
||||
await this.updateMeta(syncableAccount, accountKey, this.headers);
|
||||
}
|
||||
);
|
||||
if (phoneNumber !== oldPhoneNumber) {
|
||||
const oldPhoneKey: string = await Phone.toKey(oldPhoneNumber);
|
||||
const newPhoneKey: string = await Phone.toKey(phoneNumber);
|
||||
const newPhoneData: Syncable = new Syncable(newPhoneKey, strip0x(address));
|
||||
await this.updateMeta(newPhoneData, newPhoneKey, this.headers);
|
||||
const oldPhoneData: Syncable = new Syncable(oldPhoneKey, '');
|
||||
await this.updateMeta(oldPhoneData, oldPhoneKey, this.headers);
|
||||
}
|
||||
return accountKey;
|
||||
}
|
||||
|
||||
@@ -200,10 +185,34 @@ export class UserService {
|
||||
async loadAccounts(limit: number = 100, offset: number = 0): Promise<void> {
|
||||
try {
|
||||
const accountRegistry = await RegistryService.getAccountRegistry();
|
||||
const accountAddresses: Array<string> = await accountRegistry.last(limit);
|
||||
const accountAddresses: Array<string> = await accountRegistry.last(offset + limit);
|
||||
this.loggingService.sendInfoLevelMessage(accountAddresses);
|
||||
for (const accountAddress of accountAddresses.slice(offset, offset + limit)) {
|
||||
await this.getAccountByAddress(accountAddress, limit);
|
||||
if (typeof Worker !== 'undefined') {
|
||||
const worker = new Worker('@app/_workers/fetch-accounts.worker', { type: 'module' });
|
||||
worker.onmessage = ({ data }) => {
|
||||
if (data) {
|
||||
this.tokenService.load.subscribe(async (status: boolean) => {
|
||||
if (status) {
|
||||
data.balance = await this.tokenService.getTokenBalance(
|
||||
data.identities.evm[`bloxberg:${environment.bloxbergChainId}`][0]
|
||||
);
|
||||
}
|
||||
});
|
||||
this.addAccount(data, limit);
|
||||
}
|
||||
};
|
||||
worker.postMessage({
|
||||
addresses: accountAddresses.slice(offset, offset + limit),
|
||||
url: environment.cicMetaUrl,
|
||||
token: sessionStorage.getItem(btoa('CICADA_SESSION_TOKEN')),
|
||||
});
|
||||
} else {
|
||||
this.loggingService.sendInfoLevelMessage(
|
||||
'Web workers are not supported in this environment'
|
||||
);
|
||||
for (const accountAddress of accountAddresses.slice(offset, offset + limit)) {
|
||||
await this.getAccountByAddress(accountAddress, limit);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
this.loggingService.sendErrorLevelMessage('Unable to load accounts.', 'user.service', error);
|
||||
@@ -213,13 +222,22 @@ export class UserService {
|
||||
|
||||
async getAccountByAddress(
|
||||
accountAddress: string,
|
||||
limit: number = 100
|
||||
limit: number = 100,
|
||||
history: boolean = false
|
||||
): Promise<Observable<AccountDetails>> {
|
||||
const accountSubject: Subject<any> = new Subject<any>();
|
||||
this.getAccountDetailsFromMeta(await User.toKey(add0x(accountAddress)))
|
||||
.pipe(first())
|
||||
.subscribe(async (res) => {
|
||||
const account: Syncable = Envelope.fromJSON(JSON.stringify(res)).unwrap();
|
||||
if (history) {
|
||||
try {
|
||||
// @ts-ignore
|
||||
this.historyList.next(Automerge.getHistory(account.m).reverse());
|
||||
} catch (error) {
|
||||
this.loggingService.sendErrorLevelMessage('No history found', this, { error });
|
||||
}
|
||||
}
|
||||
const accountInfo = account.m.data;
|
||||
await personValidation(accountInfo);
|
||||
this.tokenService.load.subscribe(async (status: boolean) => {
|
||||
@@ -310,4 +328,60 @@ export class UserService {
|
||||
}
|
||||
this.accountsList.next(this.accounts);
|
||||
}
|
||||
|
||||
async loadChangesToAccountStructure(
|
||||
name: string,
|
||||
phoneNumber: string,
|
||||
age: string,
|
||||
type: string,
|
||||
bio: string,
|
||||
gender: string,
|
||||
businessCategory: string,
|
||||
userLocation: string,
|
||||
location: string,
|
||||
locationType: string
|
||||
): Promise<AccountDetails> {
|
||||
const accountInfo: any = {
|
||||
vcard: {
|
||||
fn: [{}],
|
||||
n: [{}],
|
||||
tel: [{}],
|
||||
},
|
||||
location: {},
|
||||
};
|
||||
if (name) {
|
||||
accountInfo.vcard.fn[0].value = name;
|
||||
accountInfo.vcard.n[0].value = name.split(' ');
|
||||
}
|
||||
if (phoneNumber) {
|
||||
accountInfo.vcard.tel[0].value = phoneNumber;
|
||||
}
|
||||
if (bio) {
|
||||
accountInfo.products = [bio];
|
||||
}
|
||||
if (gender) {
|
||||
accountInfo.gender = gender;
|
||||
}
|
||||
if (age) {
|
||||
accountInfo.age = age;
|
||||
}
|
||||
if (type) {
|
||||
accountInfo.type = type;
|
||||
}
|
||||
if (businessCategory) {
|
||||
accountInfo.category = businessCategory;
|
||||
}
|
||||
if (location) {
|
||||
accountInfo.location.area = location;
|
||||
}
|
||||
if (userLocation) {
|
||||
accountInfo.location.area_name = userLocation;
|
||||
}
|
||||
if (locationType) {
|
||||
accountInfo.location.area_type = locationType;
|
||||
}
|
||||
await vcardValidation(accountInfo.vcard);
|
||||
accountInfo.vcard = btoa(vCard.generate(accountInfo.vcard));
|
||||
return accountInfo;
|
||||
}
|
||||
}
|
||||
|
||||
57
src/app/_workers/fetch-accounts.worker.ts
Normal file
57
src/app/_workers/fetch-accounts.worker.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
/// <reference lib="webworker" />
|
||||
|
||||
import { Envelope, Syncable, User } from 'cic-client-meta';
|
||||
import { add0x } from '@src/assets/js/ethtx/dist/hex';
|
||||
import { personValidation, vcardValidation } from '@app/_helpers/schema-validation';
|
||||
import * as vCard from 'vcard-parser';
|
||||
|
||||
const headers = {
|
||||
'x-cic-automerge': 'client',
|
||||
};
|
||||
|
||||
const options = {
|
||||
headers,
|
||||
};
|
||||
|
||||
addEventListener('message', async ({ data }) => {
|
||||
if (data.addresses instanceof Array) {
|
||||
for (const accountAddress of data.addresses) {
|
||||
try {
|
||||
const account = await getAccountByAddress(accountAddress, data.url, data.token);
|
||||
postMessage(account);
|
||||
} catch (error) {
|
||||
console.log(`ERROR we failed to get account ${accountAddress}`, error);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
async function getAccountByAddress(
|
||||
accountAddress: string,
|
||||
metaUrl: string,
|
||||
token: string
|
||||
): Promise<any> {
|
||||
const userKey = await User.toKey(add0x(accountAddress));
|
||||
|
||||
headers['Authorization'] = 'Bearer ' + token;
|
||||
const response = await fetch(`${metaUrl}/${userKey}`, options)
|
||||
.then((res) => {
|
||||
if (res.ok) {
|
||||
return res.json();
|
||||
} else {
|
||||
return Promise.reject({
|
||||
status: res.status,
|
||||
statusText: res.statusText,
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
throw Error(`${error.status}: ${error.statusText}`);
|
||||
});
|
||||
const account: Syncable = Envelope.fromJSON(JSON.stringify(response)).unwrap();
|
||||
const accountInfo = account.m.data;
|
||||
await personValidation(accountInfo);
|
||||
accountInfo.vcard = vCard.parse(atob(accountInfo.vcard));
|
||||
await vcardValidation(accountInfo.vcard);
|
||||
return accountInfo;
|
||||
}
|
||||
@@ -44,31 +44,6 @@ export class AppComponent implements OnInit {
|
||||
await this.tokenService.init();
|
||||
await this.userService.init();
|
||||
await this.transactionService.init();
|
||||
await this.router.events
|
||||
.pipe(filter((e) => e instanceof NavigationEnd))
|
||||
.forEach(async (routeInfo) => {
|
||||
if (routeInfo instanceof NavigationEnd) {
|
||||
this.url = routeInfo.url;
|
||||
if (!this.url.match(this.accountDetailsRegex) || !this.url.includes('tx')) {
|
||||
await this.blockSyncService.blockSync();
|
||||
}
|
||||
if (!this.url.includes('accounts')) {
|
||||
try {
|
||||
// TODO it feels like this should be in the onInit handler
|
||||
await this.userService.loadAccounts(100);
|
||||
} catch (error) {
|
||||
this.loggingService.sendErrorLevelMessage('Failed to load accounts', this, { error });
|
||||
}
|
||||
}
|
||||
if (!this.url.includes('tokens')) {
|
||||
this.tokenService.load.subscribe(async (status: boolean) => {
|
||||
if (status) {
|
||||
await this.tokenService.getTokens();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
try {
|
||||
const publicKeys = await this.authService.getPublicKeys();
|
||||
await this.authService.mutableKeyStore.importPublicKey(publicKeys);
|
||||
@@ -86,6 +61,7 @@ export class AppComponent implements OnInit {
|
||||
}
|
||||
});
|
||||
}
|
||||
await this.routeManagement();
|
||||
}
|
||||
|
||||
// Load resize
|
||||
@@ -124,4 +100,31 @@ export class AppComponent implements OnInit {
|
||||
const conversion: any = event.detail.tx;
|
||||
await this.transactionService.setConversion(conversion, 100);
|
||||
}
|
||||
|
||||
async routeManagement(): Promise<void> {
|
||||
await this.router.events
|
||||
.pipe(filter((e) => e instanceof NavigationEnd))
|
||||
.forEach(async (routeInfo) => {
|
||||
if (routeInfo instanceof NavigationEnd) {
|
||||
this.url = routeInfo.url;
|
||||
if (!this.url.match(this.accountDetailsRegex) || !this.url.includes('tx')) {
|
||||
await this.blockSyncService.blockSync();
|
||||
}
|
||||
if (!this.url.includes('accounts')) {
|
||||
try {
|
||||
await this.userService.loadAccounts(100);
|
||||
} catch (error) {
|
||||
this.loggingService.sendErrorLevelMessage('Failed to load accounts', this, { error });
|
||||
}
|
||||
}
|
||||
if (!this.url.includes('tokens')) {
|
||||
this.tokenService.load.subscribe(async (status: boolean) => {
|
||||
if (status) {
|
||||
await this.tokenService.getTokens();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -333,7 +333,88 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<mat-tab-group *ngIf="account" dynamicHeight mat-align-tabs="start">
|
||||
<div class="card mt-1">
|
||||
<app-account-history
|
||||
*ngIf="history"
|
||||
[account]="history?.snapshot.data"
|
||||
(closeWindow)="history = $event"
|
||||
></app-account-history>
|
||||
<mat-card-title class="card-header"> HISTORY </mat-card-title>
|
||||
<div class="card-body">
|
||||
<div *ngIf="historyLoading">
|
||||
<h2 class="text-center"><strong>Loading History!</strong></h2>
|
||||
<mat-progress-bar [mode]="'query'"></mat-progress-bar>
|
||||
</div>
|
||||
|
||||
<mat-table
|
||||
class="mat-elevation-z10"
|
||||
[dataSource]="historyDataSource"
|
||||
matSort
|
||||
matSortActive="timestamp"
|
||||
#HistoryTableSort="matSort"
|
||||
matSortDirection="asc"
|
||||
matSortDisableClear
|
||||
>
|
||||
<ng-container matColumnDef="actor">
|
||||
<mat-header-cell *matHeaderCellDef mat-sort-header>Actor</mat-header-cell>
|
||||
<mat-cell *matCellDef="let history">
|
||||
{{ history?.change.actor }}
|
||||
</mat-cell>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="signer">
|
||||
<mat-header-cell *matHeaderCellDef mat-sort-header>Signer</mat-header-cell>
|
||||
<mat-cell *matCellDef="let history">
|
||||
{{ history?.snapshot.signature?.data | signatureUser | async }}
|
||||
</mat-cell>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="message">
|
||||
<mat-header-cell *matHeaderCellDef mat-sort-header>Message</mat-header-cell>
|
||||
<mat-cell *matCellDef="let history">
|
||||
{{ history?.change.message }}
|
||||
</mat-cell>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="sequence">
|
||||
<mat-header-cell *matHeaderCellDef mat-sort-header>Sequence</mat-header-cell>
|
||||
<mat-cell *matCellDef="let history">
|
||||
{{ history?.change.seq }}
|
||||
</mat-cell>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="dependencies">
|
||||
<mat-header-cell *matHeaderCellDef mat-sort-header>Dependencies</mat-header-cell>
|
||||
<mat-cell *matCellDef="let history">
|
||||
{{ getKeyValue(history?.change.deps) }}
|
||||
</mat-cell>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="timestamp">
|
||||
<mat-header-cell *matHeaderCellDef mat-sort-header>ChangedAt</mat-header-cell>
|
||||
<mat-cell *matCellDef="let history">
|
||||
{{ history?.snapshot.timestamp | unixDate }}
|
||||
</mat-cell>
|
||||
</ng-container>
|
||||
|
||||
<mat-header-row *matHeaderRowDef="historyDisplayedColumns"></mat-header-row>
|
||||
<mat-row
|
||||
*matRowDef="let history; columns: historyDisplayedColumns"
|
||||
(click)="viewHistory(history)"
|
||||
matRipple
|
||||
></mat-row>
|
||||
</mat-table>
|
||||
|
||||
<mat-paginator
|
||||
#HistoryTablePaginator="matPaginator"
|
||||
[pageSize]="historyDefaultPageSize"
|
||||
[pageSizeOptions]="historyPageSizeOptions"
|
||||
showFirstLastButtons
|
||||
></mat-paginator>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<mat-tab-group dynamicHeight mat-align-tabs="start">
|
||||
<mat-tab label="Transactions">
|
||||
<app-transaction-details
|
||||
[transaction]="transaction"
|
||||
|
||||
@@ -47,6 +47,20 @@ export class AccountDetailsComponent implements OnInit, AfterViewInit {
|
||||
@ViewChild('UserTablePaginator', { static: true }) userTablePaginator: MatPaginator;
|
||||
@ViewChild('UserTableSort', { static: true }) userTableSort: MatSort;
|
||||
|
||||
historyDataSource: MatTableDataSource<any>;
|
||||
historyDisplayedColumns: Array<string> = [
|
||||
'actor',
|
||||
'signer',
|
||||
'message',
|
||||
'sequence',
|
||||
'dependencies',
|
||||
'timestamp',
|
||||
];
|
||||
historyDefaultPageSize: number = 10;
|
||||
historyPageSizeOptions: Array<number> = [10, 20, 50, 100];
|
||||
@ViewChild('HistoryTablePaginator', { static: true }) historyTablePaginator: MatPaginator;
|
||||
@ViewChild('HistoryTableSort', { static: true }) historyTableSort: MatSort;
|
||||
|
||||
accountInfoForm: FormGroup;
|
||||
account: AccountDetails;
|
||||
accountAddress: string;
|
||||
@@ -71,6 +85,9 @@ export class AccountDetailsComponent implements OnInit, AfterViewInit {
|
||||
areaType: string;
|
||||
accountsLoading: boolean = true;
|
||||
transactionsLoading: boolean = true;
|
||||
histories: Array<any> = [];
|
||||
history: any;
|
||||
historyLoading: boolean = true;
|
||||
|
||||
constructor(
|
||||
private formBuilder: FormBuilder,
|
||||
@@ -93,56 +110,17 @@ export class AccountDetailsComponent implements OnInit, AfterViewInit {
|
||||
}
|
||||
|
||||
async ngOnInit(): Promise<void> {
|
||||
this.accountInfoForm = this.formBuilder.group({
|
||||
firstName: ['', Validators.required],
|
||||
lastName: ['', Validators.required],
|
||||
phoneNumber: ['', Validators.required],
|
||||
age: [''],
|
||||
type: ['', Validators.required],
|
||||
bio: ['', Validators.required],
|
||||
gender: ['', Validators.required],
|
||||
businessCategory: ['', Validators.required],
|
||||
userLocation: ['', Validators.required],
|
||||
location: ['', Validators.required],
|
||||
locationType: ['', Validators.required],
|
||||
});
|
||||
this.buildAccountsInfoForm();
|
||||
this.transactionService.resetTransactionsList();
|
||||
await this.blockSyncService.blockSync(this.accountAddress);
|
||||
this.userService.resetAccountsList();
|
||||
(await this.userService.getAccountByAddress(this.accountAddress, 100)).subscribe(
|
||||
(await this.userService.getAccountByAddress(this.accountAddress, 100, true)).subscribe(
|
||||
async (res) => {
|
||||
if (res !== undefined) {
|
||||
this.account = res;
|
||||
this.cdr.detectChanges();
|
||||
this.locationService.areaNamesSubject.subscribe((response) => {
|
||||
this.area = this.locationService.getAreaNameByLocation(
|
||||
this.account.location.area_name,
|
||||
response
|
||||
);
|
||||
this.cdr.detectChanges();
|
||||
this.locationService.areaTypesSubject.subscribe((result) => {
|
||||
this.areaType = this.locationService.getAreaTypeByArea(this.area, result);
|
||||
this.cdr.detectChanges();
|
||||
});
|
||||
});
|
||||
this.userService.categoriesSubject.subscribe((result) => {
|
||||
this.category = this.userService.getCategoryByProduct(this.account.products[0], result);
|
||||
this.cdr.detectChanges();
|
||||
});
|
||||
const fullName = this.account.vcard?.fn[0].value.split(' ');
|
||||
this.accountInfoForm.patchValue({
|
||||
firstName: fullName[0].split(',')[0],
|
||||
lastName: fullName.slice(1).join(' '),
|
||||
phoneNumber: this.account.vcard?.tel[0].value,
|
||||
age: this.account.age,
|
||||
type: this.account.type,
|
||||
bio: this.account.products,
|
||||
gender: this.account.gender,
|
||||
businessCategory: this.account.category || this.category || 'other',
|
||||
userLocation: this.account.location.area_name,
|
||||
location: this.account.location.area || this.area || 'other',
|
||||
locationType: this.account.location.area_type || this.areaType || 'other',
|
||||
});
|
||||
this.queryLocationAndCategory(this.account);
|
||||
this.populateAccountsInfoForm(this.account);
|
||||
this.userService
|
||||
.getAccountStatus(this.account.vcard?.tel[0].value)
|
||||
.pipe(first())
|
||||
@@ -152,51 +130,8 @@ export class AccountDetailsComponent implements OnInit, AfterViewInit {
|
||||
}
|
||||
}
|
||||
);
|
||||
this.userService.accountsSubject.subscribe((accounts) => {
|
||||
this.userDataSource = new MatTableDataSource<any>(accounts);
|
||||
this.userDataSource.paginator = this.userTablePaginator;
|
||||
this.userDataSource.sort = this.userTableSort;
|
||||
this.accounts = accounts;
|
||||
if (accounts.length > 0) {
|
||||
this.accountsLoading = false;
|
||||
}
|
||||
this.cdr.detectChanges();
|
||||
});
|
||||
|
||||
this.transactionService.transactionsSubject.subscribe((transactions) => {
|
||||
this.transactionsDataSource = new MatTableDataSource<any>(transactions);
|
||||
this.transactionsDataSource.paginator = this.transactionTablePaginator;
|
||||
this.transactionsDataSource.sort = this.transactionTableSort;
|
||||
this.transactions = transactions;
|
||||
if (transactions.length > 0) {
|
||||
this.transactionsLoading = false;
|
||||
}
|
||||
this.cdr.detectChanges();
|
||||
});
|
||||
this.userService.getCategories();
|
||||
this.userService.categoriesSubject.subscribe((res) => {
|
||||
this.categories = Object.keys(res);
|
||||
});
|
||||
this.locationService.getAreaNames();
|
||||
this.locationService.areaNamesSubject.subscribe((res) => {
|
||||
this.areaNames = Object.keys(res);
|
||||
});
|
||||
this.locationService.getAreaTypes();
|
||||
this.locationService.areaTypesSubject.subscribe((res) => {
|
||||
this.areaTypes = Object.keys(res);
|
||||
});
|
||||
this.userService
|
||||
.getAccountTypes()
|
||||
.pipe(first())
|
||||
.subscribe((res) => (this.accountTypes = res));
|
||||
this.userService
|
||||
.getTransactionTypes()
|
||||
.pipe(first())
|
||||
.subscribe((res) => (this.transactionsTypes = res));
|
||||
this.userService
|
||||
.getGenders()
|
||||
.pipe(first())
|
||||
.subscribe((res) => (this.genders = res));
|
||||
this.populateDataTables();
|
||||
this.loadSearchData();
|
||||
this.tokenService.load.subscribe(async (status: boolean) => {
|
||||
if (status) {
|
||||
this.tokenSymbol = await this.tokenService.getTokenSymbol();
|
||||
@@ -213,6 +148,10 @@ export class AccountDetailsComponent implements OnInit, AfterViewInit {
|
||||
this.transactionsDataSource.paginator = this.transactionTablePaginator;
|
||||
this.transactionsDataSource.sort = this.transactionTableSort;
|
||||
}
|
||||
if (this.historyDataSource) {
|
||||
this.historyDataSource.paginator = this.historyTablePaginator;
|
||||
this.historyDataSource.sort = this.historyTableSort;
|
||||
}
|
||||
}
|
||||
|
||||
doTransactionFilter(value: string): void {
|
||||
@@ -227,6 +166,10 @@ export class AccountDetailsComponent implements OnInit, AfterViewInit {
|
||||
this.transaction = transaction;
|
||||
}
|
||||
|
||||
viewHistory(history): void {
|
||||
this.history = history;
|
||||
}
|
||||
|
||||
viewAccount(account): void {
|
||||
this.router.navigateByUrl(
|
||||
`/accounts/${strip0x(account.identities.evm[`bloxberg:${environment.bloxbergChainId}`][0])}`
|
||||
@@ -253,7 +196,8 @@ export class AccountDetailsComponent implements OnInit, AfterViewInit {
|
||||
this.accountInfoFormStub.businessCategory.value,
|
||||
this.accountInfoFormStub.userLocation.value,
|
||||
this.accountInfoFormStub.location.value,
|
||||
this.accountInfoFormStub.locationType.value
|
||||
this.accountInfoFormStub.locationType.value,
|
||||
this.account.vcard?.tel[0].value
|
||||
);
|
||||
this.submitted = false;
|
||||
}
|
||||
@@ -307,4 +251,127 @@ export class AccountDetailsComponent implements OnInit, AfterViewInit {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
getKeyValue(obj: any): string {
|
||||
let str = '';
|
||||
if (obj instanceof Object) {
|
||||
for (const [key, value] of Object.entries(obj)) {
|
||||
str += `${key}: ${value} `;
|
||||
}
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
buildAccountsInfoForm(): void {
|
||||
this.accountInfoForm = this.formBuilder.group({
|
||||
firstName: ['', Validators.required],
|
||||
lastName: ['', Validators.required],
|
||||
phoneNumber: ['', Validators.required],
|
||||
age: [''],
|
||||
type: ['', Validators.required],
|
||||
bio: ['', Validators.required],
|
||||
gender: ['', Validators.required],
|
||||
businessCategory: ['', Validators.required],
|
||||
userLocation: ['', Validators.required],
|
||||
location: ['', Validators.required],
|
||||
locationType: ['', Validators.required],
|
||||
});
|
||||
}
|
||||
|
||||
populateAccountsInfoForm(accountInfo: AccountDetails): void {
|
||||
const fullName = accountInfo.vcard?.fn[0].value.split(' ');
|
||||
this.accountInfoForm.patchValue({
|
||||
firstName: fullName[0].split(',')[0],
|
||||
lastName: fullName.slice(1).join(' '),
|
||||
phoneNumber: accountInfo.vcard?.tel[0].value,
|
||||
age: accountInfo.age,
|
||||
type: accountInfo.type,
|
||||
bio: accountInfo.products,
|
||||
gender: accountInfo.gender,
|
||||
businessCategory: accountInfo.category || this.category || 'other',
|
||||
userLocation: accountInfo.location.area_name,
|
||||
location: accountInfo.location.area || this.area || 'other',
|
||||
locationType: accountInfo.location.area_type || this.areaType || 'other',
|
||||
});
|
||||
}
|
||||
|
||||
populateDataTables(): void {
|
||||
this.userService.accountsSubject.subscribe((accounts) => {
|
||||
this.userDataSource = new MatTableDataSource<any>(accounts);
|
||||
this.userDataSource.paginator = this.userTablePaginator;
|
||||
this.userDataSource.sort = this.userTableSort;
|
||||
this.accounts = accounts;
|
||||
if (accounts.length > 0) {
|
||||
this.accountsLoading = false;
|
||||
}
|
||||
this.cdr.detectChanges();
|
||||
});
|
||||
|
||||
this.transactionService.transactionsSubject.subscribe((transactions) => {
|
||||
this.transactionsDataSource = new MatTableDataSource<any>(transactions);
|
||||
this.transactionsDataSource.paginator = this.transactionTablePaginator;
|
||||
this.transactionsDataSource.sort = this.transactionTableSort;
|
||||
this.transactions = transactions;
|
||||
if (transactions.length > 0) {
|
||||
this.transactionsLoading = false;
|
||||
}
|
||||
this.cdr.detectChanges();
|
||||
});
|
||||
|
||||
this.userService.historySubject.subscribe(async (histories) => {
|
||||
this.historyDataSource = new MatTableDataSource<any>(histories);
|
||||
this.historyDataSource.paginator = this.historyTablePaginator;
|
||||
this.historyDataSource.sort = this.historyTableSort;
|
||||
this.histories = histories;
|
||||
if (histories.length > 0) {
|
||||
this.historyLoading = false;
|
||||
}
|
||||
this.cdr.detectChanges();
|
||||
});
|
||||
}
|
||||
|
||||
queryLocationAndCategory(accountInfo: AccountDetails): void {
|
||||
this.locationService.areaNamesSubject.subscribe((response) => {
|
||||
this.area = this.locationService.getAreaNameByLocation(
|
||||
accountInfo.location.area_name,
|
||||
response
|
||||
);
|
||||
this.cdr.detectChanges();
|
||||
this.locationService.areaTypesSubject.subscribe((result) => {
|
||||
this.areaType = this.locationService.getAreaTypeByArea(this.area, result);
|
||||
this.cdr.detectChanges();
|
||||
});
|
||||
});
|
||||
this.userService.categoriesSubject.subscribe((result) => {
|
||||
this.category = this.userService.getCategoryByProduct(accountInfo.products[0], result);
|
||||
this.cdr.detectChanges();
|
||||
});
|
||||
}
|
||||
|
||||
loadSearchData(): void {
|
||||
this.userService.getCategories();
|
||||
this.userService.categoriesSubject.subscribe((res) => {
|
||||
this.categories = Object.keys(res);
|
||||
});
|
||||
this.locationService.getAreaNames();
|
||||
this.locationService.areaNamesSubject.subscribe((res) => {
|
||||
this.areaNames = Object.keys(res);
|
||||
});
|
||||
this.locationService.getAreaTypes();
|
||||
this.locationService.areaTypesSubject.subscribe((res) => {
|
||||
this.areaTypes = Object.keys(res);
|
||||
});
|
||||
this.userService
|
||||
.getAccountTypes()
|
||||
.pipe(first())
|
||||
.subscribe((res) => (this.accountTypes = res));
|
||||
this.userService
|
||||
.getTransactionTypes()
|
||||
.pipe(first())
|
||||
.subscribe((res) => (this.transactionsTypes = res));
|
||||
this.userService
|
||||
.getGenders()
|
||||
.pipe(first())
|
||||
.subscribe((res) => (this.genders = res));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
<div *ngIf="account" class="mb-3 mt-1">
|
||||
<div class="card text-center">
|
||||
<mat-card-title class="card-header">
|
||||
<div class="row">
|
||||
ACCOUNT DETAILS
|
||||
<button
|
||||
mat-raised-button
|
||||
type="button"
|
||||
class="btn btn-outline-secondary ml-auto mr-2"
|
||||
(click)="close()"
|
||||
>
|
||||
CLOSE
|
||||
</button>
|
||||
</div>
|
||||
</mat-card-title>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<ul class="list-group list-group-flush">
|
||||
<li class="list-group-item">
|
||||
<span>Name: {{ account?.vcard?.fn[0].value }}</span>
|
||||
</li>
|
||||
<li class="list-group-item">
|
||||
<span>Phone Number: {{ account?.vcard?.tel[0].value }}</span>
|
||||
</li>
|
||||
<li class="list-group-item">
|
||||
<span>Account Type: {{ account?.type }}</span>
|
||||
</li>
|
||||
<li class="list-group-item">
|
||||
<span>Gender: {{ account?.gender }}</span>
|
||||
</li>
|
||||
<li class="list-group-item">
|
||||
<span>Age: {{ account?.age }}</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<ul class="list-group list-group-flush">
|
||||
<li class="list-group-item">
|
||||
<span>Bio: {{ account?.products }}</span>
|
||||
</li>
|
||||
<li class="list-group-item">
|
||||
<span>Business Category: {{ account?.category }}</span>
|
||||
</li>
|
||||
<li class="list-group-item">
|
||||
<span>User Location: {{ account?.location?.area_name }}</span>
|
||||
</li>
|
||||
<li class="list-group-item">
|
||||
<span>Location: {{ account?.location?.area }}</span>
|
||||
</li>
|
||||
<li class="list-group-item">
|
||||
<span>Location Type: {{ account?.location?.area_type }}</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,24 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { AccountHistoryComponent } from './account-history.component';
|
||||
|
||||
describe('AccountHistoryComponent', () => {
|
||||
let component: AccountHistoryComponent;
|
||||
let fixture: ComponentFixture<AccountHistoryComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [AccountHistoryComponent],
|
||||
}).compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(AccountHistoryComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,38 @@
|
||||
import {
|
||||
Component,
|
||||
OnInit,
|
||||
ChangeDetectionStrategy,
|
||||
Input,
|
||||
Output,
|
||||
EventEmitter,
|
||||
SimpleChanges,
|
||||
OnChanges,
|
||||
} from '@angular/core';
|
||||
const vCard = require('vcard-parser');
|
||||
|
||||
@Component({
|
||||
selector: 'app-account-history',
|
||||
templateUrl: './account-history.component.html',
|
||||
styleUrls: ['./account-history.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class AccountHistoryComponent implements OnInit, OnChanges {
|
||||
@Input() account;
|
||||
|
||||
@Output() closeWindow: EventEmitter<any> = new EventEmitter<any>();
|
||||
|
||||
constructor() {}
|
||||
|
||||
ngOnInit(): void {}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges): void {
|
||||
if (this.account) {
|
||||
this.account.vcard = vCard.parse(atob(this.account.vcard));
|
||||
}
|
||||
}
|
||||
|
||||
close(): void {
|
||||
this.account = null;
|
||||
this.closeWindow.emit(this.account);
|
||||
}
|
||||
}
|
||||
@@ -54,7 +54,6 @@ export class AccountsComponent implements OnInit, AfterViewInit {
|
||||
}
|
||||
});
|
||||
try {
|
||||
// TODO it feels like this should be in the onInit handler
|
||||
await this.userService.loadAccounts(100);
|
||||
} catch (error) {
|
||||
this.loggingService.sendErrorLevelMessage('Failed to load accounts', this, { error });
|
||||
|
||||
@@ -24,6 +24,7 @@ import { ReactiveFormsModule } from '@angular/forms';
|
||||
import { AccountSearchComponent } from './account-search/account-search.component';
|
||||
import { MatSnackBarModule } from '@angular/material/snack-bar';
|
||||
import { MatProgressBarModule } from '@angular/material/progress-bar';
|
||||
import { AccountHistoryComponent } from './account-history/account-history.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
@@ -31,7 +32,9 @@ import { MatProgressBarModule } from '@angular/material/progress-bar';
|
||||
AccountDetailsComponent,
|
||||
CreateAccountComponent,
|
||||
AccountSearchComponent,
|
||||
AccountHistoryComponent,
|
||||
],
|
||||
exports: [AccountHistoryComponent],
|
||||
imports: [
|
||||
CommonModule,
|
||||
AccountsRoutingModule,
|
||||
|
||||
@@ -38,6 +38,22 @@ export class CreateAccountComponent implements OnInit {
|
||||
referrer: ['', Validators.required],
|
||||
businessCategory: ['', Validators.required],
|
||||
});
|
||||
this.loadSearchData();
|
||||
}
|
||||
|
||||
get createFormStub(): any {
|
||||
return this.createForm.controls;
|
||||
}
|
||||
|
||||
onSubmit(): void {
|
||||
this.submitted = true;
|
||||
if (this.createForm.invalid || !confirm('Create account?')) {
|
||||
return;
|
||||
}
|
||||
this.submitted = false;
|
||||
}
|
||||
|
||||
loadSearchData(): void {
|
||||
this.userService.getCategories();
|
||||
this.userService.categoriesSubject.subscribe((res) => {
|
||||
this.categories = Object.keys(res);
|
||||
@@ -55,16 +71,4 @@ export class CreateAccountComponent implements OnInit {
|
||||
.pipe(first())
|
||||
.subscribe((res) => (this.genders = res));
|
||||
}
|
||||
|
||||
get createFormStub(): any {
|
||||
return this.createForm.controls;
|
||||
}
|
||||
|
||||
onSubmit(): void {
|
||||
this.submitted = true;
|
||||
if (this.createForm.invalid || !confirm('Create account?')) {
|
||||
return;
|
||||
}
|
||||
this.submitted = false;
|
||||
}
|
||||
}
|
||||
|
||||
8
src/app/shared/_pipes/signature-user.pipe.spec.ts
Normal file
8
src/app/shared/_pipes/signature-user.pipe.spec.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { SignatureUserPipe } from './signature-user.pipe';
|
||||
|
||||
describe('SignatureUserPipe', () => {
|
||||
it('create an instance', () => {
|
||||
const pipe = new SignatureUserPipe();
|
||||
expect(pipe).toBeTruthy();
|
||||
});
|
||||
});
|
||||
20
src/app/shared/_pipes/signature-user.pipe.ts
Normal file
20
src/app/shared/_pipes/signature-user.pipe.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { Pipe, PipeTransform } from '@angular/core';
|
||||
import * as openpgp from 'openpgp';
|
||||
import { asciiToHex } from '@app/_helpers';
|
||||
import { KeystoreService } from '@app/_services';
|
||||
|
||||
@Pipe({
|
||||
name: 'signatureUser',
|
||||
})
|
||||
export class SignatureUserPipe implements PipeTransform {
|
||||
async transform(armoredSignature: string, ...args: unknown[]): Promise<string> {
|
||||
const keystore = await KeystoreService.getKeystore();
|
||||
const signature = await openpgp.signature.readArmored(armoredSignature);
|
||||
const keyId = asciiToHex(signature.packets[0].issuerKeyId.bytes);
|
||||
const pubKey = keystore.getPublicKeyForId(keyId);
|
||||
if (pubKey) {
|
||||
return pubKey.users[0].userId.userid;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,7 @@ import { MatDialogModule } from '@angular/material/dialog';
|
||||
import { SafePipe } from '@app/shared/_pipes/safe.pipe';
|
||||
import { NetworkStatusComponent } from './network-status/network-status.component';
|
||||
import { UnixDatePipe } from './_pipes/unix-date.pipe';
|
||||
import { SignatureUserPipe } from './_pipes/signature-user.pipe';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
@@ -26,6 +27,7 @@ import { UnixDatePipe } from './_pipes/unix-date.pipe';
|
||||
SafePipe,
|
||||
NetworkStatusComponent,
|
||||
UnixDatePipe,
|
||||
SignatureUserPipe,
|
||||
],
|
||||
exports: [
|
||||
TopbarComponent,
|
||||
@@ -36,6 +38,7 @@ import { UnixDatePipe } from './_pipes/unix-date.pipe';
|
||||
SafePipe,
|
||||
NetworkStatusComponent,
|
||||
UnixDatePipe,
|
||||
SignatureUserPipe,
|
||||
],
|
||||
imports: [CommonModule, RouterModule, MatIconModule, MatDialogModule],
|
||||
})
|
||||
|
||||
@@ -6,11 +6,11 @@ export const environment = {
|
||||
logLevel: NgxLoggerLevel.DEBUG,
|
||||
serverLogLevel: NgxLoggerLevel.OFF,
|
||||
loggingUrl: '',
|
||||
cicMetaUrl: 'https://meta-auth.dev.grassrootseconomics.net:443',
|
||||
cicMetaUrl: 'http://localhost:63380',
|
||||
publicKeysUrl: 'https://dev.grassrootseconomics.net/.well-known/publickeys/',
|
||||
cicCacheUrl: 'https://cache.dev.grassrootseconomics.net',
|
||||
web3Provider: 'wss://bloxberg-ws.dev.grassrootseconomics.net',
|
||||
cicUssdUrl: 'https://user.dev.grassrootseconomics.net',
|
||||
cicCacheUrl: 'http://localhost:63313',
|
||||
web3Provider: 'http://localhost:8545',
|
||||
cicUssdUrl: 'http://localhost:63415',
|
||||
registryAddress: '0xea6225212005e86a4490018ded4bf37f3e772161',
|
||||
trustedDeclaratorAddress: '0xEb3907eCad74a0013c259D5874AE7f22DcBcC95C',
|
||||
dashboardUrl: 'https://dashboard.sarafu.network/',
|
||||
|
||||
17
src/environments/environment.staging.ts
Normal file
17
src/environments/environment.staging.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { NgxLoggerLevel } from 'ngx-logger';
|
||||
|
||||
export const environment = {
|
||||
production: false,
|
||||
bloxbergChainId: 8996,
|
||||
logLevel: NgxLoggerLevel.DEBUG,
|
||||
serverLogLevel: NgxLoggerLevel.OFF,
|
||||
loggingUrl: '',
|
||||
cicMetaUrl: 'https://meta.staging.grassrootseconomics.net',
|
||||
publicKeysUrl: 'https://dev.grassrootseconomics.net/.well-known/publickeys/',
|
||||
cicCacheUrl: 'https://cache.staging.grassrootseconomics.net',
|
||||
web3Provider: 'wss://bloxberg.staging.grassrootseconomics.net',
|
||||
cicUssdUrl: 'https://user.staging.grassrootseconomics.net',
|
||||
registryAddress: '0xea6225212005e86a4490018ded4bf37f3e772161',
|
||||
trustedDeclaratorAddress: '0xEb3907eCad74a0013c259D5874AE7f22DcBcC95C',
|
||||
dashboardUrl: 'https://dashboard.sarafu.network/',
|
||||
};
|
||||
15
tsconfig.worker.json
Normal file
15
tsconfig.worker.json
Normal file
@@ -0,0 +1,15 @@
|
||||
/* To learn more about this file see: https://angular.io/config/tsconfig. */
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "./out-tsc/worker",
|
||||
"lib": [
|
||||
"es2018",
|
||||
"webworker"
|
||||
],
|
||||
"types": []
|
||||
},
|
||||
"include": [
|
||||
"src/**/*.worker.ts"
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user