Better UI, better admin

This commit is contained in:
Adrian Woźniak 2022-08-05 16:15:14 +02:00
parent bbf774d8d9
commit b9569229fb
No known key found for this signature in database
GPG Key ID: 0012845A89C7352B
11 changed files with 187 additions and 50 deletions

View File

@ -8,3 +8,4 @@ import "./admin/businesses/admin-businesses";
import "./admin/businesses/admin-edit-business";
import "./admin/offers/admin-edit-offer";
import "./admin/offers/ow-admin-offers";

View File

@ -1,12 +1,66 @@
import { Component } from "../../shared";
import { Component, FORM_STYLE } from "../../shared";
customElements.define('admin-businesses', class extends Component {
static get observedAttributes() {
return ['state-filter'];
}
constructor() {
super(`
<style>
:host { display: block; }
::slotted([state]) {
display: none;
}
:host([state-filter="Pending"]) ::slotted([state="Pending"]) {
display: block;
}
:host([state-filter="Approved"]) ::slotted([state="Approved"]) {
display: block;
}
:host([state-filter="Banned"]) ::slotted([state="Banned"]) {
display: block;
}
:host([state-filter="Pinned"]) ::slotted([state="Pinned"]) {
display: block;
}
:host([state-filter="Internal"]) ::slotted([state="Internal"]) {
display: block;
}
${ FORM_STYLE }
</style>
<slot></slot>
<article>
<section>
<select id="state">
<option value="Pending">Pending</option>
<option value="Approved">Approved</option>
<option value="Banned">Banned</option>
<option value="Pinned">Pinned</option>
<option value="Internal">Internal</option>
</select>
</section>
<section>
<slot></slot>
</section>
</article>
`);
this.shadowRoot.querySelector('#state').addEventListener('change', ev => {
ev.stopPropagation();
this.state_filter = ev.target.value;
});
}
connectedCallback() {
super.connectedCallback();
this.state_filter = 'Pending';
}
get state_filter() {
return this.getAttribute('state-filter');
}
set state_filter(v) {
this.setAttribute('state-filter', v);
this.shadowRoot.querySelector('#state').value = v;
}
});

View File

