frontend work

This commit is contained in:
nitowa
2024-10-13 14:45:00 +02:00
parent 9d64d43230
commit ec746cd1a2
9 changed files with 135 additions and 57 deletions
+7 -7
View File
@@ -12,7 +12,7 @@
"buffer": "^6.0.3", "buffer": "^6.0.3",
"chai": "^4.3.4", "chai": "^4.3.4",
"node-fetch": "^2.6.1", "node-fetch": "^2.6.1",
"rjsvm": "^0.3.0", "rjsvm": "^0.3.2",
"xrpio": "^0.3.0", "xrpio": "^0.3.0",
"xrpl": "^2.7.0" "xrpl": "^2.7.0"
}, },
@@ -3119,9 +3119,9 @@
} }
}, },
"node_modules/rjsvm": { "node_modules/rjsvm": {
"version": "0.3.0", "version": "0.3.2",
"resolved": "https://registry.npmjs.org/rjsvm/-/rjsvm-0.3.0.tgz", "resolved": "https://registry.npmjs.org/rjsvm/-/rjsvm-0.3.2.tgz",
"integrity": "sha512-BQSOA7ao2feNl5dyhaAH3A2LJkj7zr3fIsWktlGFbICOa9NZGuZiwLIehf/YaeMhDCOzYe10troHlhU8BCis7w==", "integrity": "sha512-plaK9+hlTUlEA9W7fZo1wOjnIrwxC0oiFPogvScW/vcHEMsVHJ8Vlmk8hMbhA29X6DA0+VezDtnQ9XFIdLLMSg==",
"dependencies": { "dependencies": {
"axios": "^1.7.7", "axios": "^1.7.7",
"stream-http": "^3.2.0", "stream-http": "^3.2.0",
@@ -6618,9 +6618,9 @@
} }
}, },
"rjsvm": { "rjsvm": {
"version": "0.3.0", "version": "0.3.2",
"resolved": "https://registry.npmjs.org/rjsvm/-/rjsvm-0.3.0.tgz", "resolved": "https://registry.npmjs.org/rjsvm/-/rjsvm-0.3.2.tgz",
"integrity": "sha512-BQSOA7ao2feNl5dyhaAH3A2LJkj7zr3fIsWktlGFbICOa9NZGuZiwLIehf/YaeMhDCOzYe10troHlhU8BCis7w==", "integrity": "sha512-plaK9+hlTUlEA9W7fZo1wOjnIrwxC0oiFPogvScW/vcHEMsVHJ8Vlmk8hMbhA29X6DA0+VezDtnQ9XFIdLLMSg==",
"requires": { "requires": {
"axios": "^1.7.7", "axios": "^1.7.7",
"stream-http": "^3.2.0", "stream-http": "^3.2.0",
+1 -1
View File
@@ -21,7 +21,7 @@
"buffer": "^6.0.3", "buffer": "^6.0.3",
"chai": "^4.3.4", "chai": "^4.3.4",
"node-fetch": "^2.6.1", "node-fetch": "^2.6.1",
"rjsvm": "^0.3.0", "rjsvm": "^0.3.2",
"xrpio": "^0.3.0", "xrpio": "^0.3.0",
"xrpl": "^2.7.0" "xrpl": "^2.7.0"
}, },
+7 -7
View File
@@ -26,7 +26,7 @@
"buffer": "^6.0.3", "buffer": "^6.0.3",
"modern-normalize": "^1.1.0", "modern-normalize": "^1.1.0",
"process": "^0.11.10", "process": "^0.11.10",
"rjsvm": "^0.3.0", "rjsvm": "^0.3.2",
"rxjs": "~7.5.0", "rxjs": "~7.5.0",
"tslib": "^2.3.0", "tslib": "^2.3.0",
"xrpio": "^0.3.0", "xrpio": "^0.3.0",
@@ -11639,9 +11639,9 @@
} }
}, },
"node_modules/rjsvm": { "node_modules/rjsvm": {
"version": "0.3.0", "version": "0.3.2",
"resolved": "https://registry.npmjs.org/rjsvm/-/rjsvm-0.3.0.tgz", "resolved": "https://registry.npmjs.org/rjsvm/-/rjsvm-0.3.2.tgz",
"integrity": "sha512-BQSOA7ao2feNl5dyhaAH3A2LJkj7zr3fIsWktlGFbICOa9NZGuZiwLIehf/YaeMhDCOzYe10troHlhU8BCis7w==", "integrity": "sha512-plaK9+hlTUlEA9W7fZo1wOjnIrwxC0oiFPogvScW/vcHEMsVHJ8Vlmk8hMbhA29X6DA0+VezDtnQ9XFIdLLMSg==",
"dependencies": { "dependencies": {
"axios": "^1.7.7", "axios": "^1.7.7",
"stream-http": "^3.2.0", "stream-http": "^3.2.0",
@@ -22544,9 +22544,9 @@
} }
}, },
"rjsvm": { "rjsvm": {
"version": "0.3.0", "version": "0.3.2",
"resolved": "https://registry.npmjs.org/rjsvm/-/rjsvm-0.3.0.tgz", "resolved": "https://registry.npmjs.org/rjsvm/-/rjsvm-0.3.2.tgz",
"integrity": "sha512-BQSOA7ao2feNl5dyhaAH3A2LJkj7zr3fIsWktlGFbICOa9NZGuZiwLIehf/YaeMhDCOzYe10troHlhU8BCis7w==", "integrity": "sha512-plaK9+hlTUlEA9W7fZo1wOjnIrwxC0oiFPogvScW/vcHEMsVHJ8Vlmk8hMbhA29X6DA0+VezDtnQ9XFIdLLMSg==",
"requires": { "requires": {
"axios": "^1.7.7", "axios": "^1.7.7",
"stream-http": "^3.2.0", "stream-http": "^3.2.0",
+1 -1
View File
@@ -30,7 +30,7 @@
"buffer": "^6.0.3", "buffer": "^6.0.3",
"modern-normalize": "^1.1.0", "modern-normalize": "^1.1.0",
"process": "^0.11.10", "process": "^0.11.10",
"rjsvm": "^0.3.0", "rjsvm": "^0.3.2",
"rxjs": "~7.5.0", "rxjs": "~7.5.0",
"tslib": "^2.3.0", "tslib": "^2.3.0",
"xrpio": "^0.3.0", "xrpio": "^0.3.0",
+70 -11
View File
@@ -1,19 +1,66 @@
<div class="main-container"> <div class="main-container">
<header class="header-2"> <header class="header-2">
<div class="branding"> <div class="branding">
<a class="nav-link"> <a class="nav-link" target="_blank" [href]="'https://testnet.xrpl.org/accounts/'+contractAddress">
<cds-icon shape="home" size="lg"></cds-icon> <cds-icon shape="home" size="lg"></cds-icon>
<span class="title">httXrp</span> <span class="title">{{contractAddress}}</span>
</a> </a>
</div> </div>
<div class="header-nav"> <div class="header-nav">
<a class="active nav-link nav-text">Shoutbox</a> <a class="active nav-link nav-text">Shoutbox</a>
</div> </div>
</header> </header>
<div class="content-container"> <div class="content-container">
<div class="content-area"> <div class="content-area">
<div class="clr-row"> <div class="clr-row">
<div class="clr-col-lg-5 clr-col-md-8 clr-col-12"> <div class="clr-col-lg-6 clr-col-md-8 clr-col-12">
<div class="card">
<h3 class="card-header">Wallets in use</h3>
<div class="clr-row">
<div class="clr-col-lg-6 clr-col-md-8 clr-col-12">
<div class="card-block">
<clr-input-container>
<label>User Wallet 1 Address</label>
<input clrInput [disabled]="true" required type="text" [(ngModel)]="userWallet.address"
name="title" size="29" />
</clr-input-container>
<clr-input-container>
<label>Secret</label>
<input clrInput [disabled]="true" required type="text" [(ngModel)]="userWallet.secret"
name="title" size="29" />
</clr-input-container>
</div>
</div>
<div class="clr-col-lg-6 clr-col-md-8 clr-col-12">
<div class="card-block">
<clr-input-container>
<label>User Wallet 2 Address</label>
<input clrInput [disabled]="true" required type="text" [(ngModel)]="drainWallet.address"
name="title" size="29" />
</clr-input-container>
<clr-input-container>
<label>Secret</label>
<input clrInput [disabled]="true" required type="text" [(ngModel)]="drainWallet.secret"
name="title" size="29" />
</clr-input-container>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="clr-row">
<div class="clr-col-lg-6 clr-col-md-8 clr-col-12">
<div class="card"> <div class="card">
<h3 class="card-header">Shout Something</h3> <h3 class="card-header">Shout Something</h3>
<form clrForm #loginForm="ngForm"> <form clrForm #loginForm="ngForm">
@@ -21,20 +68,27 @@
<div class="card-block"> <div class="card-block">
<clr-input-container> <clr-input-container>
<input clrInput [disabled]="sending" required placeholder="Title" type="text" <input clrInput [disabled]="sending" required placeholder="Title" type="text"
[(ngModel)]="newShout.title" name="title" /> [(ngModel)]="newShout.title" name="title" size="45" />
</clr-input-container> </clr-input-container>
<textarea clrTextarea [disabled]="sending" required placeholder="Shout Body" type="text" <textarea clrTextarea [disabled]="sending" required placeholder="Shout Body" type="text"
[(ngModel)]="newShout.body" name="body"></textarea> [(ngModel)]="newShout.body" name="body" cols="43" rows="15"></textarea>
<clr-input-container> <clr-input-container>
<input clrInput [disabled]="sending" required placeholder="Your Name" type="text" <input clrInput [disabled]="sending" required placeholder="Your Name" type="text"
[(ngModel)]="newShout.from" name="from" /> [(ngModel)]="newShout.from" name="from" size="45" />
</clr-input-container> </clr-input-container>
</div> </div>
<div class="card-footer"> <div class="card-footer">
<button class="btn btn-success" (click)="submitShout()" <button class="btn btn-success" (click)="submitShout()"
[disabled]="!loginForm.form.valid || sending">Shout</button> [disabled]="!loginForm.form.valid || sending">Shout</button>
<span *ngIf="sending">Sending...</span>
<span *ngIf="waiting">It may take up to 30 seconds for the new entry to persist</span> <span *ngIf="sending">Sending...</span>
<span *ngIf="waiting">
TX <a [href]="'https://testnet.xrpl.org/transactions/'+lastMessageHash+'/detailed'" target="_blank">
<cds-icon shape="link"></cds-icon>
</a>
<br />
It may take up to 30 seconds for the new entry to persist
</span>
</div> </div>
</form> </form>
</div> </div>
@@ -42,7 +96,7 @@
</div> </div>
<div class="clr-row" *ngIf="initializing"> <div class="clr-row" *ngIf="initializing">
<div class="clr-col-lg-5 clr-col-md-8 clr-col-12"> <div class="clr-col-lg-6 clr-col-md-8 clr-col-12">
<div class="card"> <div class="card">
<h3 class="card-header">Syncing application state</h3> <h3 class="card-header">Syncing application state</h3>
<div class="card-block"> <div class="card-block">
@@ -56,9 +110,14 @@
</div> </div>
<div class="clr-row" *ngFor="let shout of shouts"> <div class="clr-row" *ngFor="let shout of shouts">
<div class="clr-col-lg-5 clr-col-md-8 clr-col-12"> <div class="clr-col-lg-6 clr-col-md-8 clr-col-12">
<div class="card"> <div class="card">
<h3 class="card-header">{{shout.title}}</h3> <h3 class="card-header">
{{shout.title}}
<a [href]="'https://testnet.xrpl.org/transactions/'+shout.hash+'/detailed'" target="_blank">
<cds-icon shape="link"></cds-icon>
</a>
</h3>
<div class="card-block"> <div class="card-block">
<div class="card-text"> <div class="card-text">
{{shout.body}} {{shout.body}}
+41 -19
View File
@@ -1,12 +1,15 @@
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { ShoutboxDataService } from './services/ShoutboxData.service'; import { ShoutboxDataService } from './services/ShoutboxData.service';
import { makeTestnetWallet } from './util/TestnetUtils';
@Component({ @Component({
selector: 'app-root', selector: 'app-root',
templateUrl: './app.component.html', templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'], styleUrls: ['./app.component.scss'],
}) })
export class AppComponent implements OnInit{ export class AppComponent implements OnInit {
lastMessageHash = ""
contractAddress = "";
initializing = true initializing = true
waiting = false waiting = false
title = 'httXrp Shoutbox'; title = 'httXrp Shoutbox';
@@ -15,34 +18,53 @@ export class AppComponent implements OnInit{
newShout = { newShout = {
title: "", title: "",
body: "", body: "",
from: "" from: "",
hash: ""
}
userWallet = {
address: "",
secret: ""
}
drainWallet = {
address: "",
secret: ""
} }
constructor( constructor(
private dataService: ShoutboxDataService private dataService: ShoutboxDataService
){} ) {
this.contractAddress = dataService.getContractAddress()
}
submitShout = () => { submitShout = () => {
this.sending = true this.sending = true
this.dataService.submitShout(this.newShout) this.dataService.submitShout(this.newShout)
.then(() => { .then((hash) => {
this.newShout = { this.newShout = {
title: "", title: "",
body: "", body: "",
from: "" from: "",
} hash: ""
}) }
.finally(() => { this.lastMessageHash = hash
this.sending = false })
this.waiting = true .finally(() => {
setTimeout(() => {this.waiting = false}, 20000) this.sending = false
}) this.waiting = true
setTimeout(() => { this.waiting = false }, 20000)
})
} }
ngOnInit(){ ngOnInit() {
this.dataService.initialize((shout:any) => { Promise.all([makeTestnetWallet(), makeTestnetWallet()]).then(([userWallet, drainWallet]) => {
this.shouts.unshift(shout) console.log(userWallet, drainWallet)
this.initializing = false this.userWallet = userWallet
this.drainWallet = drainWallet
this.dataService.initialize((shout: any) => {
this.shouts.unshift(shout)
this.initializing = false
}, userWallet, drainWallet)
}) })
} }
} }
+2 -1
View File
@@ -6,7 +6,7 @@ import { AppComponent } from './app.component';
import { CdsModule } from '@cds/angular'; import { CdsModule } from '@cds/angular';
import { ClarityModule } from '@clr/angular'; import { ClarityModule } from '@clr/angular';
import { ClarityIcons, homeIcon } from '@cds/core/icon'; import { ClarityIcons, homeIcon, linkIcon } from '@cds/core/icon';
import { ShoutboxDataService } from './services/ShoutboxData.service'; import { ShoutboxDataService } from './services/ShoutboxData.service';
import { FormsModule } from '@angular/forms'; import { FormsModule } from '@angular/forms';
@@ -27,5 +27,6 @@ import { FormsModule } from '@angular/forms';
export class AppModule { export class AppModule {
constructor() { constructor() {
ClarityIcons.addIcons(homeIcon); ClarityIcons.addIcons(homeIcon);
ClarityIcons.addIcons(linkIcon);
} }
} }
@@ -1,5 +1,4 @@
import { Injectable } from "@angular/core"; import { Injectable } from "@angular/core";
import { makeTestnetWallet } from "../util/TestnetUtils";
import { z } from 'zod'; import { z } from 'zod';
declare const RJSVM: any; declare const RJSVM: any;
@@ -16,15 +15,12 @@ export class ShoutboxDataService {
private dataWriter = undefined as any private dataWriter = undefined as any
public submitShout = async (shout: any) => { public submitShout = async (shout: any) => {
await this.dataWriter.callEndpoint('submit', shout, 10) return await this.dataWriter.callEndpoint('submit', shout, 10)
} }
public getContractAddress = () => listeningAddress
initialize = async (onData:Function) => { initialize = async (onData:Function, userWallet?:any, drainWallet?:any) => {
const [userWallet, drainWallet] = await Promise.all([makeTestnetWallet(), makeTestnetWallet()])
console.log(userWallet, drainWallet)
this.dataWriter = new Datawriter({ this.dataWriter = new Datawriter({
receiveAddress: drainWallet.address, receiveAddress: drainWallet.address,
@@ -74,8 +70,8 @@ export class ShoutboxDataService {
const RJSVM_Contract = { const RJSVM_Contract = {
submit: { submit: {
implementation: function (env:any, shout:any) { implementation: function (env:any, shout: any) {
console.log(shout); shout.hash = env.hash;
(this as any).state.shouts.unshift(shout) (this as any).state.shouts.unshift(shout)
}, },
visibility: 'public', visibility: 'public',
+1 -1
View File
@@ -11,7 +11,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico"> <link rel="icon" type="image/x-icon" href="favicon.ico">
<script src="https://cdn.jsdelivr.net/npm/rjsvm@0.3.1/lib/browser/rjsvm.browser.js"></script> <script src="https://cdn.jsdelivr.net/npm/rjsvm@0.3.2/lib/browser/rjsvm.browser.js"></script>
</head> </head>
<body cds-text="body" cds-theme="dark"> <body cds-text="body" cds-theme="dark">
<app-root></app-root> <app-root></app-root>