wip store

This commit is contained in:
Martti Malmi 2020-11-25 17:34:53 +02:00
parent 363a8246b9
commit b29f8680f8
4 changed files with 124 additions and 134 deletions

View File

@ -78,9 +78,10 @@ class Main extends Component {
<${Settings} path="/settings"/>
<${LogoutConfirmation} path="/logout"/>
<${Profile.Profile} path="/profile/:id"/>
<${StoreView} path="/store/:id"/>
<${CheckoutView} path="/checkout/:id"/>
<${ProductView} path="/product/:id/:store"/>
<${StoreView} path="/store/:store"/>
<${CheckoutView} path="/checkout/:store"/>
<${ProductView} path="/product/:product/:store"/>
<${ProductView} path="/product/new"/>
<${FollowsView} path="/follows/:id"/>
<${FollowsView} followers=${true} path="/followers/:id"/>
</${Router}>

View File

@ -15,33 +15,24 @@ import MessageFeed from './MessageFeed.js';
import Identicon from './Identicon.js';
import Name from './Name.js';
import SearchBox from './SearchBox.js';
import StoreView from './StoreView.js';
class CheckoutView extends Component {
class CheckoutView extends StoreView {
constructor() {
super();
this.eventListeners = [];
this.followedUsers = new Set();
this.followers = new Set();
this.cart = {};
this.state = {
paymentMethod: 'bitcoin',
items: {
aa: {name: 'Doge T-shirt', description: 'Amazing t shirt with doge', price: '100€'},
bb: {name: 'Doge Mug', description: 'Wonderful mug with doge', price: '200€'},
cc: {name: 'Iris Sticker', description: 'Very sticky stickers', price: '10€'},
dd: {name: 'Iris virtual badge', description: 'Incredible profile badge', price: '5€'},
ee: {name: 'Gun hosting', description: 'Top gun hosting', price: '10€ / month'}
}
};
this.state.paymentMethod = 'bitcoin';
}
changeItemCount(k, v, e) {
this.cart[k] = Math.max(this.cart[k] + v, 0);
localState.get('cart').get(this.props.id).get(k).put(this.cart[k]);
localState.get('cart').get(this.props.store).get(k).put(this.cart[k]);
}
confirm() {
const pub = this.props.id;
const pub = this.props.store;
localState.get('cart').get(pub).map().once((v, k) => {
!!v && localState.get('cart').get(pub).get(k).put(null);
});
@ -51,19 +42,18 @@ class CheckoutView extends Component {
}
renderCart() {
const total = Object.keys(this.cart).reduce((sum, currentKey) => {
return sum + parseInt(this.state.items[currentKey].price) * this.cart[currentKey];
}, 0);
return html`
<h3 class="side-padding-xs">Shopping cart</h3>
<div class="flex-table">
${Object.keys(this.cart).filter(k => !!this.cart[k]).map(k => {
${Object.keys(this.cart).filter(k => !!this.cart[k] && !!this.state.items[k]).map(k => {
const i = this.state.items[k];
return html`
<div class="flex-row">
<div class="flex-cell">
<${SafeImg} src=${i.thumbnail}/>
${i.name}
<a href=${'/product/' + k + '/' + this.props.store}>
<${SafeImg} src=${i.thumbnail}/>
${i.name || 'item'}
</a>
</div>
<div class="flex-cell no-flex price-cell">
<p>
@ -79,7 +69,7 @@ class CheckoutView extends Component {
})}
<div class="flex-row">
<div class="flex-cell"></div>
<div class="flex-cell no-flex"><b>Total ${total} </b></div>
<div class="flex-cell no-flex"><b>Total ${this.state.totalPrice} </b></div>
</div>
</div>
<p class="side-padding-xs">
@ -133,9 +123,6 @@ class CheckoutView extends Component {
}
renderConfirmation() {
const total = Object.keys(this.cart).reduce((sum, currentKey) => {
return sum + parseInt(this.state.items[currentKey].price) * this.cart[currentKey];
}, 0);
return html`
<h3 class="side-padding-xs">Confirmation</h3>
<div class="flex-table">
@ -145,7 +132,7 @@ class CheckoutView extends Component {
<div class="flex-row">
<div class="flex-cell">
<${SafeImg} src=${i.thumbnail}/>
${i.name}
${i.name || 'item'}
</div>
<div class="flex-cell no-flex price-cell">
<p>
@ -158,7 +145,7 @@ class CheckoutView extends Component {
})}
<div class="flex-row">
<div class="flex-cell"></div>
<div class="flex-cell no-flex"><b>Total ${total} </b></div>
<div class="flex-cell no-flex"><b>Total ${this.state.totalPrice} </b></div>
</div>
</div>
<p>
@ -188,7 +175,7 @@ class CheckoutView extends Component {
<div class="main-view" id="profile">
<div class="content">
<p>
<a href="/store/${this.props.id}"><iris-profile-attribute pub=${this.props.id}/></a>
<a href="/store/${this.props.store}"><iris-profile-attribute pub=${this.props.store}/></a>
</p>
<div id="store-steps">
<div class=${p === 'cart' ? 'active' : ''} onClick=${() => this.setState({page:'cart'})}>Cart</div>
@ -206,19 +193,19 @@ class CheckoutView extends Component {
}
componentDidUpdate(prevProps) {
if (prevProps.id !== this.props.id) {
if (prevProps.store !== this.props.store) {
this.componentDidMount();
}
}
componentDidMount() {
const pub = this.props.id;
StoreView.prototype.componentDidMount.call(this);
const pub = this.props.store;
this.setState({page:'cart'})
this.eventListeners.forEach(e => e.off());
this.cart = {};
localState.get('cart').get(pub).map().on((v, k) => {
this.cart[k] = v;
this.setState({cart: this.cart})
this.setState({cart: this.cart});
});
localState.get('paymentMethod').on(paymentMethod => this.setState({paymentMethod}));
localState.get('delivery').open(delivery => this.setState({delivery}));

View File

@ -15,33 +15,47 @@ import MessageFeed from './MessageFeed.js';
import Identicon from './Identicon.js';
import Name from './Name.js';
import SearchBox from './SearchBox.js';
import StoreView from './StoreView.js';
class ProductView extends Component {
class ProductView extends StoreView {
constructor() {
super();
this.eventListeners = [];
this.followedUsers = new Set();
this.followers = new Set();
this.cart = {};
this.state = {
items: {
aa: {name: 'Doge T-shirt', description: 'Amazing t shirt with doge', price: '100€'},
bb: {name: 'Doge Mug', description: 'Wonderful mug with doge', price: '200€'},
cc: {name: 'Iris Sticker', description: 'Very sticky stickers', price: '10€'},
dd: {name: 'Iris virtual badge', description: 'Incredible profile badge', price: '5€'},
ee: {name: 'Gun hosting', description: 'Top gun hosting', price: '10€ / month'}
}
};
}
addToCart() {
const count = (this.cart[this.props.id] || 0) + 1;
localState.get('cart').get(this.props.store).get(this.props.id).put(count);
const count = (this.cart[this.props.product] || 0) + 1;
localState.get('cart').get(this.props.store).get(this.props.product).put(count);
}
showProduct() {
newProduct() {
return html`
<div class="main-view" id="profile">
<div class="content">
<a href="/store/${Session.getPubKey()}"><iris-profile-attribute pub=${Session.getPubKey()} /></a>
<h3>Add item</h3>
<h2 contenteditable placeholder="Item name" onInput=${e => this.newProductName = e.target.innerText} />
<textarea placeholder="Item description" onInput=${e => this.newProductDescription = e.target.value} style="resize: vertical"/>
<input type="number" placeholder="Price" onInput=${e => this.newProductPrice = parseInt(e.target.value)}/>
<hr/>
<p>
Item ID:
</p>
<p>
<input placeholder="Item ID" onInput=${e => this.newProductId = e.target.value} />
</p>
<button onClick=${e => this.addItemClicked(e)}>Add item</button>
</div>
</div>
`;
}
render() {
const cartTotalItems = Object.values(this.cart).reduce((sum, current) => sum + current, 0);
const i = this.state.items[this.props.id];
const i = this.state.product;
if (!i) return html``;
return html`
<div class="main-view" id="profile">
<div class="content">
@ -51,64 +65,52 @@ class ProductView extends Component {
<button onClick=${() => route('/checkout/' + this.props.store)}>Shopping cart (${cartTotalItems})</button>
</p>
` : ''}
<h3>${i.name}</h3>
<${SafeImg} src=${i.thumbnail}/>
<p class="description">${i.description}</p>
<p class="price">${i.price}</p>
<button class="add" onClick=${() => this.addToCart()}>
Add to cart
${this.cart[this.props.id] ? ` (${this.cart[this.props.id]})` : ''}
</button>
${this.state.product ? html`
<h3>${i.name}</h3>
<${SafeImg} src=${i.thumbnail}/>
<p class="description">${i.description}</p>
<p class="price">${i.price}</p>
<button class="add" onClick=${() => this.addToCart()}>
Add to cart
${this.cart[this.props.product] ? ` (${this.cart[this.props.product]})` : ''}
</button>
` : ''}
${this.props.store && this.props.product ? '' : this.newProduct()}
</div>
</div>`;
}
newProduct() {
return html`<div class="main-view">add product</div>`
}
render() {
this.isMyProfile = Session.getPubKey() === this.props.id;
const chat = chats[this.props.id];
const uuid = chat && chat.uuid;
const messageForm = this.isMyProfile ? html`<${MessageForm} class="hidden-xs" autofocus=${false} activeChat="public"/>` : '';
const followable = !(this.isMyProfile || this.props.id.length < 40);
let profilePhoto;
if (this.isMyProfile) {
profilePhoto = html`<${ProfilePhotoPicker} currentPhoto=${this.state.photo} placeholder=${this.props.id} callback=${src => this.onProfilePhotoSet(src)}/>`;
} else {
if (this.state.photo) {
profilePhoto = html`<${SafeImg} class="profile-photo" src=${this.state.photo}/>`
} else {
profilePhoto = html`<${Identicon} str=${this.props.id} width=250/>`
}
}
if (this.props.id && this.props.store) {
return this.showProduct();
}
return this.newProduct();
}
componentWillUnmount() {
this.eventListeners.forEach(e => e.off());
}
componentDidUpdate(prevProps) {
if (prevProps.id !== this.props.id) {
if (prevProps.product !== this.props.product) {
this.componentDidMount();
}
}
addItemClicked(e) {
const product = {
name: this.newProductName,
description: this.newProductDescription,
price: this.newProductPrice
};
console.log(product);
publicState.user().get('store').get('products').get(this.newProductId).put(product);
route(`/store/${Session.getPubKey()}`)
}
componentDidMount() {
const pub = this.props.id;
StoreView.prototype.componentDidMount.call(this);
const pub = this.props.store;
this.eventListeners.forEach(e => e.off());
this.setState({followedUserCount: 0, followerCount: 0, name: '', photo: '', about: ''});
this.isMyProfile = Session.getPubKey() === pub;
this.cart = {};
localState.get('cart').get(this.props.store).map().on((v, k) => {
this.cart[k] = v;
this.setState({cart: this.cart})
});
if (this.props.product && pub) {
publicState.user(pub).get('store').get('products').get(this.props.product).on(product => this.setState({product}));
}
}
}

View File

@ -23,38 +23,31 @@ class StoreView extends Component {
this.followedUsers = new Set();
this.followers = new Set();
this.cart = {};
this.state = {
items: {
aa: {name: 'Doge T-shirt', description: 'Amazing t shirt with doge', price: '100€'},
bb: {name: 'Doge Mug', description: 'Wonderful mug with doge', price: '200€'},
cc: {name: 'Iris Sticker', description: 'Very sticky stickers', price: '10€'},
dd: {name: 'Iris virtual badge', description: 'Incredible profile badge', price: '5€'},
ee: {name: 'Gun hosting', description: 'Top gun hosting', price: '10€ / month'}
}
};
this.state = {items:{}};
this.items = {};
}
addToCart(k, e) {
e.stopPropagation();
const count = (this.cart[k] || 0) + 1;
localState.get('cart').get(this.props.id).get(k).put(count);
localState.get('cart').get(this.props.store).get(k).put(count);
}
render() {
const cartTotalItems = Object.values(this.cart).reduce((sum, current) => sum + current, 0);
this.isMyProfile = Session.getPubKey() === this.props.id;
const chat = chats[this.props.id];
this.isMyProfile = Session.getPubKey() === this.props.store;
const chat = chats[this.props.store];
const uuid = chat && chat.uuid;
const messageForm = this.isMyProfile ? html`<${MessageForm} class="hidden-xs" autofocus=${false} activeChat="public"/>` : '';
const followable = !(this.isMyProfile || this.props.id.length < 40);
const followable = !(this.isMyProfile || this.props.store.length < 40);
let profilePhoto;
if (this.isMyProfile) {
profilePhoto = html`<${ProfilePhotoPicker} currentPhoto=${this.state.photo} placeholder=${this.props.id} callback=${src => this.onProfilePhotoSet(src)}/>`;
profilePhoto = html`<${ProfilePhotoPicker} currentPhoto=${this.state.photo} placeholder=${this.props.store} callback=${src => this.onProfilePhotoSet(src)}/>`;
} else {
if (this.state.photo) {
profilePhoto = html`<${SafeImg} class="profile-photo" src=${this.state.photo}/>`
} else {
profilePhoto = html`<${Identicon} str=${this.props.id} width=250/>`
profilePhoto = html`<${Identicon} str=${this.props.store} width=250/>`
}
}
return html`
@ -66,30 +59,29 @@ class StoreView extends Component {
${profilePhoto}
</div>
<div class="profile-header-stuff">
<h3 class="profile-name"><iris-profile-attribute placeholder="Name" contenteditable=${this.isMyProfile} pub=${this.props.id}/></h3>
<h3 class="profile-name"><iris-profile-attribute placeholder="Name" contenteditable=${this.isMyProfile} pub=${this.props.store}/></h3>
<div class="profile-about hidden-xs">
<p class="profile-about-content">
<iris-profile-attribute placeholder="About" contenteditable=${this.isMyProfile} attr="about" pub=${this.props.id}/>
<iris-profile-attribute placeholder="About" contenteditable=${this.isMyProfile} attr="about" pub=${this.props.store}/>
</p>
</div>
<div class="profile-actions">
<div class="follow-count">
<a href="/follows/${this.props.id}">
<a href="/follows/${this.props.store}">
<span>${this.state.followedUserCount}</span> ${t('following')}
</a>
<a href="/followers/${this.props.id}">
<a href="/followers/${this.props.store}">
<span>${this.state.followerCount}</span> ${t('known_followers')}
</a>
</div>
${this.followedUsers.has(Session.getPubKey()) ? html`
<p><small>${t('follows_you')}</small></p>
`: ''}
${followable ? html`<${FollowButton} id=${this.props.id}/>` : ''}
<button onClick=${() => route('/chat/' + this.props.id)}>${t('send_message')}</button>
${followable ? html`<${FollowButton} id=${this.props.store}/>` : ''}
<button onClick=${() => route('/chat/' + this.props.store)}>${t('send_message')}</button>
${uuid ? '' : html`
<${CopyButton} text=${t('copy_link')} title=${this.state.name} copyStr=${'https://iris.to/' + window.location.hash}/>
`}
<button onClick=${() => $('#profile-page-qr').toggle()}>${t('show_qr_code')}</button>
${this.isMyProfile ? '' : html`
<button class="show-settings" onClick=${() => this.onClickSettings()}>${t('settings')}</button>
`}
@ -99,27 +91,25 @@ class StoreView extends Component {
<div class="profile-about visible-xs-flex">
<p class="profile-about-content" placeholder=${this.isMyProfile ? t('about') : ''} contenteditable=${this.isMyProfile} onInput=${e => this.onAboutInput(e)}>${this.state.about}</p>
</div>
<p id="profile-page-qr" style="display:none" class="qr-container"></p>
</div>
<h3>Store</h3>
${cartTotalItems ? html`
<p>
<button onClick=${() => route('/checkout/' + this.props.id)}>Shopping cart (${cartTotalItems})</button>
<button onClick=${() => route('/checkout/' + this.props.store)}>Shopping cart (${cartTotalItems})</button>
</p>
` : ''}
${this.isMyProfile ? html`
<div class="store-item" onClick=${() => route(`/product//${this.props.id}`)}>
<a href="/product/new/${this.props.id}" class="name">Add item</a>
<div class="store-item" onClick=${() => route(`/product/new`)}>
<a href="/product/new" class="name">Add item</a>
</div>
` : ''}
${Object.keys(this.state.items).map(k => {
const i = this.state.items[k];
return html`
<div class="store-item" onClick=${() => route(`/product/${k}/${this.props.id}`)}>
<div class="store-item" onClick=${() => route(`/product/${k}/${this.props.store}`)}>
<${SafeImg} src=${i.thumbnail}/>
<a href="/product/${k}/${this.props.id}" class="name">${i.name}</a>
<a href="/product/${k}/${this.props.store}" class="name">${i.name}</a>
<p class="description">${i.description}</p>
<p class="price">${i.price}</p>
<button class="add" onClick=${e => this.addToCart(k, e)}>
@ -139,34 +129,44 @@ class StoreView extends Component {
}
componentDidUpdate(prevProps) {
if (prevProps.id !== this.props.id) {
if (prevProps.store !== this.props.store) {
this.componentDidMount();
}
}
updateTotalPrice() {
const totalPrice = Object.keys(this.cart).reduce((sum, currentKey) => {
const item = this.items[currentKey];
const price = item && parseInt(item.price) || 0;
return sum + price * this.cart[currentKey];
}, 0);
this.setState({totalPrice});
}
componentDidMount() {
const pub = this.props.id;
const pub = this.props.store;
this.eventListeners.forEach(e => e.off());
this.setState({followedUserCount: 0, followerCount: 0, name: '', photo: '', about: ''});
this.setState({followedUserCount: 0, followerCount: 0, name: '', photo: '', about: '', totalPrice: 0});
this.isMyProfile = Session.getPubKey() === pub;
this.cart = {};
var qrCodeEl = $('#profile-page-qr');
qrCodeEl.empty();
localState.get('cart').get(this.props.id).map().on((v, k) => {
localState.get('cart').get(this.props.store).map().on((v, k) => {
this.cart[k] = v;
this.setState({cart: this.cart})
this.updateTotalPrice();
});
qrCodeEl.empty();
new QRCode(qrCodeEl[0], {
text: 'https://iris.to/' + window.location.hash,
width: 300,
height: 300,
colorDark : "#000000",
colorLight : "#ffffff",
correctLevel : QRCode.CorrectLevel.H
});
if (pub) {
publicState.user(pub).get('store').get('products').map().on((p, id) => {
if (p) {
const o = {};
o[id] = p;
Object.assign(this.items, o);
this.setState({items: this.items});
this.updateTotalPrice();
}
});
}
}
}