Fix rent offers

This commit is contained in:
Adrian Woźniak 2023-10-13 19:33:47 +02:00
parent de03009257
commit f14d27b93d
4 changed files with 139 additions and 32 deletions

View File

@ -783,6 +783,10 @@ select {
z-index: 50; z-index: 50;
} }
.m-0 {
margin: 0px;
}
.m-1 { .m-1 {
margin: 0.25rem; margin: 0.25rem;
} }
@ -1169,10 +1173,6 @@ select {
text-align: center; text-align: center;
} }
.text-right {
text-align: right;
}
.text-2xl { .text-2xl {
font-size: 1.5rem; font-size: 1.5rem;
line-height: 2rem; line-height: 2rem;
@ -1621,6 +1621,14 @@ select {
} }
@media (min-width: 1280px) { @media (min-width: 1280px) {
.xl\:mt-6 {
margin-top: 1.5rem;
}
.xl\:block {
display: block;
}
.xl\:flex { .xl\:flex {
display: flex; display: flex;
} }
@ -1629,9 +1637,25 @@ select {
min-height: calc(100vh - 80px - 192px); min-height: calc(100vh - 80px - 192px);
} }
.xl\:w-\[30\%\] {
width: 30%;
}
.xl\:w-\[48\%\] { .xl\:w-\[48\%\] {
width: 48%; width: 48%;
} }
.xl\:justify-between {
justify-content: space-between;
}
.xl\:p-0 {
padding: 0px;
}
.xl\:text-right {
text-align: right;
}
} }
.\[\&\.active\]\:text-black\/90.active { .\[\&\.active\]\:text-black\/90.active {

View File

@ -5,15 +5,16 @@ use std::sync::Arc;
use actix_web::http::header::ContentType; use actix_web::http::header::ContentType;
use actix_web::web::{scope, Data, Form, Path, ServiceConfig}; use actix_web::web::{scope, Data, Form, Path, ServiceConfig};
use actix_web::{get, post, put, HttpRequest, HttpResponse}; use actix_web::{delete, get, post, put, HttpRequest, HttpResponse};
use askama_actix::Template; use askama_actix::Template;
use autometrics::autometrics; use autometrics::autometrics;
use oswilno_contract::parking_space_locations::Model as ParkingSpaceLocation; use oswilno_contract::parking_space_locations::Model as ParkingSpaceLocation;
use oswilno_contract::parking_space_rents::Model as ParkingSpaceRent; use oswilno_contract::parking_space_rents::Model as ParkingSpaceRent;
use oswilno_contract::parking_spaces::Model as ParkingSpace; use oswilno_contract::parking_spaces::Model as ParkingSpace;
use oswilno_contract::prelude::*;
use oswilno_contract::sea_orm_active_enums::ParkingSpaceState; use oswilno_contract::sea_orm_active_enums::ParkingSpaceState;
use oswilno_contract::{ use oswilno_contract::{
accounts, chrono, parking_space_locations, parking_space_rents, parking_spaces, accounts, chrono, parking_space_locations, parking_space_rents, parking_spaces, rent_requests,
}; };
use oswilno_session::{Authenticated, MaybeAuthenticated}; use oswilno_session::{Authenticated, MaybeAuthenticated};
use oswilno_view::{ use oswilno_view::{
@ -40,7 +41,8 @@ pub fn mount(config: &mut ServiceConfig) {
.service(all_parking_spaces) .service(all_parking_spaces)
.service(create) .service(create)
.service(edit_show) .service(edit_show)
.service(update), .service(update)
.service(delete_parking_space),
); );
} }
@ -132,6 +134,34 @@ async fn search_parking_spaces() -> HttpResponse {
HttpResponse::Ok().body("") HttpResponse::Ok().body("")
} }
#[delete("/delete/{parking_space_id}")]
async fn delete_parking_space(
_req: HttpRequest,
db: Data<sea_orm::DatabaseConnection>,
_session: Authenticated,
_hcx: HelperContext,
parking_space_id: Path<i32>,
) -> HttpResponse {
let parking_space_id = parking_space_id.into_inner();
let db = db.into_inner();
let Ok(res) = ParkingSpaces::delete_by_id(parking_space_id)
.exec(&*db)
.await
.inspect_err(|e| tracing::error!("Failed to delete parking space {parking_space_id}: {e}"))
else {
return HttpResponse::NotFound()
.body(format!("Parking space {parking_space_id} does not exists"));
};
if res.rows_affected == 1 {
HttpResponse::SeeOther()
.append_header(("HX-Redirect", "/parking-spaces/all"))
.append_header(("Location", "/parking-spaces/all"))
.body("")
} else {
HttpResponse::NotFound().body(format!("Parking space {parking_space_id} does not exists"))
}
}
async fn load_parking_spaces( async fn load_parking_spaces(
db: Arc<DatabaseConnection>, db: Arc<DatabaseConnection>,
account_id: Option<i32>, account_id: Option<i32>,
@ -792,3 +822,52 @@ fn render_rent_form(
} }
.unwrap() .unwrap()
} }
#[post("/{parking_space_id}/parking-space-rents/{parking_space_rent_id}/request")]
pub async fn create_rent_request(
session: Authenticated,
db: Data<DatabaseConnection>,
parking_space_id: Path<i32>,
parking_space_rent_id: Path<i32>,
hcx: HelperContext,
) -> HttpResponse {
let db = db.into_inner();
let parking_space_id = parking_space_id.into_inner();
let parking_space_rent_id = parking_space_rent_id.into_inner();
{
use rent_requests::Column::*;
let res = RentRequests::find()
.filter(ParkingSpaceId.eq(Some(parking_space_id)))
.filter(ParkingSpaceRentId.eq(Some(parking_space_rent_id)))
.filter(AccountId.eq(Some(session.account_id()))).one(&*db).await
.inspect_err(|e| tracing::error!("Failed to check rent request existence for space {parking_space_id} and rent {parking_space_rent_id}: {e}"));
match res {
Ok(Some(_)) => {
return HttpResponse::Conflict()
.body(filters::t("Already requested", &hcx).unwrap_or_default());
}
Err(_) => {
return HttpResponse::InternalServerError()
.body(filters::t("Internat server error", &hcx).unwrap_or_default());
}
_ => {}
};
};
let Ok(_rent_request) = rent_requests::ActiveModel {
parking_space_id: Set(Some(parking_space_id)),
parking_space_rent_id: Set(Some(parking_space_rent_id)),
account_id: Set(Some(session.account_id())),
..Default::default()
}.save(&*db).await
.inspect_err(|e| tracing::error!("Failed to create rent request for space {parking_space_id} and rent {parking_space_rent_id}: {e}")) else {
return HttpResponse::InternalServerError()
.body(filters::t("Internat server error", &hcx).unwrap_or_default());
};
HttpResponse::Ok()
.append_header((
"HX-Retarget",
format!("#submit-request-rent-{parking_space_rent_id}").as_str(),
))
.finish()
}

