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/businesses/admin-edit-business";
import "./admin/offers/admin-edit-offer"; 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 { customElements.define('admin-businesses', class extends Component {
static get observedAttributes() {
return ['state-filter'];
}
constructor() { constructor() {
super(` super(`
<style> <style>
:host { display: block; } :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> </style>
<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> <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) { :host(:first-child) {
border-top: 2px solid var(--border-slim-color); border-top: 2px solid var(--border-slim-color);
} }
section { article {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
} }
#state { #state {
min-width: 200px; min-width: 200px;
} }
#view {
width: calc(100% - 220px);
}
#actions {
width: 200px
}
#actions > input:not(:last-child) { #actions > input:not(:last-child) {
margin-right: .5rem; margin-right: .5rem;
} }
@ -38,9 +44,11 @@ customElements.define('admin-edit-business', class extends Component {
} }
${ BUTTON_STYLE }${ INPUT_STYLE } ${ BUTTON_STYLE }${ INPUT_STYLE }
</style> </style>
<section> <article>
<section id="view">
<slot></slot> <slot></slot>
<div id="actions"> </section>
<section id="actions">
<input value="Usuń" type="button" /> <input value="Usuń" type="button" />
<form id="change-state" action="/admin/businesses/set-state" method="post"> <form id="change-state" action="/admin/businesses/set-state" method="post">
<input name="id" id="id" type="hidden" /> <input name="id" id="id" type="hidden" />
@ -52,8 +60,8 @@ customElements.define('admin-edit-business', class extends Component {
<option value="Internal">Internal</option> <option value="Internal">Internal</option>
</select> </select>
</form> </form>
</div>
</section> </section>
</article>
`); `);
const form = this.shadowRoot.querySelector('#change-state'); 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-businesses.js";
import "./local-businesses/local-business-item.js"; import "./local-businesses/local-business-item.js";
import "./local-businesses/local-business.js"; import "./local-businesses/local-business.js";
import "./local-businesses/single-local-business.js";
import "./login-form.js"; import "./login-form.js";
import "./register-form.js"; import "./register-form.js";
import "./register-form/register-business-account-form"; import "./register-form/register-business-account-form";
import "./register-form/register-business-item-form.js"; 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" %} {% extends "../layout.html" %}
{% block content %} {% block content %}
<ow-admin> <ow-admin>
<ow-offers> <ow-admin-offers>
<h1>Admin - Sprzedaż niepotrzebnych rzeczy</h1> <h1>Admin - Sprzedaż niepotrzebnych rzeczy</h1>
{% for offer in offers %} {% for offer in offers %}
@ -27,6 +27,6 @@
></marketplace-offer> ></marketplace-offer>
</admin-edit-offer> </admin-edit-offer>
{% endfor %} {% endfor %}
</ow-offers> </ow-admin-offers>
</ow-admin> </ow-admin>
{% endblock %} {% endblock %}

View File

@ -1,11 +1,11 @@
{% extends "../base.html" %} {% extends "../base.html" %}
{% block content %} {% block content %}
<local-business <single-local-business {{h.account_id_tag(account)}}>
slot="business" <local-business
business-id="{{business.id}}" business-id="{{business.id}}"
name="{{business.name}}" name="{{business.name}}"
state="{{business.state.as_str()}}" state="{{business.state.as_str()}}"
> >
{% for line in business.description.lines() %} {% for line in business.description.lines() %}
<p slot="description">{{line}}</p> <p slot="description">{{line}}</p>
{% endfor %} {% endfor %}
@ -29,6 +29,6 @@
></contact-info> ></contact-info>
{% endfor %} {% endfor %}
</contact-info-list> </contact-info-list>
</local-business>
</local-business> </single-local-business>
{% endblock %} {% endblock %}

View File

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

View File

@ -88,7 +88,7 @@ pub async fn visible_businesses(t: &mut T<'_>) -> Result<Vec<db::LocalBusiness>>
r#" r#"
SELECT id, owner_id, name, description, state SELECT id, owner_id, name, description, state
FROM local_businesses FROM local_businesses
WHERE state != 'Banned' WHERE state != 'Banned' AND state != 'Pending'
GROUP BY id, state GROUP BY id, state
ORDER BY name ASC 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 mut t = ok_or_internal!(&req, pool.begin().await);
let account = require_admin!(&req, &mut t, id); 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(); t.commit().await.ok();