UI tuning
This commit is contained in:
parent
a9669432ec
commit
f91b4fb4f9
@ -2,6 +2,34 @@
|
||||
@import 'noto-sans.css';
|
||||
@import 'beam-weapon.css';
|
||||
|
||||
/* latin-ext */
|
||||
@font-face {
|
||||
font-family: 'Cardo';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/cardo/v19/wlp_gwjKBV1pqhv23IEp2A.woff2) format('woff2');
|
||||
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||
}
|
||||
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: 'Cardo';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/cardo/v19/wlp_gwjKBV1pqhv43IE.woff2) format('woff2');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Garamond Premier Pro Display';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url('/assets/fonts/Garamond Premier Pro Display.otf') format('otf');
|
||||
}
|
||||
|
||||
* {
|
||||
--hover-color: #f18902;
|
||||
--border-slim-color: #495057;
|
||||
@ -9,6 +37,8 @@
|
||||
--red-color: #9D0208;
|
||||
--orange-color: #E85D04;
|
||||
--blue-color: #023e8a;
|
||||
|
||||
--ast-border-color: #dddddd;
|
||||
}
|
||||
|
||||
header > h1 {
|
||||
@ -16,23 +46,6 @@ header > h1 {
|
||||
}
|
||||
|
||||
@media (min-width: 1200px) {
|
||||
header > h1 {
|
||||
font-family: 'Beam Weapon', sans-serif;
|
||||
font-weight: bold;
|
||||
text-shadow: 2px 1px 2px #fff, -1px -1px 2px #fff;
|
||||
display: block;
|
||||
font-size: 115px;
|
||||
padding: 0;
|
||||
text-align: center;
|
||||
background: no-repeat center url("/assets/images/background.webp");
|
||||
background: no-repeat center image-set(url("/assets/images/background.webp") 1x, url("/assets/images/background.jpeg") 1x);
|
||||
border-radius: 4px;
|
||||
background-size: 1280px 200px;
|
||||
width: 1280px;
|
||||
height: 200px;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
article {
|
||||
width: 1280px;
|
||||
margin: auto auto;
|
||||
@ -69,18 +82,19 @@ article {
|
||||
}
|
||||
|
||||
* {
|
||||
font-family: 'Noto Sans', sans-serif;
|
||||
font-family: 'Cardo', sans-serif;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
font-family: Georgia, "Times New Roman", Times, serif;
|
||||
font-family: 'Cardo', serif;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 3.4rem;
|
||||
margin-bottom: .8rem;
|
||||
font-family: "Garamond Premier Pro Display", Sans-serif;
|
||||
font-size: 39px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
h2 {
|
||||
@ -122,11 +136,11 @@ blockquote {
|
||||
}
|
||||
|
||||
blockquote p {
|
||||
font: italic 1.2rem/1.6 Georgia, "Times New Roman", Times, serif;
|
||||
font: italic 1.2rem/1.6 'Cardo', serif;
|
||||
}
|
||||
|
||||
local-businesses local-business p {
|
||||
font-family: 'Noto Sans', sans-serif;
|
||||
font-family: 'Cardo', sans-serif;
|
||||
}
|
||||
|
||||
.error {
|
||||
@ -162,44 +176,41 @@ ow-nav > ow-path[selected="selected"] > svg {
|
||||
|
||||
.btn {
|
||||
cursor: pointer;
|
||||
border-radius: 5px;
|
||||
box-shadow: 0 10px 20px -6px rgba(0, 0, 0, .12);
|
||||
position: relative;
|
||||
margin-bottom: 20px;
|
||||
|
||||
display: inline-block;
|
||||
font-weight: 400;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
user-select: none;
|
||||
font-size: 1rem;
|
||||
line-height: 1.5;
|
||||
transition: color .15s ease-in-out,
|
||||
background-color .15s ease-in-out,
|
||||
border-color .15s ease-in-out,
|
||||
box-shadow .15s ease-in-out;
|
||||
width: auto;
|
||||
height: calc(1.5em + 0.75rem + 2px);
|
||||
padding: .375rem .75rem;
|
||||
|
||||
border: 1px solid #495057;
|
||||
color: #495057;
|
||||
background: white;
|
||||
border: 1px solid black;
|
||||
color: white;
|
||||
background: black;
|
||||
padding: 10px 20px;
|
||||
font-family: "Cardo", Sans-serif;
|
||||
font-size: 20px;
|
||||
font-weight: 500;
|
||||
line-height: 1em;
|
||||
letter-spacing: 0;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
a.btn {
|
||||
text-decoration: none;
|
||||
line-height: 2;
|
||||
}
|
||||
|
||||
privacy-policy h2 {
|
||||
display: block;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
privacy-policy h4 {
|
||||
display: block;
|
||||
text-align: center;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
privacy-policy ul li {
|
||||
list-style: circle;
|
||||
}
|
||||
|
BIN
assets/fonts/Cardo-Bold.ttf
Normal file
BIN
assets/fonts/Cardo-Bold.ttf
Normal file
Binary file not shown.
BIN
assets/fonts/Cardo-Italic.ttf
Normal file
BIN
assets/fonts/Cardo-Italic.ttf
Normal file
Binary file not shown.
BIN
assets/fonts/Cardo-Regular.ttf
Normal file
BIN
assets/fonts/Cardo-Regular.ttf
Normal file
Binary file not shown.
BIN
assets/fonts/Garamond Premier Pro Display.otf
Normal file
BIN
assets/fonts/Garamond Premier Pro Display.otf
Normal file
Binary file not shown.
@ -55,11 +55,13 @@ customElements.define('business-item-editor', class extends Component {
|
||||
<article id="list">
|
||||
<slot></slot>
|
||||
</article>
|
||||
|
||||
<article id="form">
|
||||
<register-item-form-row remove="hidden" save="show" idx="0">
|
||||
<register-business-item-form remove="hidden" save="show" idx="0">
|
||||
<div id="shadow" slot="head"> </div>
|
||||
</register-item-form-row>
|
||||
</register-business-item-form>
|
||||
</article>
|
||||
|
||||
<article id="new-business-item-form">
|
||||
<form id="create-new-item-form" method="post" action="/business-item/new">
|
||||
<input type="hidden" name="name" id="name" />
|
||||
@ -68,6 +70,7 @@ customElements.define('business-item-editor', class extends Component {
|
||||
<input type="hidden" name="item_order" id="item_order" />
|
||||
</form>
|
||||
</article>
|
||||
|
||||
<form id="moveForm" action="/business-item/move" method="post">
|
||||
<input name="id" type="hidden" />
|
||||
<input name="item_order" type="hidden" />
|
||||
|
@ -19,6 +19,9 @@ customElements.define('business-item', class extends Component {
|
||||
#move svg {
|
||||
cursor: pointer;
|
||||
}
|
||||
form > #fields > div, form > #fields > div > label, form > #fields > div > .input {
|
||||
width: 90% !important;
|
||||
}
|
||||
@media(min-width: 1280px) {
|
||||
section > form {
|
||||
display: flex;
|
||||
@ -28,9 +31,15 @@ customElements.define('business-item', class extends Component {
|
||||
width: 25%;
|
||||
max-width: 25%;
|
||||
}
|
||||
form > #fields {
|
||||
width: 50%;
|
||||
}
|
||||
#move {
|
||||
width: 33px;
|
||||
}
|
||||
form > #fields > div, form > #fields > div > label, form > #fields > div > .input {
|
||||
width: 90% !important;
|
||||
}
|
||||
}
|
||||
#move-up, #move-down {
|
||||
border: none;
|
||||
@ -52,14 +61,18 @@ customElements.define('business-item', class extends Component {
|
||||
</button>
|
||||
</div>
|
||||
<image-input send-original="true"></image-input>
|
||||
|
||||
<div id="fields">
|
||||
<div>
|
||||
<label>Nazwa</label>
|
||||
<input name="name" id="name" />
|
||||
<input name="name" id="name" class="input" />
|
||||
</div>
|
||||
<div>
|
||||
<label>Cena</label>
|
||||
<price-input></price-input>
|
||||
<price-input class="input"></price-input>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="actions">
|
||||
<input type="submit" id="save" value="Zapisz" />
|
||||
<input type="button" id="delete" value="Usuń" />
|
||||
|
@ -8,9 +8,8 @@ customElements.define('contact-info-editor', class extends Component {
|
||||
constructor() {
|
||||
super(`
|
||||
<style>
|
||||
:host {
|
||||
display: block;
|
||||
}
|
||||
:host { display: block; }
|
||||
* { font-family: 'Cardo', sans-serif; }
|
||||
#contact-wrapper contact-type-icon {
|
||||
width: 24px;
|
||||
margin-right: 8px;
|
||||
@ -29,6 +28,10 @@ customElements.define('contact-info-editor', class extends Component {
|
||||
:host([save="false"]) #submit {
|
||||
display: none;
|
||||
}
|
||||
input[type=submit] {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
}
|
||||
@media only screen and (min-device-width: 1000px) {
|
||||
article {
|
||||
margin: 0;
|
||||
@ -37,7 +40,6 @@ customElements.define('contact-info-editor', class extends Component {
|
||||
${ FORM_STYLE }
|
||||
</style>
|
||||
<article>
|
||||
<h2>Edycja listy danych kontaktowych</h2>
|
||||
<section>
|
||||
<form method="post" action="/contacts/create">
|
||||
<div id="contact-wrapper">
|
||||
|
@ -10,19 +10,14 @@ customElements.define('edit-contact-info', class extends Component {
|
||||
<style>
|
||||
:host { display: block; }
|
||||
article {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
}
|
||||
#actions {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
display: block;
|
||||
}
|
||||
#buttons {
|
||||
display: flex;
|
||||
justify-content: start;
|
||||
margin: 8px 0;
|
||||
}
|
||||
#actions > *:not(:last-child) {
|
||||
#actions input {
|
||||
margin-right: 8px;
|
||||
}
|
||||
:host([mode = 'view']) contact-info-editor {
|
||||
@ -44,6 +39,17 @@ customElements.define('edit-contact-info', class extends Component {
|
||||
:host([delete = "false"]) #deleteButton {
|
||||
display: none;
|
||||
}
|
||||
@media only screen and (min-device-width: 1000px) {
|
||||
article {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
}
|
||||
#actions {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
}
|
||||
${ BUTTON_STYLE }
|
||||
</style>
|
||||
<article>
|
||||
|
@ -9,7 +9,7 @@ customElements.define('local-business-item', class extends Component {
|
||||
super(`
|
||||
<style>
|
||||
:host { display: block; }
|
||||
* { font-family: 'Noto Sans', sans-serif; }
|
||||
* { font-family: 'Cardo', sans-serif; }
|
||||
:host([picture-url = '']) #img {
|
||||
display: none;
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ customElements.define('local-business', class extends Component {
|
||||
super(`
|
||||
<style>
|
||||
:host { display: block; }
|
||||
* { font-family: 'Noto Sans', sans-serif; }
|
||||
* { font-family: 'Cardo', sans-serif; }
|
||||
#items {
|
||||
margin-top: 16px;
|
||||
}
|
||||
@ -36,14 +36,6 @@ customElements.define('local-business', class extends Component {
|
||||
`);
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
super.connectedCallback();
|
||||
}
|
||||
|
||||
attributeChangedCallback(name, oldV, newV) {
|
||||
super.attributeChangedCallback(name, oldV, newV);
|
||||
}
|
||||
|
||||
get name() {
|
||||
return this.getAttribute('name') || ''
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ customElements.define('local-business-list', class extends Component {
|
||||
super(`
|
||||
<style>
|
||||
:host { display: block; }
|
||||
* { font-family: 'Noto Sans', sans-serif; }
|
||||
* { font-family: 'Cardo', sans-serif; }
|
||||
::slotted(local-business[local-business-visible="invisible"]) {
|
||||
display: none;
|
||||
}
|
||||
|
@ -5,12 +5,12 @@ customElements.define('login-form', class extends Component {
|
||||
super(`
|
||||
<style>
|
||||
:host { display: block; }
|
||||
* { font-family: 'Noto Sans', sans-serif; }
|
||||
* { font-family: 'Cardo', sans-serif; }
|
||||
${ FORM_STYLE }
|
||||
</style>
|
||||
<form action="/login" method="post">
|
||||
<div>
|
||||
<label>Login</label>
|
||||
<label>E-Mail</label>
|
||||
<input name="email" placeholder="E-Mail" type="email" required />
|
||||
</div>
|
||||
<div>
|
||||
|
@ -8,6 +8,7 @@ customElements.define('marketplace-offer', class extends Component {
|
||||
}
|
||||
|
||||
constructor() {
|
||||
// language=HTML
|
||||
super(`
|
||||
<style>
|
||||
:host {
|
||||
@ -16,23 +17,31 @@ customElements.define('marketplace-offer', class extends Component {
|
||||
border-bottom: 1px solid var(--border-light-gray-color);
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
section {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
#preview {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
image-popup {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
#sep {
|
||||
display: block;
|
||||
grid-area: sep;
|
||||
text-align: center;
|
||||
}
|
||||
:host([price-range-max="0"]) #sep {
|
||||
|
||||
:host([price-range-max="0"]) #sep, :host([price-range]) #sep,
|
||||
:host([price-range-max="0"]) #price-min, :host([price-range]) #price-min
|
||||
{
|
||||
display: none;
|
||||
}
|
||||
|
||||
#details {
|
||||
display: grid;
|
||||
column-gap: 16px;
|
||||
@ -40,24 +49,39 @@ customElements.define('marketplace-offer', class extends Component {
|
||||
"desc desc desc"
|
||||
"min sep max";
|
||||
grid-template-columns: auto 10px auto;
|
||||
width: 90%;
|
||||
}
|
||||
|
||||
#preview {
|
||||
grid-area: img;
|
||||
max-width: 200px;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
#description {
|
||||
grid-area: desc;
|
||||
text-align: justify;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
#price-min {
|
||||
grid-area: min;
|
||||
justify-self: end;
|
||||
-webkit-transition: background .3s, border .3s, border-radius .3s, -webkit-box-shadow .3s;
|
||||
transition: background .3s, border .3s, border-radius .3s, -webkit-box-shadow .3s;
|
||||
-o-transition: background .3s, border .3s, border-radius .3s, box-shadow .3s;
|
||||
transition: background .3s, border .3s, border-radius .3s, box-shadow .3s;
|
||||
transition: background .3s, border .3s, border-radius .3s, box-shadow .3s, -webkit-box-shadow .3s;
|
||||
}
|
||||
|
||||
#price-max {
|
||||
grid-area: max;
|
||||
justify-self: start;
|
||||
-webkit-transition: background .3s, border .3s, border-radius .3s, -webkit-box-shadow .3s;
|
||||
transition: background .3s, border .3s, border-radius .3s, -webkit-box-shadow .3s;
|
||||
-o-transition: background .3s, border .3s, border-radius .3s, box-shadow .3s;
|
||||
transition: background .3s, border .3s, border-radius .3s, box-shadow .3s;
|
||||
transition: background .3s, border .3s, border-radius .3s, box-shadow .3s, -webkit-box-shadow .3s;
|
||||
}
|
||||
|
||||
#contacts {
|
||||
display: flex;
|
||||
justify-content: end;
|
||||
@ -67,41 +91,42 @@ customElements.define('marketplace-offer', class extends Component {
|
||||
#details {
|
||||
display: grid;
|
||||
column-gap: 16px;
|
||||
grid-template-areas: "img desc desc desc desc desc"
|
||||
"img _ _ min sep max";
|
||||
grid-template-columns: 400px auto auto 100px 10px 100px;
|
||||
grid-template-areas: "img img img" "desc desc desc" "min sep max";
|
||||
grid-template-columns: auto 10px auto;
|
||||
margin: 0 20px 0 20px;
|
||||
}
|
||||
|
||||
image-popup {
|
||||
width: 100%;
|
||||
}
|
||||
image-popup {
|
||||
width: 400px;
|
||||
height: 400px;
|
||||
}
|
||||
|
||||
#preview {
|
||||
max-width: 400px;
|
||||
max-height: 400px;
|
||||
grid-area: img;
|
||||
align-self: center;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#description {
|
||||
min-height: 200px;
|
||||
grid-area: desc;
|
||||
justify-self: stretch;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
#price-min {
|
||||
grid-area: min;
|
||||
justify-self: end;
|
||||
width: 100px;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
#price-max {
|
||||
grid-area: max;
|
||||
justify-self: start;
|
||||
width: 100px;
|
||||
text-align: left;
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
|
||||
${ INPUT_STYLE }
|
||||
</style>
|
||||
<section id="details">
|
||||
@ -198,12 +223,12 @@ customElements.define('marketplace-offer', class extends Component {
|
||||
max.innerHTML = `Za darmo`;
|
||||
}
|
||||
if (this.#price_range.isRange) {
|
||||
min.innerHTML = `<price-view value="${this.#price_range.min}"></price-view>`
|
||||
max.innerHTML = `<price-view value="${this.#price_range.max}"></price-view>`;
|
||||
min.innerHTML = `<price-view value="${ this.#price_range.min }"></price-view>`
|
||||
max.innerHTML = `<price-view value="${ this.#price_range.max }"></price-view>`;
|
||||
}
|
||||
if (this.#price_range.isFixed) {
|
||||
min.innerHTML = ``;
|
||||
max.innerHTML = `<price-view value="${this.#price_range.min}"></price-view>`;
|
||||
max.innerHTML = `<price-view value="${ this.#price_range.min }"></price-view>`;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
@ -1,6 +1,10 @@
|
||||
import { Component } from "../shared";
|
||||
import { Component, BUTTON_STYLE } from "../shared";
|
||||
|
||||
customElements.define('marketplace-offers', class extends Component {
|
||||
static get observedAttributes() {
|
||||
return ['account-id'];
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super(`
|
||||
<style>
|
||||
@ -11,18 +15,48 @@ customElements.define('marketplace-offers', class extends Component {
|
||||
display: block;
|
||||
text-align: center;
|
||||
}
|
||||
article {
|
||||
margin: 8px;
|
||||
#offers {
|
||||
display: block;
|
||||
}
|
||||
::slotted(marketplace-offer), ::slotted(user-edit-offer) {
|
||||
width: 100%;
|
||||
margin: 0 20px 20px;
|
||||
}
|
||||
@media only screen and (min-device-width: 1000px) {
|
||||
article {
|
||||
margin: 0;
|
||||
#offers {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
::slotted(marketplace-offer), ::slotted(user-edit-offer) {
|
||||
width: calc(33% - 40px);
|
||||
margin: 0 20px 20px;
|
||||
}
|
||||
}
|
||||
${ BUTTON_STYLE }
|
||||
</style>
|
||||
<article>
|
||||
<slot></slot>
|
||||
<section>
|
||||
<button id="publish" class="btn">Dodaj ogłoszenie</button>
|
||||
</section>
|
||||
<section><slot></slot></section>
|
||||
<section id="offers">
|
||||
<slot name="offer"></slot>
|
||||
</section>
|
||||
</article>
|
||||
`);
|
||||
this.shadowRoot.querySelector('#publish').addEventListener('click', ev => {
|
||||
ev.stopPropagation();
|
||||
ev.preventDefault();
|
||||
location.href = '/account/offers';
|
||||
});
|
||||
}
|
||||
|
||||
set account_id(v) {
|
||||
this.setAttribute('account-id', v)
|
||||
}
|
||||
|
||||
get account_id() {
|
||||
return this.getAttribute('account-id');
|
||||
}
|
||||
});
|
||||
|
@ -16,15 +16,11 @@ customElements.define('user-edit-offer', class extends Component {
|
||||
:host([mode='form']) #form { display: block; }
|
||||
:host([state='Finished']) #finishForm { display: none; }
|
||||
#actions {
|
||||
width: 120px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
#actions > * {
|
||||
margin-right: 16px;
|
||||
}
|
||||
#actions input {
|
||||
width: 100%;
|
||||
width: 140px;
|
||||
}
|
||||
#state {
|
||||
font-weight: bold;
|
||||
@ -34,26 +30,19 @@ customElements.define('user-edit-offer', class extends Component {
|
||||
}
|
||||
@media only screen and (min-device-width: 1200px) {
|
||||
:host([mode='view']) #view { display: flex; }
|
||||
#actions {
|
||||
margin-left: 16px;
|
||||
display: block;
|
||||
}
|
||||
#actions > * {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
${ BUTTON_STYLE }
|
||||
</style>
|
||||
<section id="state"></section>
|
||||
<section id="view">
|
||||
<slot></slot>
|
||||
<div id="actions">
|
||||
<div id="state"></div>
|
||||
</section>
|
||||
<section id="actions">
|
||||
<input type="button" value="Edytuj" id="edit" />
|
||||
<form id="finishForm" action="/offers/finish" method="post">
|
||||
<input type="hidden" name="id" class="id" value="" />
|
||||
<input type="submit" slot="action" id="finish" value="Zakończ" />
|
||||
</form>
|
||||
</div>
|
||||
</section>
|
||||
<section id="form">
|
||||
<offer-form>
|
||||
@ -65,7 +54,7 @@ customElements.define('user-edit-offer', class extends Component {
|
||||
this.shadowRoot.querySelector('#edit').addEventListener('click', ev => {
|
||||
ev.stopPropagation();
|
||||
ev.preventDefault();
|
||||
this.mode = 'form';
|
||||
location.href = `/marketplace/${this.offer_id}/edit`
|
||||
});
|
||||
this.shadowRoot.querySelector('#cancel').addEventListener('click', ev => {
|
||||
ev.preventDefault();
|
||||
|
@ -40,7 +40,11 @@ customElements.define('account-view', class extends Component {
|
||||
}
|
||||
#logout {
|
||||
border-color: var(--red-color);
|
||||
color: var(--red-color);
|
||||
background: var(--red-color);
|
||||
color: white;
|
||||
}
|
||||
#logoutSection {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
section input[type="button"],
|
||||
section input[type="button"],
|
||||
@ -48,13 +52,10 @@ customElements.define('account-view', class extends Component {
|
||||
width: 100%;
|
||||
}
|
||||
section input[type="submit"],
|
||||
section a.btn {
|
||||
padding-bottom: 0;
|
||||
padding-top: 0;
|
||||
display: block;
|
||||
section a {
|
||||
color: black;
|
||||
}
|
||||
::slotted(#editService) {
|
||||
width: calc(100% - 1.5rem) !important;
|
||||
padding-bottom: 0 !important;
|
||||
padding-top: 0 !important;
|
||||
display: block !important;
|
||||
@ -77,11 +78,39 @@ customElements.define('account-view', class extends Component {
|
||||
width: auto;
|
||||
}
|
||||
::slotted(#editService) {
|
||||
min-width: 120px !important;
|
||||
width: auto !important;
|
||||
display: inline-block !important;
|
||||
}
|
||||
}
|
||||
::slotted(button) {
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
user-select: none;
|
||||
height: calc(1.5em + 0.75rem + 2px);
|
||||
border: 1px solid black;
|
||||
color: white;
|
||||
background: black;
|
||||
padding: 10px 20px;
|
||||
font-family: "Cardo", Sans-serif;
|
||||
font-size: 20px;
|
||||
font-weight: 500;
|
||||
line-height: 1em;
|
||||
letter-spacing: 0;
|
||||
transition: all 0.2s;
|
||||
width: 100%;
|
||||
}
|
||||
#editServiceSection {
|
||||
margin-bottom: 16px;
|
||||
width: 100%;
|
||||
}
|
||||
label {
|
||||
width: 120px;
|
||||
}
|
||||
.input {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
${ FORM_STYLE }${ BUTTON_STYLE }
|
||||
</style>
|
||||
<article>
|
||||
@ -89,11 +118,11 @@ customElements.define('account-view', class extends Component {
|
||||
<section>
|
||||
<input id="id" name="id" readonly type="hidden" />
|
||||
</section>
|
||||
<section>
|
||||
<section class="input">
|
||||
<label>Login</label>
|
||||
<input id="name" name="name" readonly />
|
||||
</section>
|
||||
<section>
|
||||
<section class="input">
|
||||
<label>E-Mail</label>
|
||||
<input id="email" name="email" readonly />
|
||||
</section>
|
||||
@ -106,17 +135,17 @@ customElements.define('account-view', class extends Component {
|
||||
<label>Powiązane konto Facebook</label>
|
||||
<input id="facebook_id" name="facebook_id" readonly />
|
||||
</section>
|
||||
<section>
|
||||
<section id="editServiceSection">
|
||||
<slot name="editService"></slot>
|
||||
</section>
|
||||
<section>
|
||||
<section id="logoutSection">
|
||||
<form action="/logout" method="post">
|
||||
<input id="logout" value="Wyloguj" type="submit" />
|
||||
</form>
|
||||
</section>
|
||||
<section id="rules">
|
||||
<a class="btn" href="/terms-and-condition" target="_blank">Regulamin</a>
|
||||
<a class="btn" href="/privacy-policy" target="_blank">Polityka prywatności</a>
|
||||
<a class="" href="/terms-and-condition" target="_blank">Regulamin</a>
|
||||
<a class="" href="/privacy-policy" target="_blank">Polityka prywatności</a>
|
||||
</section>
|
||||
</article>
|
||||
`);
|
||||
@ -124,6 +153,14 @@ customElements.define('account-view', class extends Component {
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
});
|
||||
{
|
||||
const input = this.querySelector('#editService');
|
||||
if (input) input.addEventListener('click', ev => {
|
||||
ev.stopPropagation();
|
||||
ev.preventDefault();
|
||||
location.href = "/account/business-items";
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Component, FORM_STYLE, goTo, historyDetails } from "../shared";
|
||||
import { Component, BUTTON_STYLE, Router } from "../shared";
|
||||
|
||||
customElements.define('ow-account', class extends Component {
|
||||
static get observedAttributes() {
|
||||
@ -9,7 +9,7 @@ customElements.define('ow-account', class extends Component {
|
||||
super(`
|
||||
<style>
|
||||
:host { display: block; }
|
||||
* { font-family: 'Noto Sans', sans-serif; }
|
||||
* { font-family: 'Cardo', sans-serif; }
|
||||
#switch-register, #switch-login {
|
||||
display: none;
|
||||
}
|
||||
@ -19,38 +19,39 @@ customElements.define('ow-account', class extends Component {
|
||||
:host([mode="register"]) #switch-login {
|
||||
display: block !important;
|
||||
}
|
||||
a {
|
||||
input {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
}
|
||||
a:hover {
|
||||
color: var(--hover-color);
|
||||
border-bottom-color: var(--hover-color);
|
||||
text-decoration: none;
|
||||
section > input[type=button] {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
}
|
||||
@media only screen and (min-device-width: 1000px) {
|
||||
}
|
||||
|
||||
${ FORM_STYLE }
|
||||
${ BUTTON_STYLE }
|
||||
</style>
|
||||
<article>
|
||||
<slot></slot>
|
||||
<section id="switch-register">
|
||||
<a class="btn">Nie masz konta? Utwórz nowe</a>
|
||||
<input type="button" class="btn" value="Nie masz konta? Utwórz nowe" />
|
||||
</section>
|
||||
<section id="switch-login">
|
||||
<a class="btn">Posiadasz konto? Zaloguj się</a>
|
||||
<input type="button" class="btn" value="Posiadasz konto? Zaloguj się" />
|
||||
</section>
|
||||
</article>
|
||||
`);
|
||||
|
||||
this.shadowRoot.querySelector('#switch-login > a').addEventListener('click', ev => {
|
||||
this.shadowRoot.querySelector('#switch-login > input').addEventListener('click', ev => {
|
||||
ev.stopPropagation();
|
||||
ev.preventDefault();
|
||||
goTo('/login');
|
||||
Router.goTo('/login');
|
||||
});
|
||||
this.shadowRoot.querySelector('#switch-register > a').addEventListener('click', ev => {
|
||||
this.shadowRoot.querySelector('#switch-register > input').addEventListener('click', ev => {
|
||||
ev.stopPropagation();
|
||||
ev.preventDefault();
|
||||
goTo('/register/account-type');
|
||||
Router.goTo('/register/account-type');
|
||||
});
|
||||
this.addEventListener('facebook:account', ev => {
|
||||
ev.stopPropagation();
|
||||
@ -60,24 +61,24 @@ customElements.define('ow-account', class extends Component {
|
||||
|
||||
connectedCallback() {
|
||||
super.connectedCallback();
|
||||
const parts = historyDetails().parts;
|
||||
this.listenHistory(Router.historyDetails());
|
||||
}
|
||||
|
||||
listenHistory = ({ parts }) => {
|
||||
switch (parts.first) {
|
||||
case 'register': {
|
||||
if (this.mode === 'register')
|
||||
return;
|
||||
this.mode = 'register';
|
||||
break;
|
||||
}
|
||||
default:
|
||||
default: {
|
||||
if (this.mode === 'login')
|
||||
return;
|
||||
this.mode = 'login';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
listenHistory = ({ parts }) => {
|
||||
console.warn(parts);
|
||||
}
|
||||
|
||||
attributeChangedCallback(name, oldV, newV) {
|
||||
super.attributeChangedCallback(name, oldV, newV);
|
||||
}
|
||||
|
||||
get mode() {
|
||||
@ -87,5 +88,14 @@ customElements.define('ow-account', class extends Component {
|
||||
set mode(value) {
|
||||
value = ['login', 'register', 'display'].includes(value) ? value : 'login';
|
||||
this.setAttribute('mode', value);
|
||||
switch (value) {
|
||||
case 'register': {
|
||||
this.innerHTML = `<register-form></register-form>`;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
this.innerHTML = `<login-form></login-form>`;
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { FORM_STYLE, Component, goTo } from "./shared.js";
|
||||
import { FORM_STYLE, Component, Router } from "./shared.js";
|
||||
import { RegisterForm } from "./register-form/model.js";
|
||||
|
||||
customElements.define('register-form', class extends Component {
|
||||
@ -12,7 +12,7 @@ customElements.define('register-form', class extends Component {
|
||||
super(`
|
||||
<style>
|
||||
:host { display: block; }
|
||||
* { font-family: 'Noto Sans', sans-serif; }
|
||||
* { font-family: 'Cardo', sans-serif; }
|
||||
|
||||
.actions {
|
||||
display: flex;
|
||||
@ -73,15 +73,15 @@ customElements.define('register-form', class extends Component {
|
||||
#loadCache() {
|
||||
let register = {};
|
||||
try {
|
||||
register = JSON.parse(localStorage.getItem('register'));
|
||||
register = JSON.parse(localStorage.getItem('register') || '{}');
|
||||
} catch (e) {
|
||||
localStorage.removeItem('register');
|
||||
}
|
||||
this.#form.from(register);
|
||||
}
|
||||
|
||||
#copyDetail(ev) {
|
||||
ev.stopPropagation();
|
||||
console.info('ev.detail', ev.detail);
|
||||
for (const [key, value] of Object.entries(ev.detail)) {
|
||||
this.#form[key] = value;
|
||||
}
|
||||
@ -203,7 +203,7 @@ customElements.define('register-form', class extends Component {
|
||||
? this.#nextPage()
|
||||
: this.#prevPage();
|
||||
this.current = current;
|
||||
goTo(`/register/${ current }`);
|
||||
Router.goTo(`/register/${ current }`);
|
||||
}
|
||||
|
||||
get current() {
|
||||
|
@ -159,7 +159,8 @@ export class RegisterForm {
|
||||
}, {})
|
||||
}
|
||||
|
||||
from(object) {
|
||||
from(object = {}) {
|
||||
object = object || {};
|
||||
[
|
||||
'email',
|
||||
'login',
|
||||
|
@ -21,8 +21,6 @@ customElements.define('register-account-type', class extends Component {
|
||||
}
|
||||
a {
|
||||
display: block;
|
||||
border: 1px solid var(--border-slim-color);
|
||||
border-radius: 16px;
|
||||
padding: 16px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
@ -57,21 +55,22 @@ customElements.define('register-account-type', class extends Component {
|
||||
}
|
||||
#rules > a {
|
||||
display: block;
|
||||
font-size: 20px;
|
||||
}
|
||||
}
|
||||
${ BUTTON_STYLE }${ TIP_STYLE }
|
||||
</style>
|
||||
<article>
|
||||
<section id="rules">
|
||||
<a class="btn" target="_blank" href="/terms-and-condition">
|
||||
<a target="_blank" href="/terms-and-condition">
|
||||
Regulamin
|
||||
</a>
|
||||
<a class="btn" target="_blank" href="/privacy-policy">
|
||||
<a target="_blank" href="/privacy-policy">
|
||||
Polityka prywatności
|
||||
</a>
|
||||
</section>
|
||||
<button id="accept-terms">
|
||||
<h5>Zapoznałem się i zgadzam się</h5>
|
||||
Zapoznałem się i zgadzam się
|
||||
</button>
|
||||
</article>
|
||||
`);
|
||||
@ -110,7 +109,7 @@ customElements.define('register-account-type', class extends Component {
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<form-navigation></form-navigation>
|
||||
<form-navigation style="display: none;"></form-navigation>
|
||||
`;
|
||||
|
||||
const user = this.shadowRoot.querySelector('#user');
|
||||
|
@ -10,15 +10,24 @@ customElements.define('register-business-contacts-form', class extends RegisterF
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
contact-info-editor > input[type='button'] {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
}
|
||||
::slotted(edit-contact-info) {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
${ BUTTON_STYLE }
|
||||
</style>
|
||||
<article>
|
||||
<h2>Edycja listy danych kontaktowych</h2>
|
||||
<form>
|
||||
<section>
|
||||
<contact-info-editor
|
||||
save="false"
|
||||
></contact-info-editor>
|
||||
>
|
||||
<input type="button" id="addButton" value="Dodaj" />
|
||||
</contact-info-editor>
|
||||
</section>
|
||||
<slot></slot>
|
||||
<form-navigation></form-navigation>
|
||||
@ -26,19 +35,16 @@ customElements.define('register-business-contacts-form', class extends RegisterF
|
||||
</article>
|
||||
`);
|
||||
|
||||
this.shadowRoot.querySelector('#addButton').addEventListener('click', ev => {
|
||||
const editor = this.shadowRoot.querySelector('contact-info-editor');
|
||||
editor.addEventListener('submit', ev => {
|
||||
ev.stopPropagation();
|
||||
ev.preventDefault();
|
||||
const form = this.shadowRoot.querySelector('contact-info-editor');
|
||||
const { type, content } = form;
|
||||
this.innerHTML += `
|
||||
<edit-contact-info mode="view" delete="false">
|
||||
<contact-info
|
||||
type="${ type }"
|
||||
content="${ content }"
|
||||
></contact-info>
|
||||
</edit-contact-info>
|
||||
`;
|
||||
this.#addContact(editor);
|
||||
});
|
||||
editor.querySelector('#addButton').addEventListener('click', ev => {
|
||||
ev.stopPropagation();
|
||||
ev.preventDefault();
|
||||
this.#addContact(editor);
|
||||
});
|
||||
|
||||
this.mountFormHandler(() => this.#emitChange());
|
||||
@ -52,6 +58,18 @@ customElements.define('register-business-contacts-form', class extends RegisterF
|
||||
return Array.from(this.querySelectorAll('contact-info'));
|
||||
}
|
||||
|
||||
#addContact(editor) {
|
||||
const { type, content } = editor;
|
||||
this.innerHTML += `
|
||||
<edit-contact-info mode="view" delete="false">
|
||||
<contact-info
|
||||
type="${ type }"
|
||||
content="${ content }"
|
||||
></contact-info>
|
||||
</edit-contact-info>
|
||||
`;
|
||||
}
|
||||
|
||||
#emitChange() {
|
||||
const rows = this.#rows;
|
||||
const contacts = rows.map(({ type, content }) => ({
|
||||
|
@ -5,12 +5,17 @@ customElements.define('register-business-details-form', class extends RegisterFo
|
||||
static get observedAttributes() {
|
||||
return ["name", "description"];
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super(`
|
||||
<style>
|
||||
:host { display: block; }
|
||||
* { font-family: 'Noto Sans', sans-serif; }
|
||||
* { font-family: 'Cardo', sans-serif; }
|
||||
textarea { min-height: 200px; }
|
||||
form > div > input,
|
||||
form > div > textarea {
|
||||
width: 100%;
|
||||
}
|
||||
${ FORM_STYLE }${ TIP_STYLE }
|
||||
</style>
|
||||
<form id="step-2">
|
||||
|
@ -10,16 +10,30 @@ customElements.define('register-business-item-form', class extends RegisterFormC
|
||||
super(`
|
||||
<style>
|
||||
:host { display: block; }
|
||||
* { font-family: 'Noto Sans', sans-serif; }
|
||||
* { font-family: 'Cardo', sans-serif; }
|
||||
section > form input[type=button], section > form input[type=submit] {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
}
|
||||
form > #fields > div, form > #fields > div > label, form > #fields > div > .input {
|
||||
width: 90% !important;
|
||||
}
|
||||
@media only screen and (min-device-width: 1200px) {
|
||||
section > form {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
}
|
||||
form > input[type=submit] {
|
||||
section > form input[type=button], section > form input[type=submit] {
|
||||
width: 25%;
|
||||
max-width: 25%;
|
||||
}
|
||||
form > #fields {
|
||||
width: 50%;
|
||||
}
|
||||
form > #fields > div, form > #fields > div > label, form > #fields > div > .input {
|
||||
width: 90% !important;
|
||||
}
|
||||
}
|
||||
img[src=""] { display: none; }
|
||||
${ FORM_STYLE }
|
||||
</style>
|
||||
@ -27,6 +41,7 @@ customElements.define('register-business-item-form', class extends RegisterFormC
|
||||
<form method="post">
|
||||
<slot name="head"></slot>
|
||||
<image-input send-original="true"></image-input>
|
||||
<div id="fields">
|
||||
<div id="name">
|
||||
<label>Nazwa</label>
|
||||
<input id="name" class="item-name" name="name" type="text" required />
|
||||
@ -36,6 +51,7 @@ customElements.define('register-business-item-form', class extends RegisterFormC
|
||||
<price-input id="price" class="item-price" name="price" required >
|
||||
</price-input>
|
||||
</div>
|
||||
</div>
|
||||
<input id="submit-button" type="submit" value="Zapisz" />
|
||||
<input id="remove-button" type="submit" value="Usuń" />
|
||||
|
||||
@ -137,7 +153,6 @@ customElements.define('register-business-item-form', class extends RegisterFormC
|
||||
|
||||
set price(v) {
|
||||
v = parseInt(v);
|
||||
console.info('set price', v);
|
||||
this.setAttribute('price', v);
|
||||
this.shadowRoot.querySelector('#price').value = v / 100.0;
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ customElements.define('register-business-items-form', class extends RegisterForm
|
||||
super(`
|
||||
<style>
|
||||
:host { display: block; }
|
||||
* { font-family: 'Noto Sans', sans-serif; }
|
||||
* { font-family: 'Cardo', sans-serif; }
|
||||
|
||||
::slotted(section) {
|
||||
display: flex;
|
||||
@ -23,6 +23,10 @@ customElements.define('register-business-items-form', class extends RegisterForm
|
||||
::slotted(register-business-item-form) {
|
||||
margin-bottom: 18px;
|
||||
}
|
||||
form input[type=button], form input[type=submit] {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
${ FORM_STYLE }
|
||||
</style>
|
||||
@ -68,10 +72,7 @@ customElements.define('register-business-items-form', class extends RegisterForm
|
||||
}
|
||||
|
||||
#emitChange() {
|
||||
const rows = this.#rows;
|
||||
console.warn(rows);
|
||||
const items = this.#rows.map(({ price, picture_url, name }) => ({ price, picture_url, name }));
|
||||
console.warn(items);
|
||||
this.dispatchEvent(new CustomEvent(this.submitEventName, { bubbles: true, composed: true, detail: { items } }));
|
||||
}
|
||||
});
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { FORM_STYLE, goTo, PseudoForm } from "../shared.js";
|
||||
import { FORM_STYLE, Router, PseudoForm } from "../shared.js";
|
||||
import { ErrorMessage } from "../shared/error-message.js";
|
||||
|
||||
customElements.define('register-business-submit-form', class extends PseudoForm {
|
||||
static get observedAttributes() {
|
||||
@ -9,10 +10,14 @@ customElements.define('register-business-submit-form', class extends PseudoForm
|
||||
super(`
|
||||
<style>
|
||||
:host { display: block; }
|
||||
* { font-family: 'Noto Sans', sans-serif; }
|
||||
* { font-family: 'Cardo', sans-serif; }
|
||||
${ FORM_STYLE }
|
||||
img[src=''] { display: none; }
|
||||
@media only screen and (min-device-width: 1200px) {
|
||||
input[type=submit] {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
}
|
||||
@media only screen and (min-device-width: 1000px) {
|
||||
.item-view {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
@ -75,10 +80,11 @@ customElements.define('register-business-submit-form', class extends PseudoForm
|
||||
});
|
||||
|
||||
if (res.ok) {
|
||||
goTo("/account?success");
|
||||
// Router.goTo("/account?success");
|
||||
location.href ='/account?success';
|
||||
} else {
|
||||
const { error } = await res.json();
|
||||
document.querySelector('error-message').message = error;
|
||||
ErrorMessage.errorMessage = error;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { FORM_STYLE } from "../shared";
|
||||
import { RegisterFormComponent } from "./model";
|
||||
import { FORM_STYLE, Router } from "../shared.js";
|
||||
import { RegisterFormComponent } from "./model.js";
|
||||
import { ErrorMessage } from "../shared/error-message";
|
||||
|
||||
customElements.define('register-user-account-form', class extends RegisterFormComponent {
|
||||
static get observedAttributes() {
|
||||
@ -10,13 +11,7 @@ customElements.define('register-user-account-form', class extends RegisterFormCo
|
||||
super(`
|
||||
<style>
|
||||
:host { display: block; }
|
||||
* { font-family: 'Noto Sans', sans-serif; }
|
||||
:host([mode="email"]) #form {
|
||||
display: block;
|
||||
}
|
||||
:host([mode="email"]) #email-icon {
|
||||
display: none;
|
||||
}
|
||||
* { font-family: 'Cardo', sans-serif; }
|
||||
svg > path {
|
||||
fill: var(--border-slim-color);
|
||||
}
|
||||
@ -99,6 +94,34 @@ customElements.define('register-user-account-form', class extends RegisterFormCo
|
||||
form.querySelector('#account_type').value = 'User';
|
||||
form.submit();
|
||||
});
|
||||
|
||||
form.addEventListener('submit', async ev => {
|
||||
ev.stopPropagation();
|
||||
ev.preventDefault();
|
||||
const json = Array.from(form.elements).filter(el => el.name && el.name.trim().length).reduce((memo, {
|
||||
name,
|
||||
value
|
||||
}) => ({
|
||||
...memo,
|
||||
[name]: value.trim(),
|
||||
}), {});
|
||||
|
||||
const res = await fetch('/register', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(json),
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Accept': 'application/json',
|
||||
}
|
||||
});
|
||||
if (res.ok) {
|
||||
// Router.goTo("/account?success");
|
||||
location.href ='/account?success';
|
||||
} else {
|
||||
const { error } = await res.json();
|
||||
ErrorMessage.errorMessage = error;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
get submitEventName() {
|
||||
@ -106,21 +129,10 @@ customElements.define('register-user-account-form', class extends RegisterFormCo
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
super.connectedCallback();
|
||||
this.mode = 'email';
|
||||
}
|
||||
|
||||
attributeChangedCallback(name, oldV, newV) {
|
||||
if (oldV === newV) return;
|
||||
switch (name) {
|
||||
case 'mode': {
|
||||
if (newV !== 'email' && newV !== 'facebook' && newV !== '')
|
||||
return;
|
||||
this.mode = newV;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
get mode() {
|
||||
return this.getAttribute('mode') || ''
|
||||
}
|
||||
|
@ -1,53 +1,43 @@
|
||||
export const BUTTON_STYLE = `
|
||||
input[type="button"], input[type="submit"], button {
|
||||
cursor: pointer;
|
||||
border-radius: 5px;
|
||||
box-shadow: 0 10px 20px -6px rgba(0,0,0,.12);
|
||||
position: relative;
|
||||
margin-bottom: 20px;
|
||||
transition: .3s;
|
||||
display: inline-block;
|
||||
font-weight: 400;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
user-select: none;
|
||||
font-size: 1rem;
|
||||
line-height: 1.5;
|
||||
transition: color .15s ease-in-out,
|
||||
background-color .15s ease-in-out,
|
||||
border-color .15s ease-in-out,
|
||||
box-shadow .15s ease-in-out;
|
||||
width: auto;
|
||||
height: calc(1.5em + 0.75rem + 2px);
|
||||
padding: .375rem .75rem;
|
||||
|
||||
border: 1px solid #495057;
|
||||
color: #495057;
|
||||
background: white;
|
||||
border: 1px solid black;
|
||||
color: white;
|
||||
background: black;
|
||||
padding: 10px 20px;
|
||||
font-family: "Cardo", Sans-serif;
|
||||
font-size: 20px;
|
||||
font-weight: 500;
|
||||
line-height: 1em;
|
||||
letter-spacing: 0;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
.btn {
|
||||
cursor: pointer;
|
||||
border-radius: 5px;
|
||||
box-shadow: 0 10px 20px -6px rgba(0, 0, 0, .12);
|
||||
position: relative;
|
||||
margin-bottom: 20px;
|
||||
display: inline-block;
|
||||
font-weight: 400;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
user-select: none;
|
||||
font-size: 1rem;
|
||||
line-height: 1.5;
|
||||
transition: color .15s ease-in-out,
|
||||
background-color .15s ease-in-out,
|
||||
border-color .15s ease-in-out,
|
||||
box-shadow .15s ease-in-out;
|
||||
width: auto;
|
||||
height: calc(1.5em + 0.75rem + 2px);
|
||||
padding: .375rem .75rem;
|
||||
border: 1px solid #495057;
|
||||
color: #495057;
|
||||
background: white;
|
||||
border: 1px solid black;
|
||||
color: white;
|
||||
background: black;
|
||||
padding: 10px 20px;
|
||||
font-family: "Cardo", Sans-serif;
|
||||
font-size: 20px;
|
||||
font-weight: 500;
|
||||
line-height: 1em;
|
||||
letter-spacing: 0;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
a.btn {
|
||||
text-decoration: none;
|
||||
@ -66,34 +56,25 @@ input.link:hover {
|
||||
|
||||
export const INPUT_STYLE = `
|
||||
input, textarea, select, option {
|
||||
font-size: 16px;
|
||||
box-sizing: border-box;
|
||||
border: 1px solid var(--ast-border-color);
|
||||
padding: 6px 6px 5px;
|
||||
margin: 0 4px 0 0;
|
||||
outline: 0;
|
||||
line-height: 1;
|
||||
|
||||
border: none;
|
||||
border-bottom-style: none;
|
||||
border-bottom-width: medium;
|
||||
border-bottom: 1px solid rgba(0,0,0,.1);
|
||||
color: #666;
|
||||
padding: .75em;
|
||||
height: auto;
|
||||
border-width: 1px;
|
||||
border-style: solid;
|
||||
border-color: var(--ast-border-color);
|
||||
border-radius: 2px;
|
||||
padding: 0;
|
||||
|
||||
height: 36px;
|
||||
background: #fff;
|
||||
color: rgba(0,0,0,.8);
|
||||
font-size: 14px;
|
||||
|
||||
box-shadow: none !important;
|
||||
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: calc(1.5em + 0.75rem + 2px);
|
||||
padding: .375rem .75rem;
|
||||
font-size: 1rem;
|
||||
font-weight: 400;
|
||||
line-height: 1.5;
|
||||
color: #495057;
|
||||
background-clip: padding-box;
|
||||
transition: border-color .15s ease-in-out , -webkit-box-shadow .15s ease-in-out;
|
||||
transition: border-color .15s ease-in-out , box-shadow .15s ease-in-out;
|
||||
transition: border-color .15s ease-in-out , box-shadow .15s ease-in-out , -webkit-box-shadow .15s ease-in-out;
|
||||
background: #fafafa;
|
||||
background-color: rgb(250, 250, 250);
|
||||
box-shadow: none;
|
||||
box-sizing: border-box;
|
||||
transition: all .2s linear;
|
||||
}
|
||||
input[type="text"],
|
||||
input[type="number"],
|
||||
@ -170,8 +151,8 @@ export class Component extends HTMLElement {
|
||||
}
|
||||
{
|
||||
const listener = this.listenHistory;
|
||||
listener && listener(historyDetails());
|
||||
this.#dropHistory = subscribeHistory(listener);
|
||||
listener && listener(Router.historyDetails());
|
||||
this.#dropHistory = Router.subscribeHistory(listener);
|
||||
}
|
||||
}
|
||||
|
||||
@ -180,7 +161,9 @@ export class Component extends HTMLElement {
|
||||
}
|
||||
|
||||
#dropHistory;
|
||||
listenHistory = null
|
||||
|
||||
listenHistory() {
|
||||
}
|
||||
|
||||
attributeChangedCallback(name, oldV, newV) {
|
||||
if (oldV === newV)
|
||||
@ -274,7 +257,7 @@ export class PriceRange {
|
||||
toString() {
|
||||
if (this.isFixed) return this.min.toString()
|
||||
if (this.isFree) return 'free';
|
||||
return `${this.min}|${this.max}`;
|
||||
return `${ this.min }|${ this.max }`;
|
||||
}
|
||||
}
|
||||
|
||||
@ -289,22 +272,38 @@ export const runFbReady = (fn) => {
|
||||
const fbQueue = [];
|
||||
let fbReady = false;
|
||||
|
||||
const historyQueue = new Set;
|
||||
export const goTo = (url) => {
|
||||
export class Router {
|
||||
static historyQueue = new Set;
|
||||
|
||||
static goTo(url) {
|
||||
history.pushState({}, document.title, url);
|
||||
for (const call of historyQueue) call();
|
||||
document.dispatchEvent(new CustomEvent('history:push', { composed: true, bubbles: true, details: historyDetails() }));
|
||||
}
|
||||
export const historyDetails = () => {
|
||||
const parts = location.pathname.split('/').filter(s => s && s.length)
|
||||
return { parts }
|
||||
}
|
||||
const subscribeHistory = (cb) => {
|
||||
Router.onChange();
|
||||
}
|
||||
|
||||
static historyDetails() {
|
||||
return {
|
||||
parts: location.pathname.split('/').filter(s => s && s.length),
|
||||
}
|
||||
}
|
||||
|
||||
static subscribeHistory(cb) {
|
||||
if (cb) {
|
||||
const call = () => {
|
||||
cb(historyDetails());
|
||||
cb(Router.historyDetails());
|
||||
}
|
||||
historyQueue.add(call);
|
||||
return () => historyQueue.delete(call);
|
||||
Router.historyQueue.add(call);
|
||||
return () => Router.historyQueue.delete(call);
|
||||
}
|
||||
}
|
||||
|
||||
static onChange() {
|
||||
for (const call of Router.historyQueue) call();
|
||||
document.dispatchEvent(new CustomEvent('history:push', {
|
||||
composed: true,
|
||||
bubbles: true,
|
||||
details: Router.historyDetails()
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener('popstate', () => Router.onChange());
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { Component } from "../shared.js";
|
||||
|
||||
customElements.define('error-message', class extends Component {
|
||||
export class ErrorMessage extends Component {
|
||||
static get observedAttributes() {
|
||||
return ['message'];
|
||||
}
|
||||
@ -8,7 +8,8 @@ customElements.define('error-message', class extends Component {
|
||||
constructor() {
|
||||
super(`
|
||||
<style>
|
||||
:host { display: block; }
|
||||
:host { display: none; }
|
||||
:host([message]) { display: block; }
|
||||
div {
|
||||
width: 1280px;
|
||||
background: #ffe0e0;
|
||||
@ -30,4 +31,12 @@ customElements.define('error-message', class extends Component {
|
||||
this.setAttribute('message', m);
|
||||
this.shadowRoot.querySelector('div').textContent = m;
|
||||
}
|
||||
})
|
||||
|
||||
static set errorMessage(v) {
|
||||
const el = document.querySelector('error-message');
|
||||
if (!el) return;
|
||||
el.message = v;
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('error-message', ErrorMessage)
|
||||
|
@ -9,17 +9,25 @@ customElements.define('form-navigation', class extends Component {
|
||||
super(`
|
||||
<style>
|
||||
:host { display: block; }
|
||||
* { font-family: 'Noto Sans', sans-serif; }
|
||||
* { font-family: 'Cardo', sans-serif; }
|
||||
.actions {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
form > .actions > input {
|
||||
max-width: 200px;
|
||||
margin: 16px 0;
|
||||
}
|
||||
form > .actions > input.hidden {
|
||||
display: none !important;
|
||||
}
|
||||
form > .actions > input {
|
||||
width: calc(50% - 16px);
|
||||
max-width: 200px;
|
||||
}
|
||||
@media only screen and (min-device-width: 1000px) {
|
||||
form > .actions > input {
|
||||
width: auto;
|
||||
max-width: 200px;
|
||||
}
|
||||
}
|
||||
${ BUTTON_STYLE }
|
||||
</style>
|
||||
<form>
|
||||
|
@ -1,41 +1,109 @@
|
||||
import { Component } from "../../shared";
|
||||
import { Component, Router } from "../../shared.js";
|
||||
|
||||
customElements.define('ow-nav', class extends Component {
|
||||
constructor() {
|
||||
super(`
|
||||
<style>
|
||||
:host { display: block; }
|
||||
* { font-family: 'Noto Sans', sans-serif; }
|
||||
section {
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
align-content: stretch;
|
||||
|
||||
margin-bottom: 12px;
|
||||
color: #2b2727;
|
||||
font-family: Raleway, sans-serif;
|
||||
font-size: 14px;
|
||||
line-height: 32px;
|
||||
article {
|
||||
border-style: solid;
|
||||
border-width: 0 0 1px 0;
|
||||
border-color: #F2F2F2;
|
||||
transition: background 0.3s, border 0.3s, border-radius 0.3s, box-shadow 0.3s;
|
||||
margin-top: 0;
|
||||
margin-bottom: 16px;
|
||||
padding: 13px 10px 13px 10px;
|
||||
}
|
||||
section::after {
|
||||
display: block;
|
||||
content: ' ';
|
||||
border: none;
|
||||
padding: 10px 18px;
|
||||
text-decoration: none;
|
||||
color: #2b2727;
|
||||
text-transform: uppercase;
|
||||
align-self: stretch;
|
||||
flex-shrink: 20;
|
||||
flex-grow: 20;
|
||||
section, section > div {
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
position: relative;
|
||||
}
|
||||
svg {
|
||||
height: 48px;
|
||||
}
|
||||
#logo {
|
||||
display: none;
|
||||
}
|
||||
@media print {
|
||||
:host { display: none; }
|
||||
}
|
||||
@media only screen and (min-device-width: 1000px) {
|
||||
section > div {
|
||||
width: 33%;
|
||||
margin: 0 auto;
|
||||
}
|
||||
#logo {
|
||||
display: block;
|
||||
text-align: center;
|
||||
}
|
||||
#right {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<article>
|
||||
<section>
|
||||
<slot></slot>
|
||||
<div class="left">
|
||||
<slot name="left"></slot>
|
||||
</div>
|
||||
<div id="logo">
|
||||
<a href="/">
|
||||
<svg viewBox="0 0 911 550" xmlns="http://www.w3.org/2000/svg">
|
||||
<ellipse cx="293" cy="335.2" rx="121" ry="170.61" fill="none" stroke="#555" style="opacity:.5" opacity=".5"/>
|
||||
<ellipse cx="653.783" cy="113.849" rx="121.002" ry="170.613" fill="none" stroke="#555" transform="rotate(11.25)" style="opacity:.5" opacity=".5"/>
|
||||
<ellipse cx="428.125" cy="166.014" rx="125.003" ry="176.254" fill="none" stroke="#555" transform="rotate(22.5)" style="opacity:.5" opacity=".5"/>
|
||||
<ellipse cx="402.034" cy="23.889" rx="123.005" ry="173.437" fill="none" stroke="#555" transform="rotate(33.75)" style="opacity:.5" opacity=".5"/>
|
||||
<ellipse cx="464.706" cy="-31.682" rx="124.999" ry="176.248" fill="none" stroke="#555" transform="rotate(45)" style="opacity:.5" opacity=".5"/>
|
||||
<ellipse cx="540.521" cy="-306.337" rx="129.005" ry="181.898" fill="none" stroke="#555" transform="rotate(56.25)" style="opacity:.5" opacity=".5"/>
|
||||
<ellipse cx="494.207" cy="-442.566" rx="124.003" ry="174.844" fill="none" stroke="#555" transform="rotate(67.5)" style="opacity:.5" opacity=".5"/>
|
||||
<ellipse cx="239.113" cy="-150.236" rx="126.002" ry="177.663" fill="none" stroke="#555" transform="rotate(78.75)" style="opacity:.5" opacity=".5"/>
|
||||
<ellipse cx="304.2" cy="-330" rx="128" ry="180.48" fill="none" stroke="#555" transform="rotate(90)" style="opacity:.5" opacity=".5"/>
|
||||
<ellipse cx="143.181" cy="-572.932" rx="120.002" ry="169.203" fill="none" stroke="#555" transform="rotate(101.25)" style="opacity:.5" opacity=".5"/>
|
||||
<ellipse cx="142" cy="-386.769" rx="123.003" ry="173.434" fill="none" stroke="#555" transform="rotate(112.5)" style="opacity:.5" opacity=".5"/>
|
||||
<ellipse cx="-91.151" cy="-617.377" rx="123.005" ry="173.437" fill="none" stroke="#555" transform="rotate(123.75)" style="opacity:.5" opacity=".5"/>
|
||||
<ellipse cx="-17.541" cy="-483.099" rx="124.999" ry="176.248" fill="none" stroke="#555" transform="rotate(135)" style="opacity:.5" opacity=".5"/>
|
||||
<ellipse cx="-89.814" cy="-445.118" rx="128.005" ry="180.488" fill="none" stroke="#555" transform="rotate(146.25)" style="opacity:.5" opacity=".5"/>
|
||||
<ellipse cx="-309.998" cy="-338.613" rx="125.003" ry="176.254" fill="none" stroke="#555" transform="rotate(157.5)" style="opacity:.5" opacity=".5"/>
|
||||
<ellipse cx="-514.833" cy="-456.414" rx="120.002" ry="169.203" fill="none" stroke="#555" transform="rotate(168.75)" style="opacity:.5" opacity=".5"/>
|
||||
<ellipse cx="-534" cy="-351.2" rx="126" ry="177.66" fill="none" stroke="#555" transform="scale(-1)" style="opacity:.5" opacity=".5"/>
|
||||
<ellipse cx="-434.371" cy="-246.176" rx="128.002" ry="180.483" fill="none" stroke="#555" transform="rotate(-168.75)" style="opacity:.5" opacity=".5"/>
|
||||
<ellipse cx="-710.531" cy="4.041" rx="126.003" ry="177.664" fill="none" stroke="#555" transform="rotate(-157.5)" style="opacity:.5" opacity=".5"/>
|
||||
<ellipse cx="-382.027" cy="-19.162" rx="130.005" ry="183.308" fill="none" stroke="#555" transform="rotate(-146.25)" style="opacity:.5" opacity=".5"/>
|
||||
<ellipse cx="-721.398" cy="240.271" rx="129.999" ry="183.298" fill="none" stroke="#555" transform="rotate(-135)" style="opacity:.5" opacity=".5"/>
|
||||
<ellipse cx="-304.791" cy="106.633" rx="123.005" ry="173.437" fill="none" stroke="#555" transform="rotate(-123.75)" style="opacity:.5" opacity=".5"/>
|
||||
<ellipse cx="-495.302" cy="413.961" rx="128.003" ry="180.485" fill="none" stroke="#555" transform="rotate(-112.5)" style="opacity:.5" opacity=".5"/>
|
||||
<ellipse cx="-265.515" cy="206.161" rx="125.002" ry="176.253" fill="none" stroke="#555" transform="rotate(-101.25)" style="opacity:.5" opacity=".5"/>
|
||||
<ellipse cx="-180.2" cy="605" rx="122" ry="172.02" fill="none" stroke="#555" transform="rotate(-90)" style="opacity:.5" opacity=".5"/>
|
||||
<ellipse cx="-137.223" cy="326.045" rx="121.002" ry="170.613" fill="none" stroke="#555" transform="rotate(-78.75)" style="opacity:.5" opacity=".5"/>
|
||||
<ellipse cx="-80.373" cy="352.613" rx="125.003" ry="176.254" fill="none" stroke="#555" transform="rotate(-67.5)" style="opacity:.5" opacity=".5"/>
|
||||
<ellipse cx="-50.619" cy="275.587" rx="126.005" ry="177.667" fill="none" stroke="#555" transform="rotate(-56.25)" style="opacity:.5" opacity=".5"/>
|
||||
<ellipse cx="-22.773" cy="406.017" rx="126.999" ry="179.068" fill="none" stroke="#555" transform="rotate(-45)" style="opacity:.5" opacity=".5"/>
|
||||
<ellipse cx="97.486" cy="309.523" rx="121.005" ry="170.617" fill="none" stroke="#555" transform="rotate(-33.75)" style="opacity:.5" opacity=".5"/>
|
||||
<ellipse cx="507.007" cy="435.361" rx="129.003" ry="181.895" fill="none" stroke="#555" transform="rotate(-22.5)" style="opacity:.5" opacity=".5"/>
|
||||
<ellipse cx="261.461" cy="254.093" rx="130.002" ry="183.303" fill="none" stroke="#555" transform="rotate(-11.25)" style="opacity:.5" opacity=".5"/>
|
||||
<text xml:space="preserve" style="font-style:normal;font-weight:400;font-size:200px;line-height:1.25;font-family:sans-serif;fill:#000;fill-opacity:1;stroke:none" x="36.404" y="311.43">
|
||||
<tspan x="36.404" y="311.43" style="font-style:normal;font-variant:normal;font-weight:400;font-stretch:normal;font-family:'Cardo';">OS Wilno</tspan>
|
||||
</text>
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
<div id="right">
|
||||
<slot name="right"></slot>
|
||||
</div>
|
||||
</section>
|
||||
</article>
|
||||
`);
|
||||
}
|
||||
|
||||
#mount(selector, path) {
|
||||
const el = this.querySelector(selector);
|
||||
if (!el) return;
|
||||
el.addEventListener('click', (ev) => {
|
||||
ev.stopPropagation();
|
||||
ev.preventDefault();
|
||||
Router.goTo(path);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
@ -9,7 +9,7 @@ customElements.define('ow-path', class extends Component {
|
||||
super(`
|
||||
<style>
|
||||
:host { display: block; }
|
||||
* { font-family: 'Noto Sans', sans-serif; }
|
||||
* { font-family: 'Cardo', sans-serif; }
|
||||
a {
|
||||
padding: 8px;
|
||||
text-decoration: none;
|
||||
|
@ -9,7 +9,7 @@ customElements.define('price-input', class extends Component {
|
||||
super(`
|
||||
<style>
|
||||
:host { display: block; }
|
||||
* { font-family: 'Noto Sans', sans-serif; }
|
||||
* { font-family: 'Cardo', sans-serif; }
|
||||
#price {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ customElements.define('price-view', class extends HTMLElement {
|
||||
shadow.innerHTML = `
|
||||
<style>
|
||||
:host { display: block; }
|
||||
* { font-family: 'Noto Sans', sans-serif; }
|
||||
* { font-family: 'Cardo', sans-serif; }
|
||||
#price {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
@ -9,9 +9,9 @@
|
||||
facebook-id="{{a.facebook_id.as_deref().unwrap_or_default()}}"
|
||||
>
|
||||
{% if h.is_above_user(account) -%}
|
||||
<a id="editService" slot="editService" href="/account/business-items" title="Moje usługi" class="btn">
|
||||
<button id="editService" slot="editService" title="Moje usługi" class="">
|
||||
Edytuj usługi
|
||||
</a>
|
||||
</button>
|
||||
{%- endif %}
|
||||
</account-view>
|
||||
{% when None %}
|
||||
|
@ -14,12 +14,12 @@
|
||||
<main>
|
||||
{% match error %}
|
||||
{% when Some with (e) %}
|
||||
<error-message message="{{e}"></error-message>
|
||||
<error-message message="{{e}}"></error-message>
|
||||
{% when None %}
|
||||
<error-message></error-message>
|
||||
{% endmatch %}
|
||||
<article>
|
||||
{% include "nav.html" %}
|
||||
<article>
|
||||
{% block content %}{% endblock %}
|
||||
</article>
|
||||
<privacy-policy-bar></privacy-policy-bar>
|
||||
|
23
server/assets/templates/marketplace/edit.html
Normal file
23
server/assets/templates/marketplace/edit.html
Normal file
@ -0,0 +1,23 @@
|
||||
{% extends "../base.html" %}
|
||||
{% block content %}
|
||||
<marketplace-offers>
|
||||
<h2>Edycja oferty</h2>
|
||||
<offer-form
|
||||
state="{{offer.state.as_str()}}"
|
||||
offer-id="{{offer.id}}"
|
||||
description="{{offer.description}}"
|
||||
picture-url="{{offer.picture_url}}"
|
||||
{% match offer.price_range %}
|
||||
{% when PriceRange::Free %}
|
||||
price-range-min="0"
|
||||
price-range-max="0"
|
||||
{% when PriceRange::Fixed with { value } %}
|
||||
price-range-min="{{value}}"
|
||||
price-range-max="0"
|
||||
{% when PriceRange::Range with { min, max } %}
|
||||
price-range-min="{{min}}"
|
||||
price-range-max="{{max}}"
|
||||
{% endmatch %}
|
||||
></offer-form>
|
||||
</marketplace-offers>
|
||||
{% endblock %}
|
@ -1,17 +1,17 @@
|
||||
{% extends "../base.html" %}
|
||||
{% block content %}
|
||||
|
||||
{% if account.is_some() %}
|
||||
<section>
|
||||
<a href="/account/offers" class="btn">Opublikuj</a>
|
||||
</section>
|
||||
{% endif %}
|
||||
|
||||
<marketplace-offers>
|
||||
<marketplace-offers
|
||||
{% match account %}
|
||||
{% when Some with (a) %}
|
||||
account-id="{{a.id}}"
|
||||
{% when None %}
|
||||
{% endmatch %}
|
||||
>
|
||||
<h2 style="text-align: center">Rzeczy wystawione na sprzedaż</h2>
|
||||
|
||||
{% for offer in my_offers %}
|
||||
<user-edit-offer
|
||||
slot="offer"
|
||||
state="{{offer.state.as_str()}}"
|
||||
offer-id="{{offer.id}}"
|
||||
description="{{offer.description}}"
|
||||
@ -60,6 +60,7 @@
|
||||
|
||||
{% for offer in offers %}
|
||||
<marketplace-offer
|
||||
slot="offer"
|
||||
offer-id="{{offer.id}}"
|
||||
description="{{offer.description}}"
|
||||
picture-url="{{offer.picture_url}}"
|
||||
|
@ -1,23 +1,16 @@
|
||||
<ow-nav>
|
||||
<ow-path path="/" id="home" title="OS Wilno">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 511 511" xml:space="preserve">
|
||||
<path d="M127.5 143h121.675a31.386 31.386 0 0 0-1.175 8.5 7.5 7.5 0 0 0 7.5 7.5h128a7.5 7.5 0 0 0 7.5-7.5c0-17.369-14.131-31.5-31.5-31.5-1.387 0-2.789.108-4.222.327C346.299 110.022 333.268 104 319.5 104s-26.799 6.022-35.778 16.327A27.875 27.875 0 0 0 279.5 120a31.314 31.314 0 0 0-17.439 5.284c-2.147-11.751-7.917-22.248-16.119-30.284H327.5a7.5 7.5 0 0 0 7.5-7.5c0-26.191-21.309-47.5-47.5-47.5-11.859 0-22.976 4.337-31.73 12.298A31.495 31.495 0 0 0 251.5 52c-16.921 0-31.106 11.904-34.643 27.775a56.764 56.764 0 0 0-10.588-1.006c-14.429 0-27.94 5.38-38.486 15.237a37.778 37.778 0 0 0-5.822-.468C138.824 93.539 120 112.362 120 135.5a7.5 7.5 0 0 0 7.5 7.5zm124-76c1.475 0 3.04.218 4.926.687a7.505 7.505 0 0 0 7.31-2.184C270.008 58.73 278.447 55 287.5 55c15.34 0 28.232 10.683 31.626 25H232.42c3-7.605 10.422-13 19.08-13zm28 68c1.482 0 3.046.276 4.923.868a7.502 7.502 0 0 0 8.413-2.87C298.933 124.233 308.901 119 319.5 119s20.567 5.233 26.665 13.998a7.5 7.5 0 0 0 8.413 2.87c1.877-.592 3.441-.868 4.923-.868 6.399 0 11.959 3.662 14.695 9h-109.39c2.735-5.338 8.295-9 14.694-9zm-117.539-26.461c1.96 0 4.019.285 6.479.896a7.498 7.498 0 0 0 7.311-2.183c8.051-8.694 18.889-13.482 30.518-13.482 20.45 0 37.512 14.788 41.056 34.231H136.061c3.257-11.23 13.635-19.462 25.9-19.462z"/>
|
||||
<path d="M510.905 262.363c.06-2.283.095-4.571.095-6.863 0-68.247-26.577-132.408-74.834-180.666C387.908 26.577 323.747 0 255.5 0S123.092 26.577 74.834 74.834C26.577 123.092 0 187.253 0 255.5s26.577 132.408 74.834 180.666C123.092 484.423 187.253 511 255.5 511s132.408-26.577 180.666-74.834c45.966-45.966 72.242-106.365 74.635-170.975a7.538 7.538 0 0 0 .198-1.691 7.486 7.486 0 0 0-.094-1.137zM85.441 85.441C130.865 40.016 191.26 15 255.5 15s124.635 25.016 170.059 70.441C470.984 130.865 496 191.26 496 255.5c0 .167-.006.333-.006.5H463v-8.5a7.5 7.5 0 0 0-15 0v8.5h-17v-25h.5a7.499 7.499 0 0 0 5.303-12.803l-32-32A7.497 7.497 0 0 0 399.5 184h-80c-1.989 0-3.897.79-5.303 2.197l-26.92 26.92-2.015-2.418A7.5 7.5 0 0 0 279.5 208H263v-32.5a7.5 7.5 0 0 0-15 0v.5h-17v-.5a7.5 7.5 0 0 0-15 0v.5h-65v-.5a7.5 7.5 0 0 0-15 0v.5h-17v-.5a7.5 7.5 0 0 0-15 0V224H17.046c6.8-52.302 30.482-100.646 68.395-138.559zM494.769 280H431v-9h64.494c-.19 3.01-.425 6.012-.725 9zm-15.521 64H431v-49h61.776a238.363 238.363 0 0 1-13.528 49zm-15.521 32.011c-.076-.002-.15-.011-.227-.011h-416c-.076 0-.151.009-.227.011A238.142 238.142 0 0 1 38.279 359h434.44a237.097 237.097 0 0 1-8.992 17.011zm-15.951 24.003c-.092-.003-.183-.014-.276-.014h-384c-.093 0-.184.01-.276.014A239.546 239.546 0 0 1 56.743 391h397.515a240.711 240.711 0 0 1-6.482 9.014zM15 255.5c0-5.532.199-11.032.567-16.5H104v17H15.5c-.167 0-.33.014-.494.025 0-.175-.006-.35-.006-.525zM143.5 199a7.5 7.5 0 0 0 7.5-7.5v-.5h65v.5a7.5 7.5 0 0 0 15 0v-.5h17v17H119v-17h17v.5a7.5 7.5 0 0 0 7.5 7.5zM416 231v113h-97v-73.027c.168.011.335.027.504.027a7.5 7.5 0 0 0 5.757-12.301L302.179 231H416zm-110.394-15 17-17h73.787l17 17H305.606zM207 344v-73h97v73h-97zm-88 0V223h96.487l-29.749 35.699a7.5 7.5 0 0 0 .96 10.563 7.464 7.464 0 0 0 5.301 1.715V344H119zm184.487-88h-95.975l27.5-33h40.975l27.5 33zM104 271v73H31.752c-9.135-23.111-14.646-47.678-16.247-73H104zm151.5 225c-64.24 0-124.635-25.016-170.059-70.441A244.667 244.667 0 0 1 75.51 415h359.98a245.917 245.917 0 0 1-9.931 10.559C380.135 470.984 319.74 496 255.5 496z"/>
|
||||
<path d="M143.5 240a7.5 7.5 0 0 0-7.5 7.5v16a7.5 7.5 0 0 0 15 0v-16a7.5 7.5 0 0 0-7.5-7.5zM167.5 240a7.5 7.5 0 0 0-7.5 7.5v16a7.5 7.5 0 0 0 15 0v-16a7.5 7.5 0 0 0-7.5-7.5zM143.5 288a7.5 7.5 0 0 0-7.5 7.5v24a7.5 7.5 0 0 0 15 0v-24a7.5 7.5 0 0 0-7.5-7.5zM167.5 288a7.5 7.5 0 0 0-7.5 7.5v24a7.5 7.5 0 0 0 15 0v-24a7.5 7.5 0 0 0-7.5-7.5zM55.5 327a7.5 7.5 0 0 0 7.5-7.5v-24a7.5 7.5 0 0 0-15 0v24a7.5 7.5 0 0 0 7.5 7.5zM39 319.5v-24a7.5 7.5 0 0 0-15 0v24a7.5 7.5 0 0 0 15 0zM79.5 327a7.5 7.5 0 0 0 7.5-7.5v-24a7.5 7.5 0 0 0-15 0v24a7.5 7.5 0 0 0 7.5 7.5zM231.5 288a7.5 7.5 0 0 0-7.5 7.5v24a7.5 7.5 0 0 0 15 0v-24a7.5 7.5 0 0 0-7.5-7.5zM255.5 288a7.5 7.5 0 0 0-7.5 7.5v24a7.5 7.5 0 0 0 15 0v-24a7.5 7.5 0 0 0-7.5-7.5zM279.5 288a7.5 7.5 0 0 0-7.5 7.5v24a7.5 7.5 0 0 0 15 0v-24a7.5 7.5 0 0 0-7.5-7.5zM343.5 327a7.5 7.5 0 0 0 7.5-7.5v-24a7.5 7.5 0 0 0-15 0v24a7.5 7.5 0 0 0 7.5 7.5zM367.5 327a7.5 7.5 0 0 0 7.5-7.5v-24a7.5 7.5 0 0 0-15 0v24a7.5 7.5 0 0 0 7.5 7.5zM391.5 327a7.5 7.5 0 0 0 7.5-7.5v-24a7.5 7.5 0 0 0-15 0v24a7.5 7.5 0 0 0 7.5 7.5zM447.5 304a7.5 7.5 0 0 0-7.5 7.5v8a7.5 7.5 0 0 0 15 0v-8a7.5 7.5 0 0 0-7.5-7.5zM471.5 304a7.5 7.5 0 0 0-7.5 7.5v8a7.5 7.5 0 0 0 15 0v-8a7.5 7.5 0 0 0-7.5-7.5zM343.5 271a7.5 7.5 0 0 0 7.5-7.5v-8a7.5 7.5 0 0 0-15 0v8a7.5 7.5 0 0 0 7.5 7.5zM367.5 271a7.5 7.5 0 0 0 7.5-7.5v-8a7.5 7.5 0 0 0-15 0v8a7.5 7.5 0 0 0 7.5 7.5zM391.5 271a7.5 7.5 0 0 0 7.5-7.5v-8a7.5 7.5 0 0 0-15 0v8a7.5 7.5 0 0 0 7.5 7.5z"/>
|
||||
</svg>
|
||||
<span>OS Wilno</span>
|
||||
</ow-path>
|
||||
|
||||
{# <ow-path path="/zero-waste" selected="{{ page.select_marketplace() }}" title="Za darmo">
|
||||
{#
|
||||
<ow-path path="/zero-waste" selected="{{ page.select_marketplace() }}" title="Za darmo">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" xml:space="preserve">
|
||||
<path d="M21.787 265.97c0-93.686 60.433-175.027 147.281-203.282l-24.251 32.157c-3.623 4.804-2.666 11.634 2.137 15.256a10.84 10.84 0 0 0 6.551 2.197c3.302 0 6.565-1.496 8.706-4.335l42.916-56.904a10.893 10.893 0 0 0-5.155-16.861l-67.399-23.176c-5.69-1.954-11.888 1.07-13.844 6.759-1.955 5.69 1.07 11.888 6.759 13.844l33.485 11.515c-39.951 13.768-75.875 38.241-103.475 70.935C19.71 156.465 0 210.409 0 265.97c0 27.261 4.631 54.007 13.765 79.493 1.595 4.45 5.786 7.221 10.255 7.221 1.22 0 2.461-.207 3.674-.642 5.664-2.029 8.609-8.266 6.58-13.93-8.285-23.121-12.487-47.393-12.487-72.142zM414.025 402.991c-4.588-3.893-11.461-3.332-15.356 1.255-40.749 48.005-100.185 75.538-163.068 75.538-53.27 0-104.061-19.763-143.119-54.987l40.061 4.936c5.965.74 11.408-3.508 12.143-9.48.735-5.971-3.509-11.408-9.48-12.143l-70.739-8.715a10.896 10.896 0 0 0-12.025 12.895l13.628 69.958c1.013 5.202 5.572 8.813 10.681 8.813.691 0 1.391-.066 2.095-.204 5.905-1.15 9.76-6.871 8.609-12.776l-6.743-34.615c42.647 37.25 97.454 58.105 154.886 58.105 69.292 0 134.783-30.334 179.679-83.226 3.898-4.587 3.334-11.462-1.252-15.354zM509.325 288.789c-3.949-4.538-10.829-5.017-15.369-1.069l-27.12 23.593a236.333 236.333 0 0 0 4.366-45.343c0-55.56-19.71-109.503-55.497-151.896-35.361-41.885-84.382-70.28-138.033-79.955-5.917-1.072-11.586 2.866-12.653 8.788-1.068 5.921 2.866 11.586 8.787 12.654C375.561 73.91 449.415 162.4 449.415 265.969c0 14.664-1.487 29.157-4.413 43.346l-15.46-36.465c-2.349-5.539-8.745-8.124-14.281-5.777-5.539 2.349-8.126 8.742-5.778 14.281l27.821 65.619a10.89 10.89 0 0 0 17.179 3.966l53.772-46.781c4.54-3.95 5.018-10.83 1.07-15.369z"/>
|
||||
<path d="M188.028 130.89a50.918 50.918 0 0 0-4.574-.207c-21.752 0-40.793 14.02-47.564 34.164-17.981 7.019-30.042 24.311-30.042 44.123a47.444 47.444 0 0 0 11.151 30.53 67.61 67.61 0 0 0-1.206 12.72c0 36.454 29.03 66.112 64.714 66.112 6.157 0 12.253-.886 18.119-2.63.11-.033.222-.059.333-.092a529.09 529.09 0 0 1-.877 107.238 10.891 10.891 0 0 0 10.829 12.088h53.379a10.896 10.896 0 0 0 10.828-12.088 529.532 529.532 0 0 1-1.495-100.106c17.407-.964 33.696-8.121 46.232-20.417 11.715-11.489 19.022-26.339 21-42.412 15.913-7.877 26.498-24.415 26.498-42.538 0-23.342-16.958-42.798-39.2-46.695-7.81-27.348-31.586-46.41-59.334-46.41a57.88 57.88 0 0 0-4.029.141c-9.275-8.797-21.549-13.741-34.507-13.741-16.076.004-30.876 7.585-40.255 20.22zm32.91 282.263a550.944 550.944 0 0 0-.314-99.862 68.285 68.285 0 0 1 20.675 4.615 71.561 71.561 0 0 0 8.631 2.762 551.612 551.612 0 0 0 .333 92.485h-29.325zm-17.889-265.307c4.906-9.489 14.577-15.385 25.237-15.385 8.511 0 16.501 3.771 21.924 10.348a10.89 10.89 0 0 0 10.256 3.805 37.464 37.464 0 0 1 6.354-.551c19.726 0 36.41 15.343 39.668 36.483.83 5.388 5.53 9.307 10.966 9.232l.493-.016c14.127 0 25.62 11.493 25.62 25.62 0 11.212-7.49 21.298-18.217 24.529a10.896 10.896 0 0 0-7.749 10.2c-.573 27.004-23.015 48.973-50.026 48.973-6.323 0-12.48-1.161-18.3-3.45-10.586-4.165-21.761-6.264-32.818-6.264-8.172 0-16.283 1.147-24.042 3.455a41.728 41.728 0 0 1-11.907 1.726c-23.671 0-42.927-19.884-42.927-44.325 0-4.38.624-8.722 1.855-12.905a10.895 10.895 0 0 0-3.206-11.212 25.651 25.651 0 0 1-8.595-19.135c0-11.949 8.114-22.2 19.73-24.93a10.893 10.893 0 0 0 8.207-8.556c2.555-13.336 14.279-23.015 27.881-23.015 2.429 0 4.843.307 7.174.914a10.9 10.9 0 0 0 12.422-5.541z"/>
|
||||
<path d="M264.285 208.492c9.069 6.257 14.271 15.333 14.271 24.897 0 6.017 4.878 10.894 10.894 10.894 6.015 0 10.894-4.877 10.894-10.894 0-16.834-8.632-32.445-23.683-42.83-4.953-3.416-11.736-2.171-15.153 2.78-3.419 4.951-2.174 11.736 2.777 15.153zM234.981 191.995l.338.001h.085c5.977 0 10.846-4.823 10.891-10.811.046-6.017-4.794-10.931-10.81-10.976l-.503-.002c-6.017 0-10.894 4.877-10.894 10.894.001 6.016 4.877 10.894 10.893 10.894z"/>
|
||||
</svg>
|
||||
</ow-path> #}
|
||||
</ow-path>
|
||||
#}
|
||||
|
||||
{% if page.is_public() -%}
|
||||
<ow-path path="/marketplace" selected="{{ page.select_marketplace() }}" title="Targ">
|
||||
<ow-path path="/marketplace" selected="{{ page.select_marketplace() }}" title="Targ" slot="left">
|
||||
<svg viewBox="0 0 484.909 484.909" xml:space="preserve" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M204.993 438.478c-6.347 6.349-6.347 16.639 0 22.978a16.196 16.196 0 0 0 11.488 4.761c4.158 0 8.316-1.587 11.489-4.761l49.747-49.754-22.979-22.978zm112.649-112.671-16.947 16.954 22.976 22.977 39.926-39.931zm-56.872 0h-45.954l135.627 135.648a16.193 16.193 0 0 0 11.487 4.761c4.158 0 8.315-1.587 11.488-4.761 6.349-6.339 6.349-16.629 0-22.978zM102.294 107.658c21.471 0 38.878-19.915 38.878-44.478 0-24.564-17.407-44.487-38.878-44.487-21.486 0-38.877 19.923-38.877 44.487 0 24.563 17.391 44.478 38.877 44.478zm-15.17 48.128c-58.083-103.857-29.041-51.929 0 0z"/>
|
||||
<path d="M74.524 123.66c-7.062.128-11.934.302-12.44.539-5.554 1.365-19.132 13.9-21.512 19.605L1.42 250.377c-3.937 9.521.586 20.439 10.107 24.382a18.79 18.79 0 0 0 7.14 1.42c7.315 0 14.266-4.34 17.249-11.537l1.635-3.966c18.146-117.982 15.439 106.05 15.472 183.143 0 12.369 10.028 22.398 22.389 22.398 12.361 0 22.39-10.029 22.39-22.398V331.622h8.982v112.196c0 12.369 10.029 22.398 22.39 22.398s22.39-10.029 22.39-22.398c-.011-79.908-26.343-323.038 35.094-186.958 1.38 3.056 4.269 8.803 5.911 10.186.265.222 3.555 4.423 10.718 5.197.816.088 6.57-1.904 8.384-3.461 2.978-2.56 7.84-16.93 1.731-31.307-6.108-14.377-35.47-78.46-42.953-95.453-7.483-16.992-22.598-16.71-25.832-17.128-5.814-.751-11.658-.702-12.642-.736-13.92-.48-18.043.394-57.452-.498z"/>
|
||||
@ -26,14 +19,14 @@
|
||||
</svg>
|
||||
<div>Targ</div>
|
||||
</ow-path>
|
||||
<ow-path path="/" selected="{{ page.select_index() }}" title="Lokalne usługi">
|
||||
<ow-path path="/local-businesses" selected="{{ page.select_index() }}" title="Lokalne usługi" slot="left">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 511.999 511.999" xml:space="preserve">
|
||||
<path d="M440.482 50.916c-8.099-4.226-18.091-1.088-22.321 7.013l-41.925 80.336-46.147 36.662h-54.683l-57.033-18.756-33.145-53.595 5.854-5.694c3.554-3.457 3.634-9.143.176-12.697l-13.735-14.12 10.294-10.014c4.024-3.914 4.113-10.35.198-14.374l-41.438-42.6c-3.914-4.024-10.35-4.113-14.374-.198l-66.5 64.687c-4.024 3.914-4.113 10.35-.198 14.374l41.438 42.599c3.914 4.024 10.35 4.113 14.374.198l10.294-10.013 13.737 14.121c3.449 3.547 9.136 3.64 12.696.176l2.896-2.817 32.466 52.499a16.544 16.544 0 0 0 8.901 7.014l58.436 19.218.008 287.213c0 10.964 8.888 19.853 19.852 19.853s19.852-8.888 19.852-19.853V333.466l8.565-2.239 24.462 64.136-17.398 78.459c-2.373 10.704 4.38 21.306 15.084 23.679 10.69 2.373 21.303-4.371 23.679-15.083l18.771-84.647a19.858 19.858 0 0 0-1.096-12.026l-24.153-57.154V202.66l51.197-40.674a16.547 16.547 0 0 0 4.375-5.299l43.551-83.45c4.23-8.1 1.089-18.094-7.01-22.321zM171.921 90.467a16.48 16.48 0 0 0-12.357 2.058c-6.031 3.73-8.81 10.704-7.514 17.272l-.092.088-7.475-7.683 20.167-19.617 7.475 7.684-.204.198z"/>
|
||||
<circle cx="304.734" cy="129.707" r="34.286"/>
|
||||
</svg>
|
||||
<div>Lokalne Usługi</div>
|
||||
</ow-path>
|
||||
<ow-path path="/news" selected="{{ page.select_news() }}" title="Aktualności">
|
||||
<ow-path path="/news" selected="{{ page.select_news() }}" title="Aktualności" slot="left">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 508 508" xml:space="preserve">
|
||||
<path d="M437.4 197.6H307.6c-7.8 0-14.2 6.3-14.2 14.1v141.1c0 7.8 6.3 14.1 14.1 14.1h129.9c7.8 0 14.1-6.3 14.1-14.1V211.7c0-7.8-6.3-14.1-14.1-14.1zm-14 141.1H321.7V225.8h101.7v112.9zM360.7 409.3H70.6c-7.8 0-14.1 6.3-14.1 14.1-.1 7.7 6.3 14.1 14.1 14.1h290.1c7.8 0 14.1-6.3 14.1-14.1s-6.3-14.1-14.1-14.1zM251.2 338.7H70.6c-7.8 0-14.1 6.3-14.1 14.1-.1 7.8 6.3 14.1 14.1 14.1h180.6c7.8 0 14.1-6.3 14.1-14.1s-6.3-14.1-14.1-14.1zM251.2 268.1H70.6c-7.8 0-14.1 6.3-14.1 14.1-.1 7.8 6.3 14.1 14.1 14.1h180.6c7.8 0 14.1-6.3 14.1-14.1s-6.3-14.1-14.1-14.1zM251.2 197.6H70.6c-7.8 0-14.1 6.3-14.1 14.1-.1 7.8 6.3 14.1 14.1 14.1h180.6c7.8 0 14.1-6.3 14.1-14.1s-6.3-14.1-14.1-14.1z"/>
|
||||
<path d="M493.9 0H14.1C6.3 0 0 6.3 0 14.1v479.8c0 7.8 6.3 14.1 14.1 14.1h403c3.7 0 7.3-1.5 10-4.1l76.8-76.8c2.6-2.6 4.1-6.2 4.1-10v-403C508 6.3 501.7 0 493.9 0zm-62.7 459.8v-28.6h28.6l-28.6 28.6zm48.6-56.8h-62.7c-7.8 0-14.1 6.3-14.1 14.1v62.7H28.2V28.2h451.6V403z"/>
|
||||
@ -41,7 +34,7 @@
|
||||
</svg>
|
||||
<div>Aktualności</div>
|
||||
</ow-path>
|
||||
<ow-path path="/account" selected="{{ page.select_account() }}" title="Konto">
|
||||
<ow-path path="/account" selected="{{ page.select_account() }}" title="Konto" slot="right">
|
||||
<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="currentColor">
|
||||
<path d="M16 7.992C16 3.58 12.416 0 8 0S0 3.58 0 7.992c0 2.43 1.104 4.62 2.832 6.09.016.016.032.016.032.032.144.112.288.224.448.336.08.048.144.111.224.175A7.98 7.98 0 0 0 8.016 16a7.98 7.98 0 0 0 4.48-1.375c.08-.048.144-.111.224-.16.144-.111.304-.223.448-.335.016-.016.032-.016.032-.032 1.696-1.487 2.8-3.676 2.8-6.106zm-8 7.001c-1.504 0-2.88-.48-4.016-1.279.016-.128.048-.255.08-.383a4.17 4.17 0 0 1 .416-.991c.176-.304.384-.576.64-.816.24-.24.528-.463.816-.639.304-.176.624-.304.976-.4A4.15 4.15 0 0 1 8 10.342a4.185 4.185 0 0 1 2.928 1.166c.368.368.656.8.864 1.295.112.288.192.592.24.911A7.03 7.03 0 0 1 8 14.993zm-2.448-7.4a2.49 2.49 0 0 1-.208-1.024c0-.351.064-.703.208-1.023.144-.32.336-.607.576-.847.24-.24.528-.431.848-.575.32-.144.672-.208 1.024-.208.368 0 .704.064 1.024.208.32.144.608.336.848.575.24.24.432.528.576.847.144.32.208.672.208 1.023 0 .368-.064.704-.208 1.023a2.84 2.84 0 0 1-.576.848 2.84 2.84 0 0 1-.848.575 2.715 2.715 0 0 1-2.064 0 2.84 2.84 0 0 1-.848-.575 2.526 2.526 0 0 1-.56-.848zm7.424 5.306c0-.032-.016-.048-.016-.08a5.22 5.22 0 0 0-.688-1.406 4.883 4.883 0 0 0-1.088-1.135 5.207 5.207 0 0 0-1.04-.608 2.82 2.82 0 0 0 .464-.383 4.2 4.2 0 0 0 .624-.784 3.624 3.624 0 0 0 .528-1.934 3.71 3.71 0 0 0-.288-1.47 3.799 3.799 0 0 0-.816-1.199 3.845 3.845 0 0 0-1.2-.8 3.72 3.72 0 0 0-1.472-.287 3.72 3.72 0 0 0-1.472.288 3.631 3.631 0 0 0-1.2.815 3.84 3.84 0 0 0-.8 1.199 3.71 3.71 0 0 0-.288 1.47c0 .352.048.688.144 1.007.096.336.224.64.4.927.16.288.384.544.624.784.144.144.304.271.48.383a5.12 5.12 0 0 0-1.04.624c-.416.32-.784.703-1.088 1.119a4.999 4.999 0 0 0-.688 1.406c-.016.032-.016.064-.016.08C1.776 11.636.992 9.91.992 7.992.992 4.14 4.144.991 8 .991s7.008 3.149 7.008 7.001a6.96 6.96 0 0 1-2.032 4.907z"/>
|
||||
</svg>
|
||||
@ -49,7 +42,7 @@
|
||||
</ow-path>
|
||||
|
||||
{% if h.is_admin(account) -%}
|
||||
<ow-path path="/admin" selected="{{ page.select_admin_news() }}" title="Admin">
|
||||
<ow-path path="/admin" selected="{{ page.select_admin_news() }}" title="Admin" slot="right">
|
||||
<svg viewBox="0 0 36 36" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M14.68 14.81a6.76 6.76 0 1 1 6.76-6.75 6.77 6.77 0 0 1-6.76 6.75Zm0-11.51a4.76 4.76 0 1 0 4.76 4.76 4.76 4.76 0 0 0-4.76-4.76Z"/>
|
||||
<path d="M16.42 31.68A2.14 2.14 0 0 1 15.8 30H4v-5.78a14.81 14.81 0 0 1 11.09-4.68h.72a2.2 2.2 0 0 1 .62-1.85l.12-.11c-.47 0-1-.06-1.46-.06A16.47 16.47 0 0 0 2.2 23.26a1 1 0 0 0-.2.6V30a2 2 0 0 0 2 2h12.7Z"/>
|
||||
@ -62,7 +55,7 @@
|
||||
{%- endif %}
|
||||
|
||||
{% else if page.is_admin() -%}
|
||||
<ow-path path="/admin/news" selected="{{ page.select_admin_news() }}" title="Zarządzaj aktualnościami">
|
||||
<ow-path path="/admin/news" selected="{{ page.select_admin_news() }}" title="Zarządzaj aktualnościami" slot="left">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 508 508" xml:space="preserve">
|
||||
<path d="M437.4 197.6H307.6c-7.8 0-14.2 6.3-14.2 14.1v141.1c0 7.8 6.3 14.1 14.1 14.1h129.9c7.8 0 14.1-6.3 14.1-14.1V211.7c0-7.8-6.3-14.1-14.1-14.1zm-14 141.1H321.7V225.8h101.7v112.9zM360.7 409.3H70.6c-7.8 0-14.1 6.3-14.1 14.1-.1 7.7 6.3 14.1 14.1 14.1h290.1c7.8 0 14.1-6.3 14.1-14.1s-6.3-14.1-14.1-14.1zM251.2 338.7H70.6c-7.8 0-14.1 6.3-14.1 14.1-.1 7.8 6.3 14.1 14.1 14.1h180.6c7.8 0 14.1-6.3 14.1-14.1s-6.3-14.1-14.1-14.1zM251.2 268.1H70.6c-7.8 0-14.1 6.3-14.1 14.1-.1 7.8 6.3 14.1 14.1 14.1h180.6c7.8 0 14.1-6.3 14.1-14.1s-6.3-14.1-14.1-14.1zM251.2 197.6H70.6c-7.8 0-14.1 6.3-14.1 14.1-.1 7.8 6.3 14.1 14.1 14.1h180.6c7.8 0 14.1-6.3 14.1-14.1s-6.3-14.1-14.1-14.1z"/>
|
||||
<path d="M493.9 0H14.1C6.3 0 0 6.3 0 14.1v479.8c0 7.8 6.3 14.1 14.1 14.1h403c3.7 0 7.3-1.5 10-4.1l76.8-76.8c2.6-2.6 4.1-6.2 4.1-10v-403C508 6.3 501.7 0 493.9 0zm-62.7 459.8v-28.6h28.6l-28.6 28.6zm48.6-56.8h-62.7c-7.8 0-14.1 6.3-14.1 14.1v62.7H28.2V28.2h451.6V403z"/>
|
||||
@ -71,8 +64,11 @@
|
||||
<div>Aktualności</div>
|
||||
</ow-path>
|
||||
|
||||
<ow-path path="/admin/businesses" selected="{{ page.select_admin_businesses() }}"
|
||||
title="Zarządzaj usługami">
|
||||
<ow-path
|
||||
path="/admin/businesses" selected="{{ page.select_admin_businesses() }}"
|
||||
title="Zarządzaj usługami"
|
||||
slot="left"
|
||||
>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 511.999 511.999" xml:space="preserve">
|
||||
<path d="M440.482 50.916c-8.099-4.226-18.091-1.088-22.321 7.013l-41.925 80.336-46.147 36.662h-54.683l-57.033-18.756-33.145-53.595 5.854-5.694c3.554-3.457 3.634-9.143.176-12.697l-13.735-14.12 10.294-10.014c4.024-3.914 4.113-10.35.198-14.374l-41.438-42.6c-3.914-4.024-10.35-4.113-14.374-.198l-66.5 64.687c-4.024 3.914-4.113 10.35-.198 14.374l41.438 42.599c3.914 4.024 10.35 4.113 14.374.198l10.294-10.013 13.737 14.121c3.449 3.547 9.136 3.64 12.696.176l2.896-2.817 32.466 52.499a16.544 16.544 0 0 0 8.901 7.014l58.436 19.218.008 287.213c0 10.964 8.888 19.853 19.852 19.853s19.852-8.888 19.852-19.853V333.466l8.565-2.239 24.462 64.136-17.398 78.459c-2.373 10.704 4.38 21.306 15.084 23.679 10.69 2.373 21.303-4.371 23.679-15.083l18.771-84.647a19.858 19.858 0 0 0-1.096-12.026l-24.153-57.154V202.66l51.197-40.674a16.547 16.547 0 0 0 4.375-5.299l43.551-83.45c4.23-8.1 1.089-18.094-7.01-22.321zM171.921 90.467a16.48 16.48 0 0 0-12.357 2.058c-6.031 3.73-8.81 10.704-7.514 17.272l-.092.088-7.475-7.683 20.167-19.617 7.475 7.684-.204.198z"/>
|
||||
<circle cx="304.734" cy="129.707" r="34.286"/>
|
||||
@ -80,8 +76,11 @@
|
||||
<div>Lokalne Usługi</div>
|
||||
</ow-path>
|
||||
|
||||
<ow-path path="/admin/offers" selected="{{ page.select_admin_offers() }}"
|
||||
title="Zarządzaj ofertami">
|
||||
<ow-path
|
||||
path="/admin/offers" selected="{{ page.select_admin_offers() }}"
|
||||
title="Zarządzaj ofertami"
|
||||
slot="left"
|
||||
>
|
||||
<svg viewBox="0 0 32 32" xml:space="preserve" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M30.412 19.045a.34.34 0 0 0-.34.341V30.83c0 .12-.102.222-.222.222h-2.627v-3.14h.87a.402.402 0 0 0 .372-.22.402.402 0 0 0-.054-.43l-1.818-2.346a.436.436 0 0 0-.346-.173h-.003a.437.437 0 0 0-.347.179l-1.758 2.343a.403.403 0 0 0-.049.429.403.403 0 0 0 .372.218h.806v3.14h-8.941a.594.594 0 0 1-.594-.594V19.716c0-.327.266-.594.594-.594H27.7a.34.34 0 1 0 0-.681H16.327c-.703 0-1.275.572-1.275 1.275v10.742c0 .703.572 1.275 1.275 1.275h9.282a.34.34 0 0 0 .34-.34V27.57a.34.34 0 0 0-.34-.34h-.592l1.233-1.645 1.274 1.645h-.642a.34.34 0 0 0-.34.34v3.821a.34.34 0 0 0 .34.34h2.968a.905.905 0 0 0 .903-.903V19.386a.34.34 0 0 0-.34-.34z"
|
||||
|
@ -182,11 +182,17 @@ pub struct UpdateLocalBusinessInput {
|
||||
pub description: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
|
||||
#[derive(Debug, Default, Copy, Clone, Serialize, Deserialize)]
|
||||
pub enum PriceRange {
|
||||
#[default]
|
||||
Free,
|
||||
Fixed { value: i32 },
|
||||
Range { min: i32, max: i32 },
|
||||
Fixed {
|
||||
value: i32,
|
||||
},
|
||||
Range {
|
||||
min: i32,
|
||||
max: i32,
|
||||
},
|
||||
}
|
||||
|
||||
impl From<(i32, i32)> for PriceRange {
|
||||
@ -286,7 +292,7 @@ pub struct CreateLocalBusinessItemInput {
|
||||
pub name: String,
|
||||
pub price: i64,
|
||||
pub item_order: i32,
|
||||
pub picture_url: String,
|
||||
pub picture_url: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -97,7 +97,7 @@ impl Page {
|
||||
pub struct BusinessItemInput {
|
||||
pub name: String,
|
||||
pub price: u32,
|
||||
pub picture_url: String,
|
||||
pub picture_url: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
@ -250,6 +250,21 @@ pub struct Offer {
|
||||
pub contacts: Vec<Arc<db::ContactInfo>>,
|
||||
}
|
||||
|
||||
impl Default for Offer {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
id: 0,
|
||||
owner_id: 0,
|
||||
price_range: Default::default(),
|
||||
description: "".to_string(),
|
||||
picture_url: "".to_string(),
|
||||
state: Default::default(),
|
||||
created_at: chrono::Utc::now().naive_utc(),
|
||||
contacts: vec![],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<(db::Offer, &Vec<Arc<db::ContactInfo>>)> for Offer {
|
||||
fn from((offer, contacts): (db::Offer, &Vec<Arc<db::ContactInfo>>)) -> Self {
|
||||
let db::Offer {
|
||||
|
@ -77,3 +77,14 @@ RETURNING id, login, email, pass, facebook_id, account_type
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/* async fn delete_all_accounts() {
|
||||
let _ = sqlx::query_as::<sqlx::Postgres, (i32,)>(
|
||||
r#"
|
||||
delete from contacts;
|
||||
delete from local_business_items;
|
||||
delete from local_businesses;
|
||||
delete from accounts;
|
||||
"#,
|
||||
);
|
||||
}*/
|
||||
|
@ -300,11 +300,13 @@ RETURNING
|
||||
.bind(input.local_business_id)
|
||||
.bind(&input.name)
|
||||
.bind(input.price)
|
||||
.bind(if input.picture_url.is_empty() {
|
||||
format!("--{}", uuid::Uuid::new_v4())
|
||||
} else {
|
||||
input.picture_url.clone()
|
||||
})
|
||||
.bind(
|
||||
input
|
||||
.picture_url
|
||||
.as_deref()
|
||||
.map(String::from)
|
||||
.unwrap_or_else(|| format!("--{}", uuid::Uuid::new_v4())),
|
||||
)
|
||||
.bind(input.item_order)
|
||||
.fetch_one(t)
|
||||
.await
|
||||
|
@ -104,6 +104,9 @@ pub enum Error {
|
||||
offer_id: i32,
|
||||
state: db::OfferState,
|
||||
},
|
||||
Offer {
|
||||
offer_id: i32,
|
||||
},
|
||||
}
|
||||
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
|
@ -56,6 +56,34 @@ ORDER BY id DESC
|
||||
})
|
||||
}
|
||||
|
||||
#[tracing::instrument]
|
||||
pub async fn offer_by_id(t: &mut T<'_>, account_id: i32, offer_id: i32) -> Result<db::Offer> {
|
||||
sqlx::query_as(
|
||||
r#"
|
||||
SELECT
|
||||
id,
|
||||
owner_id,
|
||||
price_range,
|
||||
description,
|
||||
picture_url,
|
||||
state,
|
||||
created_at
|
||||
FROM offers
|
||||
WHERE owner_id = $1 AND id = $2
|
||||
LIMIT 1
|
||||
"#,
|
||||
)
|
||||
.bind(account_id)
|
||||
.bind(offer_id)
|
||||
.fetch_one(t)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
error!("{e}");
|
||||
dbg!(e);
|
||||
Error::Offer { offer_id }
|
||||
})
|
||||
}
|
||||
|
||||
#[tracing::instrument]
|
||||
pub async fn account_offers(t: &mut T<'_>, account_id: i32) -> Result<Vec<db::Offer>> {
|
||||
sqlx::query_as(
|
||||
|
@ -159,7 +159,7 @@ async fn new_business_item(
|
||||
name: form.name,
|
||||
price: form.price,
|
||||
item_order: form.item_order,
|
||||
picture_url: form.picture_url,
|
||||
picture_url: Some(form.picture_url),
|
||||
},
|
||||
)
|
||||
.await
|
||||
|
@ -12,6 +12,7 @@ use serde::Serialize;
|
||||
|
||||
use crate::model::db;
|
||||
use crate::model::view::{self, Page};
|
||||
use crate::routes::HttpResult;
|
||||
use crate::view::Helper;
|
||||
|
||||
#[derive(Default, Debug, Serialize, Template)]
|
||||
@ -36,6 +37,11 @@ pub async fn render_index() -> HttpResponse {
|
||||
)
|
||||
}
|
||||
|
||||
#[get("/")]
|
||||
async fn index(req: HttpRequest) -> HttpResult {
|
||||
HttpResult::goto(&req, "/marketplace")
|
||||
}
|
||||
|
||||
pub fn configure(config: &mut ServiceConfig) {
|
||||
std::fs::create_dir_all("./uploads").expect("Failed to create ./uploads directory");
|
||||
|
||||
@ -43,15 +49,18 @@ pub fn configure(config: &mut ServiceConfig) {
|
||||
account::configure(config);
|
||||
news::configure(config);
|
||||
marketplace::configure(config);
|
||||
businesses::configure(config);
|
||||
|
||||
config
|
||||
.service(Files::new("/uploads", "./uploads"))
|
||||
.service(Files::new("/assets/images", "./assets/images"))
|
||||
.service(Files::new("/assets/fonts", "./assets/fonts"))
|
||||
.service(Files::new("/assets/css", "./client/dist"))
|
||||
.service(
|
||||
Files::new("/assets/js", "./client/dist")
|
||||
.use_etag(true)
|
||||
.prefer_utf8(true)
|
||||
.show_files_listing(),
|
||||
);
|
||||
businesses::configure(config);
|
||||
)
|
||||
.service(index);
|
||||
}
|
||||
|
@ -1,5 +1,3 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use actix_http::StatusCode;
|
||||
use actix_web::web::{Data, Path, ServiceConfig};
|
||||
use actix_web::{get, post, web, HttpRequest, HttpResponse};
|
||||
@ -237,6 +235,20 @@ impl RegisterPage {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
struct RegisterForm {
|
||||
email: String,
|
||||
login: String,
|
||||
password: String,
|
||||
facebook_id: Option<String>,
|
||||
account_type: AccountType,
|
||||
items: Option<Vec<view::BusinessItemInput>>,
|
||||
contacts: Option<Vec<view::CreateContactInfoInput>>,
|
||||
name: Option<String>,
|
||||
description: Option<String>,
|
||||
}
|
||||
|
||||
#[post("/register")]
|
||||
#[tracing::instrument]
|
||||
async fn save_account_details(
|
||||
@ -245,12 +257,11 @@ async fn save_account_details(
|
||||
db: Data<PgPool>,
|
||||
id: Identity,
|
||||
) -> HttpResult {
|
||||
let mut form = form.into_inner();
|
||||
let form = form.into_inner();
|
||||
dbg!(&form);
|
||||
process_items(form.items.get_or_insert_default(), form.names);
|
||||
|
||||
let pool = db.into_inner();
|
||||
if form.account_type == db::AccountType::Admin {
|
||||
if form.account_type == AccountType::Admin {
|
||||
return HttpResult::err(&req, routes::Error::XSS);
|
||||
}
|
||||
|
||||
@ -300,6 +311,48 @@ async fn save_account_details(
|
||||
}
|
||||
};
|
||||
|
||||
if let Err(e) = queries::create_contact(
|
||||
&mut t,
|
||||
db::CreateContactInput {
|
||||
owner_id: account.id,
|
||||
contact_type: "email".into(),
|
||||
content: account.email.clone(),
|
||||
},
|
||||
)
|
||||
.await
|
||||
{
|
||||
dbg!(e);
|
||||
t.rollback().await.unwrap();
|
||||
return RegisterTemplate::bad_request(
|
||||
&req,
|
||||
"Problem z utworzeniem danych kontaktowych konta",
|
||||
Page::Register,
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(contacts) = form.contacts {
|
||||
for contact in contacts {
|
||||
if let Err(e) = queries::create_contact(
|
||||
&mut t,
|
||||
db::CreateContactInput {
|
||||
owner_id: account.id,
|
||||
contact_type: contact.contact_type,
|
||||
content: contact.content,
|
||||
},
|
||||
)
|
||||
.await
|
||||
{
|
||||
dbg!(e);
|
||||
t.rollback().await.unwrap();
|
||||
return RegisterTemplate::bad_request(
|
||||
&req,
|
||||
"Problem z utworzeniem danych kontaktowych konta",
|
||||
Page::Register,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if matches!(form.account_type, db::AccountType::Business) {
|
||||
let name = form.name.as_deref().unwrap_or_default();
|
||||
let owner_id = account.id;
|
||||
@ -325,23 +378,13 @@ async fn save_account_details(
|
||||
|
||||
for (idx, item) in form.items.unwrap_or_default().into_iter().enumerate() {
|
||||
not_xss!(&req, &item.name, t);
|
||||
not_xss!(&req, &item.picture_url, t);
|
||||
not_xss!(&req, item.picture_url.as_deref().unwrap_or_default(), t);
|
||||
|
||||
let res: sqlx::Result<db::LocalBusinessItem> = sqlx::query_as(
|
||||
r#"
|
||||
INSERT INTO local_business_items (local_business_id, name, price, item_order, picture_url)
|
||||
VALUES ($1, $2, $3, $4, $5)
|
||||
RETURNING id, local_business_id, name, price, item_order, picture_url
|
||||
"#,
|
||||
)
|
||||
.bind(business.id)
|
||||
.bind(&item.name)
|
||||
.bind(item.price as i32)
|
||||
.bind(idx as i32)
|
||||
.bind(if item.picture_url.is_empty() {
|
||||
let picture_url = match item.picture_url {
|
||||
Some(url) => Some(if url.is_empty() {
|
||||
format!("--{}", uuid::Uuid::new_v4())
|
||||
} else {
|
||||
let name = item.picture_url.split('/').last().unwrap_or_default();
|
||||
let name = url.split('/').last().unwrap_or_default();
|
||||
let dir = utils::item_picture_write_dir(format!("{}", account.id));
|
||||
if let Err(e) = std::fs::create_dir_all(&dir) {
|
||||
error!("{e} {:?}", dir);
|
||||
@ -354,8 +397,8 @@ RETURNING id, local_business_id, name, price, item_order, picture_url
|
||||
);
|
||||
}
|
||||
let path = dir.join(name);
|
||||
if let Err(e) = std::fs::rename(format!(".{}", item.picture_url), &path) {
|
||||
error!("{e} {:?}", item.picture_url);
|
||||
if let Err(e) = std::fs::rename(format!(".{}", url), &path) {
|
||||
error!("{e} {:?}", url);
|
||||
dbg!(e);
|
||||
t.rollback().await.unwrap();
|
||||
return RegisterTemplate::bad_request(
|
||||
@ -368,13 +411,24 @@ RETURNING id, local_business_id, name, price, item_order, picture_url
|
||||
path.strip_prefix('.')
|
||||
.map(String::from)
|
||||
.unwrap_or_else(|| path)
|
||||
})
|
||||
.fetch_one(&mut t)
|
||||
}),
|
||||
None => None,
|
||||
};
|
||||
let res = queries::create_item(
|
||||
&mut t,
|
||||
db::CreateLocalBusinessItemInput {
|
||||
local_business_id: business.id,
|
||||
name: item.name,
|
||||
price: item.price as i64,
|
||||
item_order: idx as i32,
|
||||
picture_url,
|
||||
},
|
||||
)
|
||||
.await;
|
||||
match res {
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
error!("{e}");
|
||||
error!("{e:?}");
|
||||
dbg!(e);
|
||||
t.rollback().await.unwrap();
|
||||
return RegisterTemplate::bad_request(
|
||||
@ -427,68 +481,6 @@ async fn display_register_page(
|
||||
)
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
struct RegisterForm {
|
||||
email: String,
|
||||
login: String,
|
||||
password: String,
|
||||
facebook_id: Option<String>,
|
||||
account_type: db::AccountType,
|
||||
items: Option<Vec<view::BusinessItemInput>>,
|
||||
contacts: Option<Vec<view::CreateContactInfoInput>>,
|
||||
name: Option<String>,
|
||||
description: Option<String>,
|
||||
#[serde(flatten)]
|
||||
names: HashMap<String, String>,
|
||||
}
|
||||
|
||||
#[tracing::instrument]
|
||||
fn process_items(items: &mut Vec<view::BusinessItemInput>, names: HashMap<String, String>) {
|
||||
let mut h = names
|
||||
.into_iter()
|
||||
.filter_map(|(name, value)| {
|
||||
let mut name = name
|
||||
.strip_prefix("items")?
|
||||
.split('[')
|
||||
.filter(|s| !s.is_empty())
|
||||
.map(|s| s.strip_suffix(']').unwrap_or(s));
|
||||
let idx: u16 = name.next().and_then(|s| s.parse().ok())?;
|
||||
match name.next() {
|
||||
Some(s @ ("name" | "price" | "picture_url")) => Some((idx, s.to_string(), value)),
|
||||
_ => None,
|
||||
}
|
||||
})
|
||||
.fold(
|
||||
HashMap::with_capacity(60),
|
||||
|mut memo, (idx, field, value)| {
|
||||
let item = memo
|
||||
.entry(idx)
|
||||
.or_insert_with(view::BusinessItemInput::default);
|
||||
match field.as_str() {
|
||||
"name" => {
|
||||
item.name = value;
|
||||
}
|
||||
"price" => {
|
||||
item.price = value.parse().unwrap_or_default();
|
||||
}
|
||||
"picture_url" => {
|
||||
item.picture_url = value;
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
memo
|
||||
},
|
||||
);
|
||||
let mut ids = { h.keys().copied().collect::<Vec<_>>() };
|
||||
ids.sort();
|
||||
for id in ids {
|
||||
if let Some(item) = h.remove(&id) {
|
||||
items.push(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[post("/upload")]
|
||||
async fn upload(
|
||||
req: HttpRequest,
|
||||
@ -523,30 +515,4 @@ mod tests {
|
||||
|
||||
use crate::model::view;
|
||||
use crate::model::view::BusinessItemInput;
|
||||
|
||||
impl BusinessItemInput {
|
||||
pub fn new<S: Into<String>, P: Into<String>>(name: S, price: u32, picture_url: P) -> Self {
|
||||
Self {
|
||||
name: name.into(),
|
||||
price,
|
||||
picture_url: picture_url.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_items() {
|
||||
let mut items = Vec::with_capacity(0);
|
||||
let mut names: HashMap<String, String> = HashMap::with_capacity(4);
|
||||
names.insert("items[0][name]".into(), "a".into());
|
||||
names.insert("items[0][price]".into(), "10".into());
|
||||
names.insert("items[1][name]".into(), "b".into());
|
||||
names.insert("items[1][price]".into(), "20".into());
|
||||
super::process_items(&mut items, names);
|
||||
let expected = vec![
|
||||
BusinessItemInput::new("a", 10, "/a"),
|
||||
BusinessItemInput::new("b", 20, "/b"),
|
||||
];
|
||||
assert_eq!(items, expected);
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ use crate::queries;
|
||||
use crate::routes::unrestricted::IndexTemplate;
|
||||
use crate::routes::{HttpResult, Identity};
|
||||
|
||||
#[get("/")]
|
||||
#[get("/local-businesses")]
|
||||
#[tracing::instrument]
|
||||
pub async fn businesses_page(req: HttpRequest, db: Data<PgPool>, id: Identity) -> HttpResult {
|
||||
let pool = db.into_inner();
|
||||
|
@ -73,6 +73,82 @@ async fn marketplace(req: HttpRequest, db: Data<PgPool>, id: Identity) -> HttpRe
|
||||
)
|
||||
}
|
||||
|
||||
pub fn configure(config: &mut ServiceConfig) {
|
||||
config.service(web::scope("/marketplace").service(marketplace));
|
||||
#[derive(Default, Serialize, Template)]
|
||||
#[template(path = "./marketplace/edit.html")]
|
||||
struct EditOfferTemplate {
|
||||
account: Option<db::Account>,
|
||||
error: Option<String>,
|
||||
page: Page,
|
||||
#[serde(skip)]
|
||||
h: Helper,
|
||||
offer: view::Offer,
|
||||
}
|
||||
|
||||
#[get("/{id}/edit")]
|
||||
async fn edit_marketplace(
|
||||
req: HttpRequest,
|
||||
db: Data<PgPool>,
|
||||
id: Identity,
|
||||
path: web::Path<(i32,)>,
|
||||
) -> HttpResult {
|
||||
let offer_id = path.into_inner().0;
|
||||
let pool = db.into_inner();
|
||||
let mut t = crate::ok_or_internal!(&req, pool.begin().await);
|
||||
let account = match id.identity() {
|
||||
Some(id) => queries::account_by_id(&mut t, id).await,
|
||||
_ => None,
|
||||
};
|
||||
let account = match account {
|
||||
Some(a) => a,
|
||||
_ => {
|
||||
return HttpResult::res(
|
||||
&req,
|
||||
StatusCode::NOT_FOUND,
|
||||
EditOfferTemplate {
|
||||
page: Page::Marketplace,
|
||||
account,
|
||||
error: Some("Oferta nie istnieje".into()),
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
let offer = match queries::offer_by_id(&mut t, account.id, offer_id).await {
|
||||
Ok(offer) => offer,
|
||||
Err(e) => {
|
||||
dbg!(e);
|
||||
return HttpResult::res(
|
||||
&req,
|
||||
StatusCode::NOT_FOUND,
|
||||
EditOfferTemplate {
|
||||
page: Page::Marketplace,
|
||||
account: Some(account),
|
||||
error: Some("Oferta nie istnieje".into()),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
t.commit().await.ok();
|
||||
|
||||
HttpResult::res(
|
||||
&req,
|
||||
StatusCode::OK,
|
||||
EditOfferTemplate {
|
||||
page: Page::Marketplace,
|
||||
account: Some(account),
|
||||
offer: view::Offer::from((offer, &vec![])),
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
pub fn configure(config: &mut ServiceConfig) {
|
||||
config.service(
|
||||
web::scope("/marketplace")
|
||||
.service(edit_marketplace)
|
||||
.service(marketplace),
|
||||
);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user