View File

@ -1,15 +1,16 @@
<section class="container mx-auto px-4"> <section class="container mx-auto px-4">
<section class="flex space-x-4"> <section class="flex space-x-4 xl:justify-between justify-center">
<h1 class="text-white font-semibold text-5xl"> <h1 class="text-white font-semibold text-5xl hidden xl:block">
{{"Parking spaces"}} {{"Parking spaces"}}
</h1> </h1>
<div class=""> <div class="hidden xl:block">
&nbsp; &nbsp;
</div> </div>
<div> <div class="hidden xl:block">
</div> </div>
{% if let Some(session) = session %} {% if let Some(session) = session %}
<div> <div class="m-0">
<a <a
href="/parking-spaces/form" href="/parking-spaces/form"
x-get="/parking-spaces/form" x-get="/parking-spaces/form"
@ -38,7 +39,7 @@
<li class="py-3 sm:py-4"> <li class="py-3 sm:py-4">
<oswilno-parking-space <oswilno-parking-space
id="parking-space-{{ parking_space.id }}" id="parking-space-{{ parking_space.id }}"
> >
{% if let Some(account) = account_by_id.get(parking_space.account_id) -%} {% if let Some(account) = account_by_id.get(parking_space.account_id) -%}
{% if let Some(location_id) = parking_space.location_id -%} {% if let Some(location_id) = parking_space.location_id -%}
{% if let Some(location) = location_by_id.get(location_id) -%} {% if let Some(location) = location_by_id.get(location_id) -%}
@ -62,7 +63,7 @@
</section> </section>
{% endif %} {% endif %}
<oswilno-parking-space-rents class="xl:flex justify-between"> <oswilno-parking-space-rents class="block xl:flex justify-between">
{% for parking_space_rent in parking_space_rents -%} {% for parking_space_rent in parking_space_rents -%}
{% if let Some(parking_space) = parking_space_by_id.get(parking_space_rent.parking_space_id) %} {% if let Some(parking_space) = parking_space_by_id.get(parking_space_rent.parking_space_id) %}
{% if parking_space.state == ParkingSpaceState::Verified || Some(parking_space.account_id.clone()) == account_id %} {% if parking_space.state == ParkingSpaceState::Verified || Some(parking_space.account_id.clone()) == account_id %}
@ -72,54 +73,57 @@
<oswilno-parking-space-rent <oswilno-parking-space-rent
id="parking-space-rent-{{ parking_space_rent.id }}" id="parking-space-rent-{{ parking_space_rent.id }}"
class="xl:w-[48%] p-4 bg-white border border-white-200 rounded-lg shadow sm:p-8 dark:bg-white-800 dark:border-white-700 mt-6" class="block xl:w-[48%] p-4 bg-white border border-white-200 rounded-lg shadow sm:p-8 dark:bg-white-800 dark:border-white-700 mt-6"
> >
<oswilno-parking-space <oswilno-parking-space
id="parking-space-{{ parking_space.id }}" id="parking-space-{{ parking_space.id }}"
{% if let Some(spot) = parking_space.spot %} spot="{{ spot }}" {% endif %} {% if let Some(spot) = parking_space.spot %} spot="{{ spot }}" {% endif %}
class="flex justify-between" class="flex justify-between flex-wrap"
> >
<span class='spot text-4xl font-bold w-[30%] text-left'> <div class='spot text-4xl font-bold w-[30%] text-left'>
{% if let Some(spot) = parking_space.spot %} {% if let Some(spot) = parking_space.spot %}
{{ spot }} {{ spot }}
{% else %} {% else %}
&nbsp; &nbsp;
{% endif %} {% endif %}
</span> </div>
<oswilno-parking-space-location <oswilno-parking-space-location
id="parking-space-location-{{ location.id }}" id="parking-space-location-{{ location.id }}"
name="{{ location.name }}" name="{{ location.name }}"
stage="{{ location.stage }}" stage="{{ location.stage }}"
number="{{ location.number }}" number="{{ location.number }}"
class="w-[30%] text-3xl" class="xl:w-[30%] flex text-3xl"
> >
<span class="name">{{ location.name }}</span> <div>{{ location.name }}</div>
<span class="number">{{ location.number }}</span> <div>&nbsp;</div>
<span class="stage-label text-sm mr-1 ml-1"> <div>{{ location.number }}</div>
&nbsp;{{"stage"|t(hcx)}}&nbsp; <div>&nbsp;</div>
</span> <div class="stage-label text-sm mr-1 ml-1">
<span class="stage"> {{"stage"|t(hcx)}}
{{ location.stage }} </div>
</span> <div>&nbsp;</div>
<div>{{ location.stage }}</div>
</oswilno-parking-space-location> </oswilno-parking-space-location>
<oswilno-account <oswilno-account
id="account-{{ account.id }}" id="account-{{ account.id }}"
class="w-[30%] text-right font-bold uppercase text-red-800 dark:text-red-400" login="{{ account.login }}"
class="w-full xl:w-[30%] text-center py-2 xl:p-0 xl:text-right font-bold uppercase text-red-800 dark:text-red-400"
> >
<div>{{ account.login }}</div> {{ account.login }}
</oswilno-account> </oswilno-account>
</oswilno-parking-space> </oswilno-parking-space>
<div class="xl:flex justify-between mt-6"> <div class="flex justify-between xl:mt-6">
<span>{{"Price:"|t(hcx)}}</span> <span>{{"Price:"|t(hcx)}}</span>
<oswilno-price <oswilno-price
id="parking-space-rent-{{ parking_space_rent.id }}-price" id="parking-space-rent-{{ parking_space_rent.id }}-price"
multiplier="100" multiplier="100"
currency="PLN" currency="PLN"
price="{{ parking_space_rent.price }}" price="{{ parking_space_rent.price }}"
> class="flex justify-between"
>
<span class="price text-3xl">{{ parking_space_rent.price|display_price }}</span> <span class="price text-3xl">{{ parking_space_rent.price|display_price }}</span>
<span class="currency text-base text-neutral-500 dark:text-neutral-300">PLN</span> <span class="currency text-base text-neutral-500 dark:text-neutral-300">PLN</span>
</oswilno-price> </oswilno-price>

View File

@ -30,7 +30,7 @@
<a <a
href="/parking-spaces/delete/{{parking_space.id}}" href="/parking-spaces/delete/{{parking_space.id}}"
hx-target="main" hx-target="main"
hx-delete="/parking-spaces/edit/{{parking_space.id}}" hx-delete="/parking-spaces/delete/{{parking_space.id}}"
hx-headers='{"Accept":"text/html-partial"}' hx-headers='{"Accept":"text/html-partial"}'
class="text-white focus:ring-4 focus:outline-none font-medium rounded-lg text-sm p-2.5 text-center inline-flex items-center" class="text-white focus:ring-4 focus:outline-none font-medium rounded-lg text-sm p-2.5 text-center inline-flex items-center"
> >