Add price range
This commit is contained in:
parent
12f95612d6
commit
de9f1742d1
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -1308,6 +1308,7 @@ dependencies = [
|
|||||||
"argon2",
|
"argon2",
|
||||||
"askama",
|
"askama",
|
||||||
"base64",
|
"base64",
|
||||||
|
"byteorder",
|
||||||
"chrono",
|
"chrono",
|
||||||
"futures",
|
"futures",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
@ -1317,6 +1318,7 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"sqlx",
|
"sqlx",
|
||||||
|
"sqlx-core",
|
||||||
"tracing",
|
"tracing",
|
||||||
"tracing-actix-web",
|
"tracing-actix-web",
|
||||||
"tracing-subscriber",
|
"tracing-subscriber",
|
||||||
|
@ -15,6 +15,7 @@ actix-utils = { version = "3.0.0" }
|
|||||||
actix-web = { version = "*" }
|
actix-web = { version = "*" }
|
||||||
argon2 = { version = "0.4.1" }
|
argon2 = { version = "0.4.1" }
|
||||||
askama = { version = "*", features = ["serde-json"] }
|
askama = { version = "*", features = ["serde-json"] }
|
||||||
|
byteorder = { version = "1.4.3" }
|
||||||
chrono = { version = "*", features = ["serde"] }
|
chrono = { version = "*", features = ["serde"] }
|
||||||
futures = { version = "0.3.21", features = ["async-await", "std"] }
|
futures = { version = "0.3.21", features = ["async-await", "std"] }
|
||||||
futures-util = { version = "0.3.21", features = [] }
|
futures-util = { version = "0.3.21", features = [] }
|
||||||
@ -24,6 +25,7 @@ rand = { version = "0.8.5", features = [] }
|
|||||||
serde = { version = "*", features = ["derive"] }
|
serde = { version = "*", features = ["derive"] }
|
||||||
serde_json = { version = "*" }
|
serde_json = { version = "*" }
|
||||||
sqlx = { version = "*", features = ["runtime-actix-rustls", "postgres", "uuid", "chrono"] }
|
sqlx = { version = "*", features = ["runtime-actix-rustls", "postgres", "uuid", "chrono"] }
|
||||||
|
sqlx-core = { version = "0.6.0" }
|
||||||
tracing = { version = "*" }
|
tracing = { version = "*" }
|
||||||
tracing-actix-web = { version = "*" }
|
tracing-actix-web = { version = "*" }
|
||||||
tracing-subscriber = { version = "*" }
|
tracing-subscriber = { version = "*" }
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
{% extends "../base.html" %}
|
{% extends "../base.html" %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<marketplace-offers>
|
<marketplace-offers>
|
||||||
<h1>Sprzedaż niepotrzebych rzeczy</h1>
|
<h1>Sprzedaż niepotrzebnych rzeczy</h1>
|
||||||
|
|
||||||
<offer-form></offer-form>
|
<offer-form></offer-form>
|
||||||
{% for offer in offers %}
|
{% for offer in offers %}
|
||||||
@ -9,6 +9,15 @@
|
|||||||
offer-id="{{offer.id}}"
|
offer-id="{{offer.id}}"
|
||||||
description="{{offer.description}}"
|
description="{{offer.description}}"
|
||||||
picture-url="{{offer.picture_url}}"
|
picture-url="{{offer.picture_url}}"
|
||||||
|
{% match offer.price_range %}
|
||||||
|
{% when PriceRange::Free %}
|
||||||
|
price-range="free"
|
||||||
|
{% when PriceRange::Fixed with { value } %}
|
||||||
|
price-range="{{value}}"
|
||||||
|
{% when PriceRange::Range with { min, max } %}
|
||||||
|
price-range-min="{{min}}"
|
||||||
|
price-range-max="{{max}}"
|
||||||
|
{% endmatch %}
|
||||||
></marketplace-offer>
|
></marketplace-offer>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</marketplace-offers>
|
</marketplace-offers>
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
import { Component, INPUT_STYLE } from "../shared";
|
import { Component, INPUT_STYLE, PriceRange } from "../shared";
|
||||||
|
|
||||||
customElements.define('marketplace-offer', class extends Component {
|
customElements.define('marketplace-offer', class extends Component {
|
||||||
|
#price_range;
|
||||||
|
|
||||||
static get observedAttributes() {
|
static get observedAttributes() {
|
||||||
return ['offer-id', 'description', 'picture-url']
|
return ['offer-id', 'description', 'picture-url', "price-range", "price-range-min", "price-range-max"]
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
@ -36,15 +38,17 @@ customElements.define('marketplace-offer', class extends Component {
|
|||||||
min-height: 200px;
|
min-height: 200px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
${INPUT_STYLE}
|
${ INPUT_STYLE }
|
||||||
</style>
|
</style>
|
||||||
<section>
|
<section>
|
||||||
<div id="preview">
|
<div id="preview">
|
||||||
<img alt="" src="" id="picture" />
|
<img alt="" src="" id="picture" />
|
||||||
</div>
|
</div>
|
||||||
<p id="description"></p>
|
<p id="description"></p>
|
||||||
|
<p id="price"></p>
|
||||||
</section>
|
</section>
|
||||||
`);
|
`);
|
||||||
|
this.#price_range = new PriceRange(0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
get offer_id() {
|
get offer_id() {
|
||||||
@ -74,4 +78,56 @@ customElements.define('marketplace-offer', class extends Component {
|
|||||||
this.setAttribute('picture-url', v);
|
this.setAttribute('picture-url', v);
|
||||||
this.shadowRoot.querySelector('#picture').src = v;
|
this.shadowRoot.querySelector('#picture').src = v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get price_range() {
|
||||||
|
return this.#price_range
|
||||||
|
}
|
||||||
|
|
||||||
|
set price_range(v) {
|
||||||
|
v = v + '';
|
||||||
|
if (!v.match(/free|(\d+([,.]\d{2})?)(,(\d+([,.]\d{2})?))?/i))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (v === 'free') return this.#price_range = new PriceRange(v, 0);
|
||||||
|
if (v.includes(',')) {
|
||||||
|
const [min, max, ...r] = v.split(',');
|
||||||
|
this.#price_range = new PriceRange(parseInt(min), parseInt(max));
|
||||||
|
}
|
||||||
|
this.#displayPrice();
|
||||||
|
}
|
||||||
|
|
||||||
|
get price_range_min() {
|
||||||
|
return this.#price_range.min
|
||||||
|
}
|
||||||
|
|
||||||
|
set price_range_min(v) {
|
||||||
|
this.#price_range.min = v;
|
||||||
|
this.#displayPrice();
|
||||||
|
}
|
||||||
|
|
||||||
|
get price_range_max() {
|
||||||
|
return this.#price_range.max
|
||||||
|
}
|
||||||
|
|
||||||
|
set price_range_max(v) {
|
||||||
|
this.#price_range.max = v;
|
||||||
|
this.#displayPrice();
|
||||||
|
}
|
||||||
|
|
||||||
|
#displayPrice() {
|
||||||
|
const view = this.shadowRoot.querySelector('#price');
|
||||||
|
if (this.#price_range.isFree) {
|
||||||
|
view.innerHTML = 'Za darmo';
|
||||||
|
}
|
||||||
|
if (this.#price_range.isRange) {
|
||||||
|
view.innerHTML = `
|
||||||
|
<span>${this.#price_range.min}PLN</span>
|
||||||
|
<span>${this.#price_range.max}PLN</span>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
if (this.#price_range.isFixed) {
|
||||||
|
view.innerHTML = `${this.#price_range.min}PLN`;
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
@ -20,6 +20,16 @@ customElements.define('offer-form', class extends Component {
|
|||||||
#descriptionSection {
|
#descriptionSection {
|
||||||
width: calc(100% - 230px);
|
width: calc(100% - 230px);
|
||||||
}
|
}
|
||||||
|
@media only screen and (min-device-width: 1200px) {
|
||||||
|
#priceSection {
|
||||||
|
width: 300px;
|
||||||
|
margin-right: 16px;
|
||||||
|
}
|
||||||
|
#descriptionSection {
|
||||||
|
width: calc(100% - 550px);
|
||||||
|
margin-right: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
${ FORM_STYLE }
|
${ FORM_STYLE }
|
||||||
</style>
|
</style>
|
||||||
<section>
|
<section>
|
||||||
@ -32,6 +42,18 @@ customElements.define('offer-form', class extends Component {
|
|||||||
<label for="description">Opis</label>
|
<label for="description">Opis</label>
|
||||||
<input name="description" id="description" type="text" />
|
<input name="description" id="description" type="text" />
|
||||||
</div>
|
</div>
|
||||||
|
<div id="priceSection">
|
||||||
|
<div>
|
||||||
|
<label>Cena minimalna</label>
|
||||||
|
<price-input id="priceMinUI" value="0"></price-input>
|
||||||
|
<input name="price_min" id="priceMin" type="hidden" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label>Cena maksymalna</label>
|
||||||
|
<price-input id="priceMaxUI" value="0"></price-input>
|
||||||
|
<input name="price_max" id="priceMax" type="hidden" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<input id="submit" type="submit" value="Utwórz" />
|
<input id="submit" type="submit" value="Utwórz" />
|
||||||
</div>
|
</div>
|
||||||
@ -39,6 +61,15 @@ customElements.define('offer-form', class extends Component {
|
|||||||
</section>
|
</section>
|
||||||
`);
|
`);
|
||||||
|
|
||||||
|
this.shadowRoot.querySelector('#priceMinUI').addEventListener('change', ev => {
|
||||||
|
ev.stopPropagation();
|
||||||
|
this.shadowRoot.querySelector('#priceMin').value = ev.target.value;
|
||||||
|
});
|
||||||
|
|
||||||
|
this.shadowRoot.querySelector('#priceMaxUI').addEventListener('change', ev => {
|
||||||
|
ev.stopPropagation();
|
||||||
|
this.shadowRoot.querySelector('#priceMax').value = ev.target.value;
|
||||||
|
});
|
||||||
this.addEventListener('image-input:uploaded', ev => {
|
this.addEventListener('image-input:uploaded', ev => {
|
||||||
this.picture_url = ev.detail;
|
this.picture_url = ev.detail;
|
||||||
});
|
});
|
||||||
|
@ -185,6 +185,44 @@ export class PseudoForm extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class PriceRange {
|
||||||
|
#min;
|
||||||
|
#max;
|
||||||
|
|
||||||
|
constructor(min, max) {
|
||||||
|
this.#min = min || 0;
|
||||||
|
this.#max = max || 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
get isFree() {
|
||||||
|
return this.#min === 'free' || (this.#min === 0 && this.#max === 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
get isRange() {
|
||||||
|
return this.#max > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
get isFixed() {
|
||||||
|
return !this.isFree && !this.isRange
|
||||||
|
}
|
||||||
|
|
||||||
|
get min() {
|
||||||
|
return this.#min
|
||||||
|
}
|
||||||
|
|
||||||
|
set min(v) {
|
||||||
|
this.#min = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
get max() {
|
||||||
|
return this.#max
|
||||||
|
}
|
||||||
|
|
||||||
|
set max(v) {
|
||||||
|
this.#max = v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export const fireFbReady = () => {
|
export const fireFbReady = () => {
|
||||||
fbReady = true;
|
fbReady = true;
|
||||||
for (const fn of fbQueue) fn();
|
for (const fn of fbQueue) fn();
|
||||||
|
8
migrations/20220720060805_add_offer_price.sql
Normal file
8
migrations/20220720060805_add_offer_price.sql
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
CREATE TYPE "PriceRange" AS
|
||||||
|
(
|
||||||
|
min int,
|
||||||
|
max int
|
||||||
|
);
|
||||||
|
|
||||||
|
ALTER TABLE offers
|
||||||
|
ADD COLUMN price_range "PriceRange" NOT NULL DEFAULT '(0, 0)';
|
@ -1,9 +1,14 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fmt::{Display, Formatter};
|
use std::fmt::{Display, Formatter};
|
||||||
|
|
||||||
|
use byteorder::ByteOrder;
|
||||||
use chrono::{NaiveDateTime, Utc};
|
use chrono::{NaiveDateTime, Utc};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use sqlx::{FromRow, Type};
|
use sqlx::{FromRow, Type};
|
||||||
|
use sqlx_core::database::{HasArguments, HasValueRef};
|
||||||
|
use sqlx_core::encode::IsNull;
|
||||||
|
use sqlx_core::error::BoxDynError;
|
||||||
|
use sqlx_core::postgres::{PgValueFormat, Postgres};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
#[derive(Debug, Default, PartialOrd, PartialEq, Eq, Copy, Clone, Serialize, Deserialize, Type)]
|
#[derive(Debug, Default, PartialOrd, PartialEq, Eq, Copy, Clone, Serialize, Deserialize, Type)]
|
||||||
@ -165,10 +170,89 @@ pub struct UpdateLocalBusinessInput {
|
|||||||
pub description: String,
|
pub description: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
|
||||||
|
pub enum PriceRange {
|
||||||
|
Free,
|
||||||
|
Fixed { value: i32 },
|
||||||
|
Range { min: i32, max: i32 },
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<(i32, i32)> for PriceRange {
|
||||||
|
fn from((min, max): (i32, i32)) -> Self {
|
||||||
|
match (min, max) {
|
||||||
|
(0, 0) => Self::Free,
|
||||||
|
(_, 0) => Self::Fixed { value: min },
|
||||||
|
_ => Self::Range { min, max },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl sqlx::Type<Postgres> for PriceRange {
|
||||||
|
fn type_info() -> sqlx::postgres::PgTypeInfo {
|
||||||
|
sqlx::postgres::PgTypeInfo::with_name("PriceRange")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn take_i32(bytes: &mut &[u8]) -> i32 {
|
||||||
|
let value = byteorder::BigEndian::read_i32(&bytes[0..4]);
|
||||||
|
*bytes = &bytes[4..];
|
||||||
|
value
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'l> sqlx::Decode<'l, Postgres> for PriceRange {
|
||||||
|
fn decode(value: <Postgres as HasValueRef<'l>>::ValueRef) -> Result<Self, BoxDynError> {
|
||||||
|
match value.format() {
|
||||||
|
PgValueFormat::Text => {
|
||||||
|
let s = value.as_str()?;
|
||||||
|
eprintln!("{s:?}");
|
||||||
|
Ok(Self::Free)
|
||||||
|
}
|
||||||
|
PgValueFormat::Binary => {
|
||||||
|
let mut bytes = value.as_bytes()?;
|
||||||
|
|
||||||
|
let _len = take_i32(&mut bytes);
|
||||||
|
|
||||||
|
let _ty = take_i32(&mut bytes);
|
||||||
|
let _min_len = take_i32(&mut bytes);
|
||||||
|
let min = take_i32(&mut bytes);
|
||||||
|
|
||||||
|
let _ty = take_i32(&mut bytes);
|
||||||
|
let _max_len = take_i32(&mut bytes);
|
||||||
|
let max = take_i32(&mut bytes);
|
||||||
|
|
||||||
|
Ok((min, max).into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'l> sqlx::Encode<'l, Postgres> for PriceRange {
|
||||||
|
fn encode_by_ref(&self, buf: &mut <Postgres as HasArguments<'l>>::ArgumentBuffer) -> IsNull {
|
||||||
|
match self {
|
||||||
|
PriceRange::Free => {
|
||||||
|
let _ = 0.encode(buf);
|
||||||
|
let _ = 0.encode(buf);
|
||||||
|
true.encode(buf)
|
||||||
|
}
|
||||||
|
PriceRange::Fixed { value } => {
|
||||||
|
let _ = value.encode(buf);
|
||||||
|
let _ = 0.encode(buf);
|
||||||
|
false.encode(buf)
|
||||||
|
}
|
||||||
|
PriceRange::Range { min, max } => {
|
||||||
|
let _ = min.encode(buf);
|
||||||
|
let _ = max.encode(buf);
|
||||||
|
false.encode(buf)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, FromRow)]
|
#[derive(Debug, Serialize, Deserialize, FromRow)]
|
||||||
pub struct Offer {
|
pub struct Offer {
|
||||||
pub id: i32,
|
pub id: i32,
|
||||||
pub owner_id: i32,
|
pub owner_id: i32,
|
||||||
|
pub price_range: PriceRange,
|
||||||
pub description: String,
|
pub description: String,
|
||||||
pub picture_url: String,
|
pub picture_url: String,
|
||||||
pub state: OfferState,
|
pub state: OfferState,
|
||||||
@ -194,7 +278,7 @@ pub struct UpdateLocalBusinessItemInput {
|
|||||||
pub picture_url: String,
|
pub picture_url: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, FromRow)]
|
#[derive(Debug, Deserialize)]
|
||||||
pub struct DeleteNewsArticleInput {
|
pub struct DeleteNewsArticleInput {
|
||||||
pub id: i32,
|
pub id: i32,
|
||||||
}
|
}
|
||||||
@ -229,6 +313,7 @@ pub struct CreateOfferInput {
|
|||||||
pub picture_url: String,
|
pub picture_url: String,
|
||||||
pub state: OfferState,
|
pub state: OfferState,
|
||||||
pub owner_id: i32,
|
pub owner_id: i32,
|
||||||
|
pub price_range: PriceRange,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -237,4 +322,5 @@ pub struct UpdateOfferInput {
|
|||||||
pub description: String,
|
pub description: String,
|
||||||
pub picture_url: String,
|
pub picture_url: String,
|
||||||
pub state: OfferState,
|
pub state: OfferState,
|
||||||
|
pub price_range: PriceRange,
|
||||||
}
|
}
|
||||||
|
@ -226,6 +226,8 @@ pub struct DeleteContactInfoInput {
|
|||||||
pub struct CreateOfferInput {
|
pub struct CreateOfferInput {
|
||||||
pub description: String,
|
pub description: String,
|
||||||
pub picture_url: String,
|
pub picture_url: String,
|
||||||
|
pub price_min: i32,
|
||||||
|
pub price_max: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
@ -233,4 +235,6 @@ pub struct UpdateOfferInput {
|
|||||||
pub id: i32,
|
pub id: i32,
|
||||||
pub description: String,
|
pub description: String,
|
||||||
pub picture_url: String,
|
pub picture_url: String,
|
||||||
|
pub price_min: i32,
|
||||||
|
pub price_max: i32,
|
||||||
}
|
}
|
||||||
|
@ -1004,6 +1004,7 @@ pub async fn all_offers(t: &mut T<'_>) -> Result<Vec<db::Offer>> {
|
|||||||
SELECT
|
SELECT
|
||||||
id,
|
id,
|
||||||
owner_id,
|
owner_id,
|
||||||
|
price_range,
|
||||||
name,
|
name,
|
||||||
description,
|
description,
|
||||||
picture_url,
|
picture_url,
|
||||||
@ -1028,6 +1029,7 @@ pub async fn visible_offers(t: &mut T<'_>) -> Result<Vec<db::Offer>> {
|
|||||||
SELECT
|
SELECT
|
||||||
id,
|
id,
|
||||||
owner_id,
|
owner_id,
|
||||||
|
price_range,
|
||||||
description,
|
description,
|
||||||
picture_url,
|
picture_url,
|
||||||
state,
|
state,
|
||||||
@ -1052,6 +1054,7 @@ pub async fn account_offers(t: &mut T<'_>, account_id: i32) -> Result<Vec<db::Of
|
|||||||
SELECT
|
SELECT
|
||||||
id,
|
id,
|
||||||
owner_id,
|
owner_id,
|
||||||
|
price_range,
|
||||||
description,
|
description,
|
||||||
picture_url,
|
picture_url,
|
||||||
state,
|
state,
|
||||||
@ -1074,11 +1077,12 @@ WHERE owner_id = $1
|
|||||||
pub async fn create_offer(t: &mut T<'_>, input: db::CreateOfferInput) -> Result<db::Offer> {
|
pub async fn create_offer(t: &mut T<'_>, input: db::CreateOfferInput) -> Result<db::Offer> {
|
||||||
sqlx::query_as(
|
sqlx::query_as(
|
||||||
r#"
|
r#"
|
||||||
INSERT INTO offers (description, picture_url, state, search, owner_id)
|
INSERT INTO offers (description, picture_url, state, search, owner_id, price_range)
|
||||||
VALUES ($1, $2, $3, to_tsvector('polish', $4), $5)
|
VALUES ($1, $2, $3, to_tsvector('polish', $4), $5, $6)
|
||||||
RETURNING
|
RETURNING
|
||||||
id,
|
id,
|
||||||
owner_id,
|
owner_id,
|
||||||
|
price_range,
|
||||||
description,
|
description,
|
||||||
picture_url,
|
picture_url,
|
||||||
state,
|
state,
|
||||||
@ -1090,6 +1094,7 @@ RETURNING
|
|||||||
.bind(input.state)
|
.bind(input.state)
|
||||||
.bind(&input.description)
|
.bind(&input.description)
|
||||||
.bind(input.owner_id)
|
.bind(input.owner_id)
|
||||||
|
.bind(input.price_range)
|
||||||
.fetch_one(t)
|
.fetch_one(t)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| {
|
.map_err(|e| {
|
||||||
@ -1107,11 +1112,13 @@ UPDATE offers
|
|||||||
SET description = $2,
|
SET description = $2,
|
||||||
picture_url = $3,
|
picture_url = $3,
|
||||||
state = $4,
|
state = $4,
|
||||||
search = to_tsvector('polish', $5)
|
search = to_tsvector('polish', $5),
|
||||||
|
price_range = $6
|
||||||
WHERE id = $1
|
WHERE id = $1
|
||||||
RETURNING
|
RETURNING
|
||||||
id,
|
id,
|
||||||
owner_id,
|
owner_id,
|
||||||
|
price_range,
|
||||||
description,
|
description,
|
||||||
picture_url,
|
picture_url,
|
||||||
state,
|
state,
|
||||||
@ -1123,6 +1130,7 @@ RETURNING
|
|||||||
.bind(&input.picture_url)
|
.bind(&input.picture_url)
|
||||||
.bind(input.state)
|
.bind(input.state)
|
||||||
.bind(&input.description)
|
.bind(&input.description)
|
||||||
|
.bind(&input.price_range)
|
||||||
.fetch_one(t)
|
.fetch_one(t)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| {
|
.map_err(|e| {
|
||||||
|
@ -3,9 +3,9 @@ use actix_web::{get, post, web, HttpResponse};
|
|||||||
use askama::*;
|
use askama::*;
|
||||||
use sqlx::PgPool;
|
use sqlx::PgPool;
|
||||||
|
|
||||||
use crate::model::db::OfferState;
|
use crate::model::db::{self, OfferState, PriceRange};
|
||||||
|
use crate::model::view;
|
||||||
use crate::model::view::Page;
|
use crate::model::view::Page;
|
||||||
use crate::model::{db, view};
|
|
||||||
use crate::routes::{Identity, Result};
|
use crate::routes::{Identity, Result};
|
||||||
use crate::view::Helper;
|
use crate::view::Helper;
|
||||||
use crate::{authorize, not_xss, ok_or_internal, queries};
|
use crate::{authorize, not_xss, ok_or_internal, queries};
|
||||||
@ -66,6 +66,7 @@ async fn create_offer(
|
|||||||
picture_url: form.picture_url,
|
picture_url: form.picture_url,
|
||||||
state: OfferState::Pending,
|
state: OfferState::Pending,
|
||||||
owner_id: account.id,
|
owner_id: account.id,
|
||||||
|
price_range: (form.price_min, form.price_max).into(),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
@ -119,6 +120,7 @@ async fn update_offer(
|
|||||||
description: form.description,
|
description: form.description,
|
||||||
picture_url: form.picture_url,
|
picture_url: form.picture_url,
|
||||||
state: Default::default(),
|
state: Default::default(),
|
||||||
|
price_range: (form.price_min, form.price_max).into(),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
|
Loading…
Reference in New Issue
Block a user