Browse Source

Working on the buying process

vue
Lev 2 years ago
parent
commit
7f8edd24f7
  1. 1
      .babelrc
  2. 31
      .idea/workspace.xml
  3. 31770
      package-lock.json
  4. 6
      package.json
  5. 1
      src/assets/main.css
  6. 1
      src/components/DarkLayout.vue
  7. 9
      src/components/DomainBar.vue
  8. 46
      src/components/DomainResult.vue
  9. 14
      src/components/Header.vue
  10. 12
      src/components/LoginModal.vue
  11. 2
      src/components/WhiteLayout.vue
  12. 1
      src/main.ts
  13. 34
      src/result.ts
  14. 39
      src/utils.ts
  15. 4
      src/views/Get.vue

1
.babelrc

@ -0,0 +1 @@
{ "presets":["@babel/env"] }

31
.idea/workspace.xml

@ -2,15 +2,21 @@
<project version="4">
<component name="ChangeListManager">
<list default="true" id="ddb8afd5-d3ba-47b1-b6d0-227403f1abf7" name="Changes" comment="TON Connect is working">
<change afterPath="$PROJECT_DIR$/src/utils.ts" afterDir="false" />
<change afterPath="$PROJECT_DIR$/.babelrc" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/package-lock.json" beforeDir="false" afterPath="$PROJECT_DIR$/package-lock.json" afterDir="false" />
<change beforePath="$PROJECT_DIR$/package.json" beforeDir="false" afterPath="$PROJECT_DIR$/package.json" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/assets/main.css" beforeDir="false" afterPath="$PROJECT_DIR$/src/assets/main.css" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/components/DarkLayout.vue" beforeDir="false" afterPath="$PROJECT_DIR$/src/components/DarkLayout.vue" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/components/DomainBar.vue" beforeDir="false" afterPath="$PROJECT_DIR$/src/components/DomainBar.vue" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/components/DomainResult.vue" beforeDir="false" afterPath="$PROJECT_DIR$/src/components/DomainResult.vue" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/components/Header.vue" beforeDir="false" afterPath="$PROJECT_DIR$/src/components/Header.vue" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/components/LoginModal.vue" beforeDir="false" afterPath="$PROJECT_DIR$/src/components/LoginModal.vue" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/components/ZoneTable.vue" beforeDir="false" afterPath="$PROJECT_DIR$/src/components/ZoneTable.vue" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/components/WhiteLayout.vue" beforeDir="false" afterPath="$PROJECT_DIR$/src/components/WhiteLayout.vue" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/main.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/views/Checkout.vue" beforeDir="false" afterPath="$PROJECT_DIR$/src/views/Checkout.vue" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/views/Find.vue" beforeDir="false" afterPath="$PROJECT_DIR$/src/views/Find.vue" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/result.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/result.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/utils.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/utils.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/views/Get.vue" beforeDir="false" afterPath="$PROJECT_DIR$/src/views/Get.vue" afterDir="false" />
</list>
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
@ -49,10 +55,16 @@
}</component>
<component name="RecentsManager">
<key name="MoveFile.RECENT_KEYS">
<recent name="$PROJECT_DIR$/src" />
<recent name="$PROJECT_DIR$" />
<recent name="$PROJECT_DIR$/src/assets/headers" />
<recent name="$PROJECT_DIR$/src/assets/images" />
<recent name="$PROJECT_DIR$/src/assets/icons" />
</key>
<key name="es6.move.members.recent.items">
<recent name="$PROJECT_DIR$/src/utils.ts" />
<recent name="$PROJECT_DIR$/src/api.ts" />
</key>
</component>
<component name="RunManager">
<configuration name="dev" type="js.build_tools.npm" nameIsGenerated="true">
@ -86,7 +98,7 @@
<workItem from="1672337938860" duration="148000" />
<workItem from="1672483245701" duration="3321000" />
<workItem from="1672753446569" duration="4197000" />
<workItem from="1672782388693" duration="8939000" />
<workItem from="1672782388693" duration="19429000" />
</task>
<task id="LOCAL-00001" summary="Wrote the landing">
<created>1670844191163</created>
@ -207,7 +219,14 @@
<option name="project" value="LOCAL" />
<updated>1672843430677</updated>
</task>
<option name="localTasksCounter" value="18" />
<task id="LOCAL-00018" summary="TON Connect is working">
<created>1672850074714</created>
<option name="number" value="00018" />
<option name="presentableId" value="LOCAL-00018" />
<option name="project" value="LOCAL" />
<updated>1672850074714</updated>
</task>
<option name="localTasksCounter" value="19" />
<servers />
</component>
<component name="TypeScriptGeneratedFilesManager">