@ -16,13 +16,19 @@ customElements.define('admin-edit-business', class extends Component {
:host(:first-child) {
border-top: 2px solid var(--border-slim-color);
}
section {
article {
display: flex;
justify-content: space-between;
}
#state {
min-width: 200px;
}
#view {
width: calc(100% - 220px);
}
#actions {
width: 200px
}
#actions > input:not(:last-child) {
margin-right: .5rem;
}
@ -38,9 +44,11 @@ customElements.define('admin-edit-business', class extends Component {
}
${ BUTTON_STYLE }${ INPUT_STYLE }
</style>
<section>
<slot></slot>
<div id="actions">
<article>
<section id="view">
<slot></slot>
</section>
<section id="actions">
<input value="Usuń" type="button" />
<form id="change-state" action="/admin/businesses/set-state" method="post">
<input name="id" id="id" type="hidden" />
@ -52,8 +60,8 @@ customElements.define('admin-edit-business', class extends Component {
<option value="Internal">Internal</option>
</select>
</form>
</div>
</section>
</section>
</article>
`);
const form = this.shadowRoot.querySelector('#change-state');

View File

@ -0,0 +1,64 @@
import { Component, FORM_STYLE } from "../../shared.js";
customElements.define('ow-admin-offers', class extends Component {
static get observedAttributes() {
return ['state-filter'];
}
constructor() {
super(`
<style>
:host {
display: block;
}
::slotted([state]) {
display: none;
}
:host([state-filter='Pending']) ::slotted([state="Pending"]) {
display: block;
}
:host([state-filter='Approved']) ::slotted([state="Approved"]) {
display: block;
}
:host([state-filter='Banned']) ::slotted([state="Banned"]) {
display: block;
}
:host([state-filter='Finished']) ::slotted([state="Finished"]) {
display: block;
}
${ FORM_STYLE }
</style>
<article>
<section>
<select id="state">
<option value="Pending">Pending</option>
<option value="Approved">Approved</option>
<option value="Banned">Banned</option>
<option value="Finished">Finished</option>
</select>
</section>
<section>
<slot></slot>
</section>
</article>
`);
this.shadowRoot.querySelector('#state').addEventListener('change', ev => {
ev.stopPropagation();
this.state_filter = ev.target.value;
});
}
connectedCallback() {
super.connectedCallback();
this.state_filter = 'Pending';
}
get state_filter() {
return this.getAttribute('state-filter');
}
set state_filter(v) {
this.setAttribute('state-filter', v);
this.shadowRoot.querySelector('#state').value = v;
}
});

View File

@ -18,8 +18,10 @@ import "./ow-account/account-view.js";
import "./local-businesses/local-businesses.js";
import "./local-businesses/local-business-item.js";
import "./local-businesses/local-business.js";
import "./local-businesses/single-local-business.js";
import "./login-form.js";
import "./register-form.js";
import "./register-form/register-business-account-form";
import "./register-form/register-business-item-form.js";

View File

@ -0,0 +1,7 @@
import { Component } from '../shared.js';
customElements.define('single-local-business', class extends Component {
constructor() {
super(`<style>:host{display:block;margin:0 8px;}@media only screen and (min-device-width: 100px){:host{margin:0;}}</style><article><slot></slot></article>`);
}
});

View File

@ -1,7 +1,7 @@
{% extends "../layout.html" %}
{% block content %}
<ow-admin>
<ow-offers>
<ow-admin-offers>
<h1>Admin - Sprzedaż niepotrzebnych rzeczy</h1>
{% for offer in offers %}
@ -27,6 +27,6 @@
></marketplace-offer>
</admin-edit-offer>
{% endfor %}
</ow-offers>
</ow-admin-offers>
</ow-admin>
{% endblock %}

View File

@ -1,34 +1,34 @@
{% extends "../base.html" %}
{% block content %}
<local-business
slot="business"
business-id="{{business.id}}"
name="{{business.name}}"
state="{{business.state.as_str()}}"
>
{% for line in business.description.lines() %}
<p slot="description">{{line}}</p>
{% endfor %}
{% for item in business.items %}
<local-business-item
slot="item"
name="{{item.name}}"
price="{{item.price}}"
picture-url="{{item.picture_url}}"
<single-local-business {{h.account_id_tag(account)}}>
<local-business
business-id="{{business.id}}"
name="{{business.name}}"
state="{{business.state.as_str()}}"
>
</local-business-item>
{% endfor %}
<contact-info-list slot="contacts">
{% for contact in business.contacts %}
<contact-info
mode="icon"
contact-id="{{contact.id}}"
content="{{h.render_contact(contact.contact_type.as_str(), contact.content.as_str())}}"
type="{{contact.contact_type}}"
></contact-info>
{% for line in business.description.lines() %}
<p slot="description">{{line}}</p>
{% endfor %}
</contact-info-list>
</local-business>
{% for item in business.items %}
<local-business-item
slot="item"
name="{{item.name}}"
price="{{item.price}}"
picture-url="{{item.picture_url}}"
>
</local-business-item>
{% endfor %}
<contact-info-list slot="contacts">
{% for contact in business.contacts %}
<contact-info
mode="icon"
contact-id="{{contact.id}}"
content="{{h.render_contact(contact.contact_type.as_str(), contact.content.as_str())}}"
type="{{contact.contact_type}}"
></contact-info>
{% endfor %}
</contact-info-list>
</local-business>
</single-local-business>
{% endblock %}

View File

@ -22,20 +22,20 @@ pub enum AccountType {
#[derive(Debug, Default, Copy, Clone, Serialize, Deserialize, Type)]
pub enum LocalBusinessState {
#[default]
Pending,
Approved,
Banned,
Pinned,
Internal,
Pending = 1,
Approved = 2,
Banned = 3,
Pinned = 4,
Internal = 5,
}
#[derive(Debug, Default, Copy, Clone, Serialize, Deserialize, Type)]
#[derive(Debug, Default, Copy, Clone, PartialEq, PartialOrd, Serialize, Deserialize, Type)]
pub enum OfferState {
#[default]
Pending,
Approved,
Banned,
Finished,
Pending = 0,
Approved = 1,
Banned = 2,
Finished = 3,
}
impl OfferState {

View File

@ -88,7 +88,7 @@ pub async fn visible_businesses(t: &mut T<'_>) -> Result<Vec<db::LocalBusiness>>
r#"
SELECT id, owner_id, name, description, state
FROM local_businesses
WHERE state != 'Banned'
WHERE state != 'Banned' AND state != 'Pending'
GROUP BY id, state
ORDER BY name ASC
"#,

View File

@ -28,7 +28,8 @@ async fn admin_offers(req: HttpRequest, db: Data<PgPool>, id: Identity) -> HttpR
let mut t = ok_or_internal!(&req, pool.begin().await);
let account = require_admin!(&req, &mut t, id);
let offers = queries::all_offers(&mut t).await.unwrap_or_default();
let mut offers = queries::all_offers(&mut t).await.unwrap_or_default();
offers.sort_by(|a, b| (a.state as u8).cmp(&(b.state as u8)));
t.commit().await.ok();