mirror of
https://github.com/irislib/iris-messenger.git
synced 2024-09-20 01:56:33 +00:00
store things
This commit is contained in:
parent
c9c5ce1dbf
commit
363a8246b9
@ -1253,12 +1253,19 @@ form.public {
|
||||
.store-item {
|
||||
display: inline-flex;
|
||||
flex-direction: column;
|
||||
width: calc(33.33% - 5px);
|
||||
height: calc(33.33% - 5px);
|
||||
background-color: rgba(255,255,255,0.1);
|
||||
width: calc(33.33% - 8px);
|
||||
height: calc(33.33% - 8px);
|
||||
background-color: var(--chat-hover);
|
||||
padding: 15px;
|
||||
margin-right: 5px;
|
||||
margin-bottom: 5px
|
||||
margin-right: 8px;
|
||||
margin-bottom: 8px;
|
||||
cursor: pointer;
|
||||
transition: all 125ms;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.store-item:hover {
|
||||
background-color: var(--chat-active);
|
||||
}
|
||||
|
||||
.price-cell {
|
||||
@ -1290,6 +1297,22 @@ form.public {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#store-steps {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
#store-steps div {
|
||||
flex-basis: 25%;
|
||||
padding: 30px 5px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#store-steps div.active {
|
||||
background-color: var(--chat-hover);
|
||||
}
|
||||
|
||||
/* Tooltip container */
|
||||
.tooltip {
|
||||
position: relative;
|
||||
@ -1406,6 +1429,9 @@ form.public {
|
||||
padding: 5px 10px;
|
||||
}
|
||||
.profile-photo-container .identicon-container * { max-width: 80px; max-height: 80px; text-align: center;}
|
||||
.side-padding-xs {
|
||||
padding: 5px 0 0 5px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 576px) {
|
||||
|
@ -14,7 +14,6 @@ import Settings from './components/Settings.js';
|
||||
import LogoutConfirmation from './components/LogoutConfirmation.js';
|
||||
import ChatView from './components/ChatView.js';
|
||||
import StoreView from './components/StoreView.js';
|
||||
import CartView from './components/CartView.js';
|
||||
import CheckoutView from './components/CheckoutView.js';
|
||||
import ProductView from './components/ProductView.js';
|
||||
import Login from './components/Login.js';
|
||||
@ -80,7 +79,6 @@ class Main extends Component {
|
||||
<${LogoutConfirmation} path="/logout"/>
|
||||
<${Profile.Profile} path="/profile/:id"/>
|
||||
<${StoreView} path="/store/:id"/>
|
||||
<${CartView} path="/cart/:id"/>
|
||||
<${CheckoutView} path="/checkout/:id"/>
|
||||
<${ProductView} path="/product/:id/:store"/>
|
||||
<${FollowsView} path="/follows/:id"/>
|
||||
|
@ -1,105 +0,0 @@
|
||||
import { Component } from '../lib/preact.js';
|
||||
import { html } from '../Helpers.js';
|
||||
import {translate as t} from '../Translation.js';
|
||||
import {localState, publicState} from '../Main.js';
|
||||
import {chats, deleteChat} from '../Chat.js';
|
||||
import Session from '../Session.js';
|
||||
import Helpers from '../Helpers.js';
|
||||
import MessageForm from './MessageForm.js';
|
||||
import ProfilePhotoPicker from './ProfilePhotoPicker.js';
|
||||
import { route } from '../lib/preact-router.es.js';
|
||||
import SafeImg from './SafeImg.js';
|
||||
import CopyButton from './CopyButton.js';
|
||||
import FollowButton from './FollowButton.js';
|
||||
import MessageFeed from './MessageFeed.js';
|
||||
import Identicon from './Identicon.js';
|
||||
import Name from './Name.js';
|
||||
import SearchBox from './SearchBox.js';
|
||||
|
||||
class CartView extends Component {
|
||||
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'}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
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]);
|
||||
}
|
||||
|
||||
render() {
|
||||
const total = Object.keys(this.cart).reduce((sum, currentKey) => {
|
||||
return sum + parseInt(this.state.items[currentKey].price) * this.cart[currentKey];
|
||||
}, 0);
|
||||
return html`
|
||||
<div class="main-view" id="profile">
|
||||
<div class="content">
|
||||
<a href="/store/${this.props.id}"><iris-profile-attribute pub=${this.props.id}/></a>
|
||||
<h2>Shopping cart</h2>
|
||||
<div class="flex-table">
|
||||
${Object.keys(this.cart).filter(k => !!this.cart[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}
|
||||
</div>
|
||||
<div class="flex-cell no-flex price-cell">
|
||||
<p>
|
||||
<span class="unit-price">${parseInt(i.price)} €</span>
|
||||
<button onClick=${() => this.changeItemCount(k, -1)}>-</button>
|
||||
<input type="text" value=${this.cart[k]} onInput=${e => this.changeItemCount(k, null, e)}/>
|
||||
<button onClick=${() => this.changeItemCount(k, 1)}>+</button>
|
||||
</p>
|
||||
<span class="price">${parseInt(i.price) * this.cart[k]} €</span>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
})}
|
||||
<div class="flex-row">
|
||||
<div class="flex-cell"><b>Total</b></div>
|
||||
<div class="flex-cell no-flex"><b>${total} €</b></div>
|
||||
</div>
|
||||
</div>
|
||||
<p>
|
||||
<button onClick=${() => route('/checkout/' + this.props.id)}>Checkout</button>
|
||||
</p>
|
||||
</div>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.eventListeners.forEach(e => e.off());
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
if (prevProps.id !== this.props.id) {
|
||||
this.componentDidMount();
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const pub = this.props.id;
|
||||
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})
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default CartView;
|
@ -2,7 +2,7 @@ import { Component } from '../lib/preact.js';
|
||||
import { html } from '../Helpers.js';
|
||||
import {translate as t} from '../Translation.js';
|
||||
import {localState, publicState} from '../Main.js';
|
||||
import {chats, deleteChat} from '../Chat.js';
|
||||
import {chats, deleteChat, newChat} from '../Chat.js';
|
||||
import Session from '../Session.js';
|
||||
import Helpers from '../Helpers.js';
|
||||
import MessageForm from './MessageForm.js';
|
||||
@ -24,6 +24,7 @@ class CheckoutView extends Component {
|
||||
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€'},
|
||||
@ -39,41 +40,163 @@ class CheckoutView extends Component {
|
||||
localState.get('cart').get(this.props.id).get(k).put(this.cart[k]);
|
||||
}
|
||||
|
||||
render() {
|
||||
confirm() {
|
||||
const pub = this.props.id;
|
||||
localState.get('cart').get(pub).map().once((v, k) => {
|
||||
!!v && localState.get('cart').get(pub).get(k).put(null);
|
||||
});
|
||||
newChat(pub);
|
||||
chats[pub].send('New order: ' + JSON.stringify(this.cart) + ', delivery: ' + JSON.stringify(this.state.delivery) + ', payment: ' + this.state.paymentMethod);
|
||||
route('/chat/' + pub);
|
||||
}
|
||||
|
||||
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 => {
|
||||
const i = this.state.items[k];
|
||||
return html`
|
||||
<div class="flex-row">
|
||||
<div class="flex-cell">
|
||||
<${SafeImg} src=${i.thumbnail}/>
|
||||
${i.name}
|
||||
</div>
|
||||
<div class="flex-cell no-flex price-cell">
|
||||
<p>
|
||||
<span class="unit-price">${parseInt(i.price)} €</span>
|
||||
<button onClick=${() => this.changeItemCount(k, -1)}>-</button>
|
||||
<input type="text" value=${this.cart[k]} onInput=${e => this.changeItemCount(k, null, e)}/>
|
||||
<button onClick=${() => this.changeItemCount(k, 1)}>+</button>
|
||||
</p>
|
||||
<span class="price">${parseInt(i.price) * this.cart[k]} €</span>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
})}
|
||||
<div class="flex-row">
|
||||
<div class="flex-cell"></div>
|
||||
<div class="flex-cell no-flex"><b>Total ${total} €</b></div>
|
||||
</div>
|
||||
</div>
|
||||
<p class="side-padding-xs">
|
||||
<button onClick=${() => this.setState({page:'delivery'})}>Next</button>
|
||||
</p>
|
||||
`;
|
||||
}
|
||||
|
||||
renderDelivery() {
|
||||
return html`
|
||||
<div class="side-padding-xs">
|
||||
<h3>Delivery</h3>
|
||||
<p>
|
||||
<input type="text" placeholder="Name" value=${this.state.delivery.name} onInput=${e => localState.get('delivery').get('name').put(e.target.value)}/>
|
||||
</p>
|
||||
<p>
|
||||
<input type="text" placeholder="Address" value=${this.state.delivery.address} onInput=${e => localState.get('delivery').get('address').put(e.target.value)}/>
|
||||
</p>
|
||||
<p>
|
||||
<input type="text" placeholder="Email (optional)" value=${this.state.delivery.email} onInput=${e => localState.get('delivery').get('email').put(e.target.value)}/>
|
||||
</p>
|
||||
<button onClick=${() => this.setState({page:'payment'})}>Next</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
paymentMethodChanged(e) {
|
||||
const val = e.target.firstChild && e.target.firstChild.value;
|
||||
val && localState.get('paymentMethod').put(val);
|
||||
}
|
||||
|
||||
renderPayment() {
|
||||
return html`
|
||||
<div class="side-padding-xs">
|
||||
<h3>Select a payment method</h3>
|
||||
<p>
|
||||
<label for="bitcoin" onClick=${e => this.paymentMethodChanged(e)}>
|
||||
<input type="radio" name="payment" id="bitcoin" value="bitcoin" checked=${this.state.paymentMethod === 'bitcoin'}/>
|
||||
Bitcoin
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label for="dogecoin" onClick=${e => this.paymentMethodChanged(e)}>
|
||||
<input type="radio" name="payment" id="dogecoin" value="dogecoin" checked=${this.state.paymentMethod === 'dogecoin'}/>
|
||||
Dogecoin
|
||||
</label>
|
||||
</p>
|
||||
<button onClick=${() => this.setState({page:'confirmation'})}>Next</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
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">
|
||||
${Object.keys(this.cart).filter(k => !!this.cart[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}
|
||||
</div>
|
||||
<div class="flex-cell no-flex price-cell">
|
||||
<p>
|
||||
${this.cart[k]} x ${parseInt(i.price)} €
|
||||
</p>
|
||||
<span class="price">${parseInt(i.price) * this.cart[k]} €</span>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
})}
|
||||
<div class="flex-row">
|
||||
<div class="flex-cell"></div>
|
||||
<div class="flex-cell no-flex"><b>Total ${total} €</b></div>
|
||||
</div>
|
||||
</div>
|
||||
<p>
|
||||
Delivery:<br/>
|
||||
${this.state.delivery.name}<br/>
|
||||
${this.state.delivery.address}<br/>
|
||||
${this.state.delivery.email}
|
||||
</p>
|
||||
<p>Payment method: <b>${this.state.paymentMethod}</b></p>
|
||||
<p class="side-padding-xs"><button onClick=${() => this.confirm()}>Confirm</button></p>
|
||||
`;
|
||||
}
|
||||
|
||||
render() {
|
||||
let page;
|
||||
const p = this.state.page;
|
||||
if (p === 'delivery') {
|
||||
page = this.renderDelivery();
|
||||
} else if (p === 'confirmation') {
|
||||
page = this.renderConfirmation();
|
||||
} else if (p === 'payment') {
|
||||
page = this.renderPayment();
|
||||
} else {
|
||||
page = this.renderCart();
|
||||
}
|
||||
return html`
|
||||
<div class="main-view" id="profile">
|
||||
<div class="content">
|
||||
<a href="/store/${this.props.id}"><iris-profile-attribute pub=${this.props.id}/></a>
|
||||
<h2>Checkout</h2>
|
||||
<div class="flex-table">
|
||||
${Object.keys(this.cart).filter(k => !!this.cart[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}
|
||||
</div>
|
||||
<div class="flex-cell no-flex price-cell">
|
||||
<p>
|
||||
${this.cart[k]} x ${parseInt(i.price)} €
|
||||
</p>
|
||||
<span class="price">${parseInt(i.price) * this.cart[k]} €</span>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
})}
|
||||
<div class="flex-row">
|
||||
<div class="flex-cell"><b>Total</b></div>
|
||||
<div class="flex-cell no-flex"><b>${total} €</b></div>
|
||||
</div>
|
||||
</div>
|
||||
<p>
|
||||
<button>Checkout</button>
|
||||
<a href="/store/${this.props.id}"><iris-profile-attribute pub=${this.props.id}/></a>
|
||||
</p>
|
||||
<div id="store-steps">
|
||||
<div class=${p === 'cart' ? 'active' : ''} onClick=${() => this.setState({page:'cart'})}>Cart</div>
|
||||
<div class=${p === 'delivery' ? 'active' : ''} onClick=${() => this.setState({page:'delivery'})}>Delivery</div>
|
||||
<div class=${p === 'payment' ? 'active' : ''} onClick=${() => this.setState({page:'payment'})}>Payment</div>
|
||||
<div class=${p === 'confirmation' ? 'active' : ''} onClick=${() => this.setState({page:'confirmation'})}>Confirm</div>
|
||||
</div>
|
||||
${page}
|
||||
</div>
|
||||
</div>`;
|
||||
}
|
||||
@ -90,12 +213,15 @@ class CheckoutView extends Component {
|
||||
|
||||
componentDidMount() {
|
||||
const pub = this.props.id;
|
||||
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})
|
||||
});
|
||||
localState.get('paymentMethod').on(paymentMethod => this.setState({paymentMethod}));
|
||||
localState.get('delivery').open(delivery => this.setState({delivery}));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -22,6 +22,7 @@ class ProductView extends Component {
|
||||
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€'},
|
||||
@ -33,17 +34,31 @@ class ProductView extends Component {
|
||||
};
|
||||
}
|
||||
|
||||
addToCart() {
|
||||
const count = (this.cart[this.props.id] || 0) + 1;
|
||||
localState.get('cart').get(this.props.store).get(this.props.id).put(count);
|
||||
}
|
||||
|
||||
showProduct() {
|
||||
const cartTotalItems = Object.values(this.cart).reduce((sum, current) => sum + current, 0);
|
||||
const i = this.state.items[this.props.id];
|
||||
return html`
|
||||
<div class="main-view" id="profile">
|
||||
<div class="content">
|
||||
<a href="/store/${this.props.store}"><iris-profile-attribute pub=${this.props.store}/></a>
|
||||
${cartTotalItems ? html`
|
||||
<p>
|
||||
<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">Add to cart</button>
|
||||
<button class="add" onClick=${() => this.addToCart()}>
|
||||
Add to cart
|
||||
${this.cart[this.props.id] ? ` (${this.cart[this.props.id]})` : ''}
|
||||
</button>
|
||||
</div>
|
||||
</div>`;
|
||||
}
|
||||
@ -89,6 +104,11 @@ class ProductView extends Component {
|
||||
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})
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -34,14 +34,14 @@ class StoreView extends Component {
|
||||
};
|
||||
}
|
||||
|
||||
addToCart(k) {
|
||||
addToCart(k, e) {
|
||||
e.stopPropagation();
|
||||
const count = (this.cart[k] || 0) + 1;
|
||||
localState.get('cart').get(this.props.id).get(k).put(count);
|
||||
}
|
||||
|
||||
render() {
|
||||
const reducer = (accumulator, currentValue) => accumulator + currentValue;
|
||||
const cartTotalItems = Object.values(this.cart).reduce(reducer, 0);
|
||||
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];
|
||||
const uuid = chat && chat.uuid;
|
||||
@ -106,18 +106,23 @@ class StoreView extends Component {
|
||||
<h3>Store</h3>
|
||||
${cartTotalItems ? html`
|
||||
<p>
|
||||
<button onClick=${() => route('/cart/' + this.props.id)}>Shopping cart (${cartTotalItems})</button>
|
||||
<button onClick=${() => route('/checkout/' + this.props.id)}>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>
|
||||
` : ''}
|
||||
${Object.keys(this.state.items).map(k => {
|
||||
const i = this.state.items[k];
|
||||
return html`
|
||||
<div class="store-item">
|
||||
<div class="store-item" onClick=${() => route(`/product/${k}/${this.props.id}`)}>
|
||||
<${SafeImg} src=${i.thumbnail}/>
|
||||
<a href="/product/${k}/${this.props.id}" class="name">${i.name}</a>
|
||||
<p class="description">${i.description}</p>
|
||||
<p class="price">${i.price}</p>
|
||||
<button class="add" onClick=${() => this.addToCart(k)}>
|
||||
<button class="add" onClick=${e => this.addToCart(k, e)}>
|
||||
Add to cart
|
||||
${this.cart[k] ? ` (${this.cart[k]})` : ''}
|
||||
</button>
|
||||
|
Loading…
Reference in New Issue
Block a user