31770
package-lock.json generated

File diff suppressed because it is too large Load Diff

6
package.json

@ -16,16 +16,22 @@
"bulma": "^0.9.4",
"qr-code-styling": "^1.6.0-rc.1",
"sass": "^1.56.2",
"tonweb": "^0.0.59",
"vue": "^3.2.45",
"vue-contenteditable": "^4.1.0",
"vue-router": "^4.1.6",
"vue3-popper": "^1.5.0",
"semver": "^7.3.8",
"vuex": "^4.0.2"
},
"devDependencies": {
"@babel/cli": "^7.20.7",
"@babel/core": "^7.20.12",
"@babel/preset-env": "^7.20.2",
"@types/node": "^18.11.16",
"@vitejs/plugin-vue": "^4.0.0",
"@vue/tsconfig": "^0.1.3",
"buffer": "^6.0.3",
"npm-run-all": "^4.1.5",
"tailwindcss": "^3.2.4",
"typescript": "~4.7.4",

1
src/assets/main.css

@ -1,4 +1,5 @@
@import './base.css';
@tailwind base;
@tailwind components;
@tailwind utilities;

1
src/components/DarkLayout.vue

@ -42,5 +42,4 @@ export default {
min-width: 16rem;
margin: 0.5rem 3rem;
}
</style>

9
src/components/DomainBar.vue

@ -1,7 +1,8 @@
<template>
<div :class="{'domain-bar': true, 'center': !has_button}">
<div style="display: flex" class="prompt-cont">
<contenteditable :contenteditable="editable" tag="div" class="prompt" :no-nl="true" v-model="val" :no-html="true" @returned="search()" spellcheck="false"></contenteditable>
<contenteditable :contenteditable="editable" tag="div" class="prompt" :no-nl="true" v-model="val" :no-html="true"
ref="domain_field" @returned="search()" spellcheck="false"></contenteditable>
<div class="post-prompt">{{ zone }}</div>
</div>
<div class="search" v-if="has_button" @click="search()">Search</div>
@ -37,6 +38,9 @@ export default {
val: this.value
}
},
mounted() {
this.$refs["domain_field"].$el.focus();
},
methods: {
search() {
this.$emit("search", this.val);
@ -57,7 +61,7 @@ export default {
<style scoped>
.domain-bar {
border-radius: 1rem;
width: 30rem;
min-width: 30rem;
min-height: 5rem;
padding: 0 1rem;
background-color: #4e5a88;
@ -79,6 +83,7 @@ export default {
/* the bar is narrower on mobile (90% of the screen) */
@media only screen and (max-width: 800px) {
.domain-bar {
min-width: revert;
width: 90vw;
/* allow multiple rows with 0.5 spacing */
flex-wrap: wrap;

46
src/components/DomainResult.vue

@ -2,18 +2,24 @@
<div class="center" v-if="result === null">
<RotateSquare2 style="width: 5rem; height: 5rem; margin-top: 3rem;"/>
</div>
<GetDomainBtn v-else-if="result.canBuy()"
<GetDomainBtn v-else-if="result.canBuy() && result.condition_fullfilled !== false"
:domain="domain" :price="result.auction_price"
:collection_required="result.collection_required"
@click="$router.push({name: 'Checkout', params: result.getRouteParams()})"/>
@click="buy()"/>
<!-- todo: differentiate between auction and buy -->
<GetDomainBtn v-else-if="result.canAuction()"
<GetDomainBtn v-else-if="result.canAuction() && result.condition_fullfilled !== false"
:domain="domain" :price="result.auction_price"
@click="$router.push({name: 'Checkout', params: result.getRouteParams()})"/>
@click="buy()"/>
<div class="owned" v-else-if="result.canBuy() && result.condition_fullfilled === false" style="cursor:initial;">
<p>To buy</p>
<p><span class="domain">*.{{ zone }}</span></p>
<p>you need to be a holder of the collection</p>
<div class="collection">{{ result.collection_required.name }}</div>
</div>
<div v-else class="owned" @click="$router.push({name: 'Explore', params: {domain: domain}})">
<p class="domain">{{ domain }}</p>
<p>is owned.</p>
<p>Click here to explore</p>
<p>Click here to explore or manage</p>
</div>
</template>
@ -21,6 +27,7 @@
import RotateSquare2 from "./RotateSquare2.vue";
import {get_domain_result} from "../result";
import GetDomainBtn from "./GetDomainBtn.vue";
import {parse_zone} from "../utils";
export default {
name: "DomainResult",
@ -38,13 +45,33 @@ export default {
},
methods: {
async get_result() {
this.result = await get_domain_result(this.domain);
this.result = await get_domain_result(this.domain, this.$store.getters.address);
},
buy() {
if (this.$store.getters.is_connected) {
this.$router.push({name: 'Checkout', params: this.result.getRouteParams()})
// todo
} else {
this.$emit('login');
}
}
},
watch: {
domain: function () {
this.result = null;
this.get_result();
},
is_connected: function () {
this.result = null;
this.get_result();
}
},
computed: {
zone() {
return parse_zone(this.domain);
},
is_connected() {
return this.$store.getters.is_connected;
}
}
}
@ -73,4 +100,11 @@ export default {
padding: 2rem;
cursor: pointer;
}
.collection {
border-radius: 10px;
background-color: white;
color: #0088cc;
}
</style>

14
src/components/Header.vue

@ -10,7 +10,7 @@
<slot></slot>
</div>
<!-- right-aligned login button -->
<div class="login-b">
<div class="login-b" v-if="showLogin">
<button class="b blue wide" @click="$emit('login-modal')" v-if="!$store.getters.is_connected">
<span>Login</span>
</button>
@ -28,15 +28,23 @@
<script>
export default {
name: "Header",
props: {
showLogin: {
type: Boolean,
default: true
}
},
computed: {
address() {
if (!this.$store.getters.is_connected) {
return '';
}
let address = this.$store.getters.address;
if (address === undefined) {
let address_raw = this.$store.getters.address;
if (address_raw === undefined) {
return '';
}
// let address = convert_address(address_raw);
let address = address_raw;
return address.slice(0, 5) + '...' + address.slice(-4);
}
}

12
src/components/LoginModal.vue

@ -16,10 +16,12 @@
</div>
</div>
<div class="modal__body center">
<div class="modal__body content center">
<div class="text">To log in, scan this:</div>
<div class="qr center">
<div ref="loginqr" class="center qr-in"></div>
</div>
<a :href="connection_url" class="b blue wide">Or click here</a>
</div>
</div>
</div>
@ -166,4 +168,12 @@ export default {
background-color: white;
border-radius: 1.5rem;
}
.content {
padding: 2.5rem 32px;
text-align: center;
display: inline-block;
font-size: 1.6rem;
color: white;
}
</style>

2
src/components/WhiteLayout.vue

@ -1,6 +1,6 @@
<template>
<div style="width: 100vw">
<Header/>
<Header :show-login="false"/>
<div class="header-logo">
<slot name="header"></slot>
</div>

1
src/main.ts

@ -5,7 +5,6 @@ import {createStore} from 'vuex'
import TonConnect from '@tonconnect/sdk';
import {isWalletInfoInjected} from '@tonconnect/sdk';
import type {WalletInfo, WalletInfoInjected, WalletInfoRemote} from '@tonconnect/sdk';
import './assets/main.css'
const app = createApp(App)

34
src/result.ts

@ -2,6 +2,7 @@
import {Zone} from "@/zone";
import {Collection} from "@/collection";
import {parse_zone} from "@/utils";
let ex_collection = () => new Collection("example.ton", "Example collection");
@ -11,13 +12,15 @@ export class Result {
auction_price?: number;
owner?: string;
collection_required: Collection | null;
condition_fullfilled: boolean | null = null;
constructor(domain: string, buy_price?: number, auction_price?: number, owner?: string, collection_required: Collection | null = null) {
constructor(domain: string, buy_price?: number, auction_price?: number, owner?: string, collection_required: Collection | null = null, condition_fullfilled: boolean | null = null) {
this.domain = domain;
this.buy_price = buy_price;
this.auction_price = auction_price;
this.owner = owner;
this.collection_required = collection_required;
this.condition_fullfilled = condition_fullfilled;
}
getRouteParams(): any {
@ -29,11 +32,11 @@ export class Result {
}
canAuction(): boolean {
return this.auction_price !== undefined && this.auction_price !== null;
return this.auction_price !== undefined && this.auction_price !== null && this.owner === undefined;
}
canBuy(): boolean {
return this.buy_price !== undefined && this.buy_price !== null;
return this.buy_price !== undefined && this.buy_price !== null && this.owner === undefined;
}
zone(): string {
@ -56,26 +59,27 @@ export async function get_search_results(query: string) {
];
}
function parse_zone(domain: string) {
// extract the zone from the domain (e.g. example.ton from 123.example.ton)
return domain.split('.').slice(1).join('.');
}
export async function get_domain_result(domain: string) {
export async function get_domain_result(domain: string, address?: string) {
// return await call_api('get/' + domain);
await sleep(100);
if (domain === 'test.ton') {
return new Result(domain);
}
// if (domain.split('.')[0] === 'owned') {
// return new Result(domain, 5, 3, '123');
// }
console.log(domain);
console.log(domain.split('.'))
let exc = ex_collection();
if (domain.startsWith('owned')) {
return new Result(domain, 5, 3, '123');
}
if (parse_zone(domain) === 'example.ton') {
return new Result(domain, 5, 3, undefined, exc);
}
if (parse_zone(domain) === 'testtesttest.ton') {
console.log(address)
if (address !== undefined && address !== '') {
return new Result(domain, 5, 3, undefined, exc, false);
} else {
return new Result(domain, 5, 3, undefined, exc);
}
}
return new Result(domain, 5, 3);
}
@ -85,7 +89,7 @@ export async function get_zones() {
return [
new Zone("example.ton", 3, 5, ex_collection()),
new Zone("agorata.ton", 3, 5),
new Zone("testtesttest.ton", 1, 1)];
new Zone("testtesttest.ton", 1, 1, ex_collection())];
}
export class TonLink {

39
src/utils.ts

@ -7,30 +7,39 @@ export function qr_options(url: string, imageSize: number = 0.4, imageMargin: nu
image: '/logo_mono.png',
margin: margin,
qrOptions: {
typeNumber: 0,
mode: 'Byte',
errorCorrectionLevel: 'Q'
typeNumber: 0,
mode: 'Byte',
errorCorrectionLevel: 'Q'
},
imageOptions: {
hideBackgroundDots: true,
imageSize: imageSize,
margin: imageMargin,
crossOrigin: 'anonymous',
hideBackgroundDots: true,
imageSize: imageSize,
margin: imageMargin,
crossOrigin: 'anonymous',
},
dotsOptions: {
color: '#282e46',
type: 'rounded'
color: '#282e46',
type: 'rounded'
},
backgroundOptions: {
color: '#ffffff',
color: '#ffffff',
},
cornersSquareOptions: {
color: '#282e46',
type: 'extra-rounded',
color: '#282e46',
type: 'extra-rounded',
},
cornersDotOptions: {
color: '#282e46',
type: 'dot',
color: '#282e46',
type: 'dot',
}
}
}
}
// export function convert_address(address_raw: string): string {
// const address = new TonWeb.utils.Address(address_raw);
// return address.toString(true, true, true);
// }
export function parse_zone(domain: string) {
// extract the zone from the domain (e.g. example.ton from 123.example.ton)
return domain.split('.').slice(1).join('.');
}

4
src/views/Get.vue

@ -1,5 +1,5 @@
<template>
<DarkLayout>
<DarkLayout ref="dl">
<template v-slot:header>
<router-link :to="{name: 'Find'}">
<button class="b darkish back">
@ -9,7 +9,7 @@
</router-link>
</template>
<DomainBar :zone="'.' + zone" :value="domain" @search="search()" @input_d="handle_input($event)"/>
<DomainResult :domain="domain + '.' + zone"/>
<DomainResult :domain="domain + '.' + zone" v-if="domain !== ''" @login="$refs.dl.login()"/>
</DarkLayout>
</template>

Loading…
Cancel
Save