More info

This commit is contained in:
eraden 2022-07-22 21:32:33 +02:00
parent ee91354de8
commit 62d4e0c46a
17 changed files with 91 additions and 101 deletions

View File

@ -132,6 +132,7 @@ local-businesses local-business p {
margin: 8px auto auto;
padding: 8px;
}
#home {
position: relative;
}

View File

@ -44,7 +44,7 @@ if (!document.querySelector('#facebook-jssdk')) {
xfbml: true,
version: 'v14.0'
});
// FB.AppEvents.logPageView();
FB.AppEvents.logPageView();
fireFbReady();
};

View File

@ -1,4 +1,4 @@
import { Component, FORM_STYLE } from "../shared";
import { Component, FORM_STYLE, TIP } from "../shared";
customElements.define('offer-form', class extends Component {
static get observedAttributes() {
@ -9,11 +9,6 @@ customElements.define('offer-form', class extends Component {
super(`
<style>
:host { display: block; }
.tip {
font-size: 10px;
font-style: italic;
color: var(--border-slim-color)
}
#description {
height: 200px;
}
@ -34,7 +29,7 @@ customElements.define('offer-form', class extends Component {
margin-right: 16px;
}
}
${ FORM_STYLE }
${ FORM_STYLE }${ TIP }
</style>
<section>
<form action="/offers/create" method="post">
@ -45,8 +40,11 @@ customElements.define('offer-form', class extends Component {
</div>
<div id="descriptionSection">
<label for="description">Opis</label>
<textarea name="description" id="description">
</textarea>
<textarea
name="description"
id="description"
placeholder="Opisz przedmiot, który chcesz sprzedać"
></textarea>
</div>
<div id="priceSection">
<div>

View File

@ -2,7 +2,7 @@ import { Component, FORM_STYLE } from "../shared";
customElements.define('account-view', class extends Component {
static get observedAttributes() {
return ['facebook-id', 'id', 'name', 'email']
return ['facebook-id', 'id', 'name', 'email', 'register-success']
}
constructor() {
@ -21,6 +21,10 @@ customElements.define('account-view', class extends Component {
display: flex;
padding: .375rem .75rem;
}
#register-success { display: none; text-align: center; color: darkgreen; }
:host([register-success]) #register-success {
display: block;
}
#fb-button {
display: none;
}
@ -29,6 +33,7 @@ customElements.define('account-view', class extends Component {
}
${ FORM_STYLE }
</style>
<h3 id="register-success">Konto utworzone!</h3>
<div>
<input id="id" name="id" readonly type="hidden" />
</div>
@ -61,6 +66,11 @@ customElements.define('account-view', class extends Component {
});
}
connectedCallback() {
super.connectedCallback();
this.register_success = (location.search || '').includes('success');
}
get name() {
return this.getAttribute('name') || '';
}
@ -87,4 +97,15 @@ customElements.define('account-view', class extends Component {
this.setAttribute('facebook-id', v);
this.shadowRoot.querySelector('#facebook_id').value = v;
}
get register_success() {
return this.getAttribute('register-success') === 'true'
}
set register_success(v) {
if (v === true || v === 'true')
this.setAttribute('register-success', 'true');
else
this.removeAttribute('register-success');
}
});

View File

@ -22,6 +22,7 @@ customElements.define('register-basic-form', class extends PseudoForm {
<label>Hasło</label>
<input name="pass" placeholder="Hasło" type="password" required />
</div>
<input type="submit" style="display: none">
<form-navigation></form-navigation>
</form>
`);
@ -30,9 +31,10 @@ customElements.define('register-basic-form', class extends PseudoForm {
form.addEventListener('submit', ev => {
ev.preventDefault();
ev.stopPropagation();
this.shadowRoot.querySelector('form-navigation').next();
});
this.shadowRoot.querySelector('form-navigation').addEventListener('form:next', ev => {
console.log(ev);
if (form.reportValidity())
this.shadowRoot.querySelector('form-navigation').next();
});
}
});

View File

@ -1,4 +1,4 @@
import { FORM_STYLE, PseudoForm } from "../shared";
import { FORM_STYLE, TIP, PseudoForm } from "../shared";
customElements.define('register-business-form', class extends PseudoForm {
constructor() {
@ -6,15 +6,18 @@ customElements.define('register-business-form', class extends PseudoForm {
<style>
:host { display: block; }
* { font-family: 'Noto Sans', sans-serif; }
${ FORM_STYLE }
textarea { min-height: 200px; }
${ FORM_STYLE }${ TIP }
</style>
<form id="step-2">
<div>
<label>Nazwa usługodawcy</label>
<input name="name" placeholder="Nazwa usługi" type="text" required autofocus />
</div>
<div>
<label>description</label>
<label>Opis usługodawcy</label>
<textarea name="description" required></textarea>
<div class="tip">Produkty dodawane w nastepnym kroku</div>
</div>
<form-navigation></form-navigation>
</form>
@ -26,4 +29,8 @@ customElements.define('register-business-form', class extends PseudoForm {
this.shadowRoot.querySelector('form-navigation').next();
});
}
connectedCallback() {
super.connectedCallback();
}
})

View File

@ -30,6 +30,7 @@ customElements.define('register-items-form', class extends PseudoForm {
<div>
<input type="button" id="add-item" value="Dodaj usługę/produkt" />
</div>
<input type="submit" style="display: none" />
<form-navigation></form-navigation>
</form>
`);
@ -39,6 +40,7 @@ customElements.define('register-items-form', class extends PseudoForm {
updateItems(this)
});
this.addEventListener('form:next', ev => {
updateItems(this);
for (const el of this.querySelectorAll('item-form-row')) {
if (!el.reportValidity()) {
ev.stopPropagation();
@ -55,7 +57,7 @@ customElements.define('register-items-form', class extends PseudoForm {
ev.stopPropagation();
ev.preventDefault();
this.appendChild(document.createElement('register-item-form-row'));
updateItems(this)
updateItems(this);
});
}

View File

@ -7,6 +7,7 @@ customElements.define('register-submit-form', class extends PseudoForm {
:host { display: block; }
* { font-family: 'Noto Sans', sans-serif; }
${ FORM_STYLE }
img[src=''] { display: none; }
@media only screen and (min-device-width: 1200px) {
.item-view {
display: flex;
@ -72,7 +73,10 @@ customElements.define('register-submit-form', class extends PseudoForm {
const [name, price, img] = row;
el.innerHTML = `
<img src="${img.value}" />
${ img.value !== ''
? `<img src="${img.value}" alt="" />`
: `<span>Brak zdjęcia</span>`
}
<input type="text" name="${ name.name }" value="${ name.value }" readonly />
<input type="hidden" name="${ price.name }" value="${ price.value }" readonly />
<input type="hidden" name="${ img.name }" value="${ img.value }" readonly />

View File

@ -1,4 +1,4 @@
import { Component, BUTTON_STYLE } from "../shared";
import { Component, BUTTON_STYLE, TIP } from "../shared";
customElements.define('register-user-type', class extends Component {
constructor() {
@ -52,7 +52,7 @@ customElements.define('register-user-type', class extends Component {
height: 200px;
}
}
${ BUTTON_STYLE }
${ BUTTON_STYLE }${ TIP }
</style>
<article>
<button id="accept-terms">
@ -84,6 +84,7 @@ customElements.define('register-user-type', class extends Component {
<path fill-rule="evenodd" clip-rule="evenodd" d="M7.5.875a3.625 3.625 0 0 0-1.006 7.109c-1.194.145-2.218.567-2.99 1.328-.982.967-1.479 2.408-1.479 4.288a.475.475 0 1 0 .95 0c0-1.72.453-2.88 1.196-3.612.744-.733 1.856-1.113 3.329-1.113s2.585.38 3.33 1.113c.742.733 1.195 1.892 1.195 3.612a.475.475 0 1 0 .95 0c0-1.88-.497-3.32-1.48-4.288-.77-.76-1.795-1.183-2.989-1.328A3.627 3.627 0 0 0 7.5.875ZM4.825 4.5a2.675 2.675 0 1 1 5.35 0 2.675 2.675 0 0 1-5.35 0Z" fill="currentColor"/>
</svg>
<div>Użytkownik</div>
<div class="tip">Zwykły użytkownik z opcją wystawiania niepotrzebnych prywatnych rzeczy na sprzedaż</div>
</a>
</li>
<li>
@ -93,6 +94,7 @@ customElements.define('register-user-type', class extends Component {
<path d="M489.4 171.05c0-2.1-.5-4.1-1.6-5.9l-72.8-128c-2.1-3.7-6.1-6.1-10.4-6.1H84.7c-4.3 0-8.3 2.3-10.4 6.1l-72.7 128c-1 1.8-1.6 3.8-1.6 5.9 0 28.7 17.3 53.3 42 64.2v211.1c0 6.6 5.4 12 12 12h381.3c6.6 0 12-5.4 12-12v-209.6c0-.5 0-.9-.1-1.3 24.8-10.9 42.2-35.6 42.2-64.4zM91.7 55.15h305.9l56.9 100.1H34.9l56.8-100.1zm256.6 124c-3.8 21.6-22.7 38-45.4 38s-41.6-16.4-45.4-38h90.8zm-116.3 0c-3.8 21.6-22.7 38-45.4 38s-41.6-16.4-45.5-38H232zm-207.2 0h90.9c-3.8 21.6-22.8 38-45.5 38-22.7.1-41.6-16.4-45.4-38zm176.8 255.2h-69v-129.5c0-9.4 7.6-17.1 17.1-17.1h34.9c9.4 0 17.1 7.6 17.1 17.1v129.5h-.1zm221.7 0H225.6v-129.5c0-22.6-18.4-41.1-41.1-41.1h-34.9c-22.6 0-41.1 18.4-41.1 41.1v129.6H66v-193.3c1.4.1 2.8.1 4.2.1 24.2 0 45.6-12.3 58.2-31 12.6 18.7 34 31 58.2 31s45.5-12.3 58.2-31c12.6 18.7 34 31 58.1 31 24.2 0 45.5-12.3 58.1-31 12.6 18.7 34 31 58.2 31 1.4 0 2.7-.1 4.1-.1v193.2zm-4.1-217.1c-22.7 0-41.6-16.4-45.4-38h90.9c-3.9 21.5-22.8 38-45.5 38z"/>
</svg>
<div>Usługodawca</div>
<div class="tip">Usługodawca posiadający stałe usłuugi lub produkty w ofercie</div>
</a>
</li>
</ul>

View File

@ -115,6 +115,7 @@ label {
${ INPUT_STYLE }
${ BUTTON_STYLE }
`;
export const TIP = `.tip { text-align: center; font-style: italic; font-size: 10px; color: var(--border-slim-color); }`;
export class Component extends HTMLElement {
#shadow;

View File

@ -18,6 +18,12 @@ customElements.define('image-input', class extends Component {
#hidden { overflow: hidden; width: 1px; height: 1px; position: relative; }
input[type=file] { position: absolute; top: -10px; left: -10px; display: none; }
#view { width: 200px; height: 200px; cursor: pointer; }
#view > span {
display: block;
text-align: center;
margin-top: 8px;
color: var(--border-slim-color)
}
div > input[type=button] {
margin: 0;
width: 100%;
@ -40,8 +46,9 @@ customElements.define('image-input', class extends Component {
<input id="file" type="file" accept="image/*" />
</section>
<div id="view">
Kliknij żeby przesłać zdjęcie (opcjonalne)
</div>
<div>
<div style="display: none;">
<input id="save" type="button" value="Wyślij" />
</div>
</article>
@ -56,10 +63,13 @@ customElements.define('image-input', class extends Component {
const input = this.shadowRoot.querySelector('#file');
const view = this.shadowRoot.querySelector('#view');
const toFile = (canvas) =>
canvas.toBlob((blob) => {
this.#file = new File([blob], `${ crypto.randomUUID() }.webp`, { type: blob.type });
}, 'image/webp');
const toFile = (canvas) => new Promise((resolve) => {
canvas.toBlob(async (blob) => {
this.#file = new File([blob], `${ crypto.randomUUID() }.webp`, { type: blob.type });
resolve();
await this.#sendFile(this.#file); // TODO: Send on form submit
}, 'image/webp');
})
input.addEventListener('change', ev => {
ev.stopPropagation();
@ -69,7 +79,7 @@ customElements.define('image-input', class extends Component {
let maxWidth = this.width;
let maxHeight = this.height;
image.onload = () => {
image.onload = async () => {
if (this.send_original) {
maxWidth = maxWidth < image.naturalWidth ? maxWidth : image.naturalWidth;
maxHeight = maxHeight < image.naturalHeight ? maxHeight : image.naturalHeight;
@ -84,19 +94,17 @@ customElements.define('image-input', class extends Component {
canvas.width = image.width = width;
canvas.height = image.height = height;
if (this.send_original) {
canvas.getContext('2d').drawImage(image, 0, 0, width, height);
} else {
canvas.getContext('2d').drawImage(image, 0, 0);
}
toFile(canvas);
canvas.getContext('2d').drawImage(image, 0, 0, width, height);
await toFile(canvas);
image.width = width > image ? 200 : (width * 200) / height;
image.height = width > image ? (width * 200) / height : 200;
view.appendChild(image);
};
image.src = URL.createObjectURL(input.files[0]);
view.innerHTML = '';
view.appendChild(image);
});
view.addEventListener('click', ev => {
@ -149,7 +157,11 @@ customElements.define('image-input', class extends Component {
if (!(v || '').startsWith("/")) v = '';
this.setAttribute('url', v);
const view = this.shadowRoot.querySelector('#view');
view.innerHTML = `<img src="${ v }" alt=""/>`;
if (v === '') {
view.innerHTML = '<span>Kliknij żeby przesłać zdjęcie (opcjonalne)</span>';
} else {
view.innerHTML = `<img src="${ v }" alt=""/>`;
}
}
get value() {

View File

@ -1,5 +1,6 @@
{% extends "../base.html" %}
{% block content %}
<h2 style="text-align: center">Lokalne usługi</h2>
<local-business-list>
{% for business in businesses %}
<local-business

View File

@ -1,7 +1,7 @@
{% extends "../base.html" %}
{% block content %}
<marketplace-offers>
<h1>Rzeczy wystawione na sprzedaż</h1>
<h2 style="text-align: center">Rzeczy wystawione na sprzedaż</h2>
{% for offer in offers %}
<marketplace-offer

View File

@ -48,7 +48,9 @@
</svg>
<div>Moje usługi</div>
</ow-path>
{%- endif %}
{% if account.is_some() -%}
<ow-path path="/account/offers" selected="{{ page.select_account_offers() }}" title="Moje sprzedaże">
<svg viewBox="0 0 32 32" xml:space="preserve" xmlns="http://www.w3.org/2000/svg">
<path

View File

@ -1,7 +1,7 @@
{% extends "../base.html" %}
{% block content %}
<marketplace-offers>
<h1>Sprzedaż niepotrzebnych rzeczy</h1>
<h2>Sprzedaż niepotrzebnych rzeczy</h2>
<offer-form></offer-form>
{% for offer in offers %}

View File

@ -204,7 +204,7 @@ RETURNING id, local_business_id, name, price, item_order, picture_url
t.commit().await.unwrap();
Ok(HttpResponse::SeeOther()
.append_header(("Location", "/"))
.append_header(("Location", "/account?success"))
.body(
AccountTemplate {
account: Some(account),

View File

@ -1,64 +1 @@
use stdweb::web::HtmlElement;
use stdweb::*;
#[global_allocator]
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
pub trait Component {
fn tag_name() -> String;
fn create(el: HtmlElement) -> Self;
fn created(&mut self) {}
fn connected_callback(&self) {}
fn disconnected_callback(&mut self) {}
fn attribute_changed(
&mut self,
_name: String,
_old_value: Option<String>,
_new_value: Option<String>,
) {
}
}
pub struct FooElement {
el: HtmlElement,
}
impl Component for FooElement {
fn tag_name() -> String {
"foo-element".into()
}
fn create(el: HtmlElement) -> Self {
Self { el }
}
fn connected_callback(&self) {}
}
pub struct BarElement {
el: HtmlElement,
}
impl Component for BarElement {
fn tag_name() -> String {
"bar-element".into()
}
fn create(el: HtmlElement) -> Self {
Self { el }
}
fn connected_callback(&self) {}
}
pub fn define() {
let tag_name = BarElement::tag_name();
js! {
customerElemenets.define(@{tag_name}, class extends HTMLElement {});
}
}