Nicer offer view

This commit is contained in:
eraden 2022-07-19 22:05:54 +02:00
parent 0abaee78f9
commit 12f95612d6
10 changed files with 120 additions and 23 deletions

View File

@ -74,36 +74,36 @@ h1, h2, h3, h4, h5, h6 {
}
h1 {
font-size: 3.4em;
margin-bottom: .8em;
font-size: 3.4rem;
margin-bottom: .8rem;
}
h2 {
font-size: 2.4em;
padding-bottom: .2em;
font-size: 2.4rem;
padding-bottom: .2rem;
border-bottom: 1px solid #333;
margin-top: 1em;
margin-bottom: .7em;
margin-top: 1rem;
margin-bottom: .7rem;
}
h3 {
font-size: 1.8em;
margin-bottom: .7em;
font-size: 1.8rem;
margin-bottom: .7rem;
}
p {
font-size: 1rem;
line-height: 1.5;
margin-bottom: 1.3em;
margin-bottom: 1.3rem;
}
ul, ol {
font-size: 1.1rem;
margin: 0 0 1.1rem 1.2em;
margin: 0 0 1.1rem 1.2rem;
}
li {
margin-bottom: .4em;
margin-bottom: .4rem;
}
terms-and-conditions li {
@ -111,13 +111,13 @@ terms-and-conditions li {
}
blockquote {
padding-left: 1em;
padding-left: 1rem;
border-left: 3px solid #999;
margin: 2.5em 2em;
margin: 2.5rem 2rem;
}
blockquote p {
font: italic 1.2em/1.6 Georgia, "Times New Roman", Times, serif;
font: italic 1.2rem/1.6 Georgia, "Times New Roman", Times, serif;
}
local-businesses local-business p {

View File

@ -1,6 +1,8 @@
{% extends "../base.html" %}
{% block content %}
<marketplace-offers>
<h1>Rzeczy wystawione na sprzedaż</h1>
{% for offer in offers %}
<marketplace-offer
offer-id="{{offer.id}}"

View File

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

View File

@ -1,14 +1,77 @@
import { Component } from "../shared";
import { Component, INPUT_STYLE } from "../shared";
customElements.define('marketplace-offer', class extends Component {
static get observedAttributes() {
return ['offer-id', 'description', 'picture-url']
}
constructor() {
super(`
<style>
:host {
display: block;
margin-bottom: 8px;
}
section {
display: flex;
justify-content: space-between;
}
img[src=""] { display: none; }
img {
width: 100%;
}
#preview {
max-width: 50%;
}
#description {
margin-left: 16px;
width: 50%;
}
@media only screen and (min-device-width: 1200px) {
#preview {
max-width: 400px;
max-height: 400px;
}
#description {
min-height: 200px;
}
}
${INPUT_STYLE}
</style>
<slot></slot>
<section>
<div id="preview">
<img alt="" src="" id="picture" />
</div>
<p id="description"></p>
</section>
`);
}
get offer_id() {
const v = parseInt(this.getAttribute('offer-id'));
return isNaN(v) ? null : v;
}
set offer_id(v) {
v = parseInt(v);
this.setAttribute('offer-id', v);
}
get description() {
return this.getAttribute('description');
}
set description(v) {
this.setAttribute('description', v);
this.shadowRoot.querySelector('#description').textContent = v;
}
get picture_url() {
return this.getAttribute('picture-url');
}
set picture_url(v) {
this.setAttribute('picture-url', v);
this.shadowRoot.querySelector('#picture').src = v;
}
});

View File

@ -7,6 +7,10 @@ customElements.define('marketplace-offers', class extends Component {
:host {
display: block;
}
h1 {
display: block;
text-align: center;
}
</style>
<slot></slot>
`);

View File

@ -33,14 +33,14 @@ customElements.define('offer-form', class extends Component {
<input name="description" id="description" type="text" />
</div>
<div>
<input id="submit" type="submit" value="Utwótz" />
<input id="submit" type="submit" value="Utwórz" />
</div>
</form>
</section>
`);
this.addEventListener('image-input:uploaded', ev => {
console.log(ev);
this.picture_url = ev.detail;
});
}
@ -68,6 +68,16 @@ customElements.define('offer-form', class extends Component {
this.shadowRoot.querySelector('#description').value = v;
}
get picture_url() {
return this.getAttribute('picture-url');
}
set picture_url(v) {
this.setAttribute('picture-url', v);
this.shadowRoot.querySelector('#picture_url').value = v;
this.shadowRoot.querySelector('image-input').url = v;
}
#removeId() {
const form = this.shadowRoot.querySelector('form');
const input = form.querySelector('#offer-id');

View File

@ -144,6 +144,14 @@ customElements.define('image-input', class extends Component {
view.innerHTML = `<img src="${ v }" alt=""/>`;
}
get value() {
return this.url;
}
set value(v) {
this.url = v;
}
async #sendFile(file) {
if (!file) return;
const form = new FormData;
@ -153,7 +161,11 @@ customElements.define('image-input', class extends Component {
body: form,
}).then(res => res.json()).then(({ path }) => {
this.url = path;
this.dispatchEvent(new CustomEvent('image-input:uploaded', { bubbles: true, composed: true }));
this.dispatchEvent(new CustomEvent('image-input:uploaded', {
bubbles: true,
composed: true,
detail: path
}));
});
}

View File

@ -1028,13 +1028,12 @@ pub async fn visible_offers(t: &mut T<'_>) -> Result<Vec<db::Offer>> {
SELECT
id,
owner_id,
name,
description,
picture_url,
state,
created_at
FROM offers
WHERE created_at + '2 weeks' <= now() AND state = 'Approved'
WHERE created_at + '2 weeks' > now() AND state = 'Approved'
"#,
)
.fetch_all(t)

View File

@ -8,7 +8,7 @@ use crate::model::view::Page;
use crate::model::{db, view};
use crate::routes::{Identity, Result};
use crate::view::Helper;
use crate::{authorize, ok_or_internal, queries};
use crate::{authorize, not_xss, ok_or_internal, queries};
#[derive(Default, Template)]
#[template(path = "./offers/index.html")]
@ -56,6 +56,9 @@ async fn create_offer(
let form = form.into_inner();
dbg!(&form);
not_xss!(&form.description, t);
not_xss!(&form.picture_url, t);
match queries::create_offer(
&mut t,
db::CreateOfferInput {
@ -106,6 +109,9 @@ async fn update_offer(
let form = form.into_inner();
dbg!(&form);
not_xss!(&form.description, t);
not_xss!(&form.picture_url, t);
match queries::update_offer(
&mut t,
db::UpdateOfferInput {

View File

@ -281,7 +281,6 @@ async fn login(form: web::Form<LoginForm>, db: Data<PgPool>, id: Identity) -> Re
Ok(HttpResponse::Ok().content_type("text/html").body(
AccountTemplate {
account: Some(record),
page: Page::Login,
..Default::default()
}