🔥 Unrestrict currency field
This commit is contained in:
parent
706892fcbe
commit
0abb938393
27
backend/trip/alembic/versions/7e331b851cb7_trip_currency.py
Normal file
27
backend/trip/alembic/versions/7e331b851cb7_trip_currency.py
Normal file
@ -0,0 +1,27 @@
|
||||
"""Trip currency
|
||||
|
||||
Revision ID: 7e331b851cb7
|
||||
Revises: 26c89b7466f2
|
||||
Create Date: 2025-08-23 15:06:50.387366
|
||||
|
||||
"""
|
||||
|
||||
import sqlalchemy as sa
|
||||
import sqlmodel.sql.sqltypes
|
||||
from alembic import op
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = "7e331b851cb7"
|
||||
down_revision = "26c89b7466f2"
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
with op.batch_alter_table("trip", schema=None) as batch_op:
|
||||
batch_op.add_column(sa.Column("currency", sqlmodel.sql.sqltypes.AutoString(), nullable=True))
|
||||
|
||||
|
||||
def downgrade():
|
||||
with op.batch_alter_table("trip", schema=None) as batch_op:
|
||||
batch_op.drop_column("currency")
|
||||
@ -250,6 +250,7 @@ class PlaceRead(PlaceBase):
|
||||
class TripBase(SQLModel):
|
||||
name: str
|
||||
archived: bool | None = None
|
||||
currency: str | None = settings.DEFAULT_CURRENCY
|
||||
|
||||
|
||||
class Trip(TripBase, table=True):
|
||||
@ -294,6 +295,7 @@ class TripReadBase(TripBase):
|
||||
image_id=obj.image_id,
|
||||
days=len(obj.days),
|
||||
collaborators=[TripMemberRead.serialize(m) for m in obj.memberships],
|
||||
currency=obj.currency if obj.currency else settings.DEFAULT_CURRENCY,
|
||||
)
|
||||
|
||||
|
||||
@ -318,6 +320,7 @@ class TripRead(TripBase):
|
||||
places=[PlaceRead.serialize(place) for place in obj.places],
|
||||
collaborators=[TripMemberRead.serialize(m) for m in obj.memberships],
|
||||
shared=bool(obj.shares),
|
||||
currency=obj.currency if obj.currency else settings.DEFAULT_CURRENCY,
|
||||
)
|
||||
|
||||
|
||||
|
||||
@ -248,8 +248,7 @@
|
||||
</div>
|
||||
<div class="mt-4">
|
||||
<p-floatlabel variant="in" class="md:col-span-2">
|
||||
<p-select [options]="currencySigns" optionValue="s" optionLabel="c" inputId="currency" id="currency"
|
||||
class="capitalize" formControlName="currency" [checkmark]="true" [showClear]="true" fluid />
|
||||
<input id="currency" formControlName="currency" pInputText fluid />
|
||||
<label for="currency">Currency</label>
|
||||
</p-floatlabel>
|
||||
</div>
|
||||
|
||||
@ -96,7 +96,6 @@ export class DashboardComponent implements OnInit, AfterViewInit {
|
||||
markerClusterGroup?: L.MarkerClusterGroup;
|
||||
gpxLayerGroup?: L.LayerGroup;
|
||||
settings?: Settings;
|
||||
currencySigns = UtilsService.currencySigns();
|
||||
doNotDisplayOptions: SelectItemGroup[] = [];
|
||||
|
||||
places: Place[] = [];
|
||||
@ -117,8 +116,6 @@ export class DashboardComponent implements OnInit, AfterViewInit {
|
||||
private router: Router,
|
||||
private fb: FormBuilder,
|
||||
) {
|
||||
this.currencySigns = UtilsService.currencySigns();
|
||||
|
||||
this.settingsForm = this.fb.group({
|
||||
map_lat: [
|
||||
"",
|
||||
|
||||
@ -19,7 +19,7 @@
|
||||
severity="help" />
|
||||
<span
|
||||
class="bg-gray-100 text-gray-800 text-xs md:text-sm font-medium me-2 px-2.5 py-0.5 rounded min-w-fit dark:bg-gray-400">{{
|
||||
(totalPrice | number:'1.0-2') || '-' }} {{ currency$ | async }}</span>
|
||||
(totalPrice | number:'1.0-2') || '-' }} @if (totalPrice) { {{ trip.currency }} }</span>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@ -131,7 +131,7 @@
|
||||
</td>}
|
||||
@if (tripTableSelectedColumns.includes('price')) {<td class="truncate">@if (tripitem.price) {<span
|
||||
class="bg-gray-100 text-gray-800 text-sm font-medium me-2 px-2.5 py-0.5 rounded">{{
|
||||
tripitem.price }} {{ currency$ | async }}</span>}</td>}
|
||||
tripitem.price }} @if (tripitem.price) { {{ trip.currency }} }</span>}</td>}
|
||||
@if (tripTableSelectedColumns.includes('status')) {<td class="truncate">@if (tripitem.status) {<span
|
||||
[style.background]="tripitem.status.color+'1A'" [style.color]="tripitem.status.color"
|
||||
class="text-xs font-medium me-2 px-2.5 py-0.5 rounded">{{
|
||||
@ -180,7 +180,7 @@
|
||||
</td>}
|
||||
@if (tripTableSelectedColumns.includes('price')) {<td class="truncate">@if (tripitem.price) {<span
|
||||
class="bg-gray-100 text-gray-800 text-sm font-medium me-2 px-2.5 py-0.5 rounded">{{
|
||||
tripitem.price }} {{ currency$ | async }}</span>}</td>}
|
||||
tripitem.price }} @if (tripitem.price) { {{ trip.currency }} }</span>}</td>}
|
||||
@if (tripTableSelectedColumns.includes('status')) {<td class="truncate">@if (tripitem.status) {<span
|
||||
[style.background]="tripitem.status.color+'1A'" [style.color]="tripitem.status.color"
|
||||
class="text-xs font-medium me-2 px-2.5 py-0.5 rounded">{{
|
||||
@ -267,7 +267,7 @@
|
||||
@if (selectedItem.price) {
|
||||
<div class="rounded-md shadow p-4">
|
||||
<p class="font-bold mb-1">Price</p>
|
||||
<p class="text-sm text-gray-500">{{ selectedItem.price }} {{ currency$ | async }}</p>
|
||||
<p class="text-sm text-gray-500">{{ selectedItem.price }} @if (selectedItem.price) { {{ trip.currency }} }</p>
|
||||
</div>
|
||||
}
|
||||
|
||||
@ -353,7 +353,7 @@
|
||||
<span
|
||||
class="bg-gray-100 text-gray-800 text-sm font-medium me-2 px-2.5 py-0.5 rounded dark:bg-gray-100/85">{{
|
||||
p.price || '-'
|
||||
}} {{ currency$ | async }}</span>
|
||||
}} @if (p.price) { {{ trip.currency }} }</span>
|
||||
|
||||
@if (trip.collaborators.length) {
|
||||
<span class="bg-gray-100 text-gray-800 text-sm me-2 px-2.5 py-0.5 rounded dark:bg-gray-100/85">{{ p.user
|
||||
@ -402,7 +402,7 @@
|
||||
</div>
|
||||
<div class="flex items-center gap-2 flex-none">
|
||||
<span class="bg-gray-100 text-gray-800 text-sm px-2.5 py-0.5 rounded-md min-w-fit dark:bg-gray-100/85">{{
|
||||
getDayStats(d).price || '-' }} {{ currency$ | async }}</span>
|
||||
getDayStats(d).price || '-' }} @if (getDayStats(d).price) { {{ trip.currency }} }</span>
|
||||
<span class="bg-blue-100 text-blue-800 text-sm px-2.5 py-0.5 rounded-md dark:bg-blue-100/85">{{
|
||||
getDayStats(d).places }}</span>
|
||||
</div>
|
||||
|
||||
@ -54,14 +54,12 @@ import { InputTextModule } from "primeng/inputtext";
|
||||
FormsModule,
|
||||
MultiSelectModule,
|
||||
CheckboxModule,
|
||||
AsyncPipe,
|
||||
],
|
||||
templateUrl: "./shared-trip.component.html",
|
||||
styleUrls: ["./shared-trip.component.scss"],
|
||||
})
|
||||
export class SharedTripComponent implements AfterViewInit {
|
||||
token?: string;
|
||||
currency$: Observable<string>;
|
||||
statuses: TripStatus[] = [];
|
||||
trip?: Trip;
|
||||
places: Place[] = [];
|
||||
@ -180,7 +178,6 @@ export class SharedTripComponent implements AfterViewInit {
|
||||
private utilsService: UtilsService,
|
||||
private route: ActivatedRoute,
|
||||
) {
|
||||
this.currency$ = this.utilsService.currency$;
|
||||
this.statuses = this.utilsService.statuses;
|
||||
this.tripTableSearchInput.valueChanges
|
||||
.pipe(takeUntilDestroyed(), debounceTime(300))
|
||||
|
||||
@ -35,7 +35,7 @@
|
||||
|
||||
<span
|
||||
class="bg-gray-100 text-gray-800 text-xs md:text-sm font-medium me-2 px-2.5 py-0.5 rounded min-w-fit dark:bg-gray-400">{{
|
||||
(totalPrice | number:'1.0-2') || '-' }} {{ currency$ | async }}</span>
|
||||
(totalPrice | number:'1.0-2') || '-' }} @if (totalPrice) { {{ trip?.currency }} }</span>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@ -161,7 +161,7 @@
|
||||
</td>}
|
||||
@if (tripTableSelectedColumns.includes('price')) {<td class="truncate">@if (tripitem.price) {<span
|
||||
class="bg-gray-100 text-gray-800 text-sm font-medium me-2 px-2.5 py-0.5 rounded">{{
|
||||
tripitem.price }} {{ currency$ | async }}</span>}</td>}
|
||||
tripitem.price }} @if (tripitem.price) { {{ trip?.currency }} }</span>}</td>}
|
||||
@if (tripTableSelectedColumns.includes('status')) {<td class="truncate">@if (tripitem.status) {<span
|
||||
[style.background]="tripitem.status.color+'1A'" [style.color]="tripitem.status.color"
|
||||
class="text-xs font-medium me-2 px-2.5 py-0.5 rounded">{{
|
||||
@ -210,7 +210,7 @@
|
||||
</td>}
|
||||
@if (tripTableSelectedColumns.includes('price')) {<td class="truncate">@if (tripitem.price) {<span
|
||||
class="bg-gray-100 text-gray-800 text-sm font-medium me-2 px-2.5 py-0.5 rounded">{{
|
||||
tripitem.price }} {{ currency$ | async }}</span>}</td>}
|
||||
tripitem.price }} @if (tripitem.price) { {{ trip?.currency }} }</span>}</td>}
|
||||
@if (tripTableSelectedColumns.includes('status')) {<td class="truncate">@if (tripitem.status) {<span
|
||||
[style.background]="tripitem.status.color+'1A'" [style.color]="tripitem.status.color"
|
||||
class="text-xs font-medium me-2 px-2.5 py-0.5 rounded">{{
|
||||
@ -310,7 +310,8 @@
|
||||
@if (selectedItem.price) {
|
||||
<div class="rounded-md shadow p-4">
|
||||
<p class="font-bold mb-1">Price</p>
|
||||
<p class="text-sm text-gray-500">{{ selectedItem.price }} {{ currency$ | async }}</p>
|
||||
<p class="text-sm text-gray-500">{{ selectedItem.price }} @if (selectedItem.price) { {{ trip?.currency }} }
|
||||
</p>
|
||||
</div>
|
||||
}
|
||||
|
||||
@ -401,7 +402,7 @@
|
||||
<span
|
||||
class="bg-gray-100 text-gray-800 text-sm font-medium me-2 px-2.5 py-0.5 rounded dark:bg-gray-100/85">{{
|
||||
p.price || '-'
|
||||
}} {{ currency$ | async }}</span>
|
||||
}} @if (p.price) { {{ trip?.currency }} }</span>
|
||||
|
||||
@if (trip?.collaborators?.length) {
|
||||
<span class="bg-gray-100 text-gray-800 text-sm me-2 px-2.5 py-0.5 rounded dark:bg-gray-100/85">{{ p.user
|
||||
@ -454,7 +455,7 @@
|
||||
<div class="flex items-center gap-2 flex-none">
|
||||
<span
|
||||
class="bg-gray-100 text-gray-800 text-sm px-2.5 py-0.5 rounded-md min-w-fit group-hover:hidden dark:bg-gray-100/85">{{
|
||||
getDayStats(d).price || '-' }} {{ currency$ | async }}</span>
|
||||
getDayStats(d).price || '-' }} @if (getDayStats(d).price) { {{ trip?.currency }} }</span>
|
||||
<span
|
||||
class="bg-blue-100 text-blue-800 text-sm px-2.5 py-0.5 rounded-md group-hover:hidden dark:bg-blue-100/85">{{
|
||||
getDayStats(d).places }}</span>
|
||||
@ -649,7 +650,7 @@
|
||||
<div class="flex items-center gap-2">
|
||||
<span
|
||||
class="text-center bg-gray-100 text-gray-800 text-xs px-2.5 py-0.5 rounded-md group-hover:hidden dark:bg-gray-100/85">-
|
||||
{{ currency$ | async }}</span>
|
||||
{{ trip?.currency }}</span>
|
||||
|
||||
<div class="hidden shrink-0 sm:flex sm:flex-col sm:items-end">
|
||||
@if (!m.invited_at) {
|
||||
|
||||
@ -86,7 +86,6 @@ import { TripInviteMemberModalComponent } from "../../modals/trip-invite-member-
|
||||
styleUrls: ["./trip.component.scss"],
|
||||
})
|
||||
export class TripComponent implements AfterViewInit {
|
||||
currency$: Observable<string>;
|
||||
tripSharedURL$?: Observable<string>;
|
||||
statuses: TripStatus[] = [];
|
||||
trip?: Trip;
|
||||
@ -284,7 +283,6 @@ export class TripComponent implements AfterViewInit {
|
||||
private utilsService: UtilsService,
|
||||
private route: ActivatedRoute,
|
||||
) {
|
||||
this.currency$ = this.utilsService.currency$;
|
||||
this.statuses = this.utilsService.statuses;
|
||||
this.tripTableSearchInput.valueChanges
|
||||
.pipe(takeUntilDestroyed(), debounceTime(300))
|
||||
|
||||
@ -1,11 +1,16 @@
|
||||
<div pFocusTrap class="grid items-center gap-4" [formGroup]="tripForm">
|
||||
<p-floatlabel variant="in">
|
||||
<div pFocusTrap class="grid md:grid-cols-4 items-center gap-4" [formGroup]="tripForm">
|
||||
<p-floatlabel class="md:col-span-3" variant="in">
|
||||
<input id="name" formControlName="name" pInputText fluid (keyup.enter)="closeDialog()" />
|
||||
<label for="name">Name</label>
|
||||
</p-floatlabel>
|
||||
|
||||
<p-floatlabel variant="in">
|
||||
<input id="currency" formControlName="currency" pInputText fluid />
|
||||
<label for="currency">Currency</label>
|
||||
</p-floatlabel>
|
||||
|
||||
@if (tripForm.get("id")?.value === -1) {
|
||||
<div class="grid grid-cols-2 gap-2">
|
||||
<div class="grid md:col-span-4 grid-cols-2 gap-2">
|
||||
<p-floatlabel variant="in">
|
||||
<p-datepicker id="from" formControlName="from" [iconDisplay]="'input'" [showIcon]="true" appendTo="body" fluid />
|
||||
<label for="from">From</label>
|
||||
@ -18,7 +23,7 @@
|
||||
</div>
|
||||
}
|
||||
|
||||
<div class="grid place-items-center">
|
||||
<div class="md:col-span-4 grid place-items-center">
|
||||
@if (tripForm.get("image_id")?.value) {
|
||||
<div class="max-w-80 max-h-80 relative group cursor-pointer" (click)="fileInput.click()">
|
||||
<img [src]="tripForm.get('image')?.value"
|
||||
|
||||
@ -40,6 +40,7 @@ export class TripCreateModalComponent {
|
||||
id: -1,
|
||||
name: ["", Validators.required],
|
||||
image: "",
|
||||
currency: null,
|
||||
image_id: null,
|
||||
from: null,
|
||||
to: null,
|
||||
|
||||
@ -61,14 +61,4 @@ export class UtilsService {
|
||||
const latlng = `${latMatch[1]},${lngMatch[1]}`;
|
||||
return [place, latlng];
|
||||
}
|
||||
|
||||
static currencySigns(): { c: string; s: string }[] {
|
||||
return [
|
||||
{ c: "EUR", s: "€" },
|
||||
{ c: "GBP", s: "£" },
|
||||
{ c: "JPY", s: "¥" },
|
||||
{ c: "USD", s: "$" },
|
||||
{ c: "CHF", s: "CHF" },
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@ -77,7 +77,7 @@
|
||||
|
||||
<div class="flex flex-col mb-4">
|
||||
<span class="text-gray-500">Price</span>
|
||||
<span>{{ selectedPlace.price || '-' }} {{ currency$ | async }}</span>
|
||||
<span>{{ selectedPlace.price || '-' }} @if (selectedPlace.price) { {{ currency$ | async }} }</span>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col mb-4">
|
||||
|
||||
@ -8,6 +8,7 @@ export interface TripBase {
|
||||
user: string;
|
||||
days: number;
|
||||
collaborators: TripMember[];
|
||||
currency: string;
|
||||
}
|
||||
|
||||
export interface Trip {
|
||||
@ -18,6 +19,7 @@ export interface Trip {
|
||||
user: string;
|
||||
days: TripDay[];
|
||||
collaborators: TripMember[];
|
||||
currency: string;
|
||||
|
||||
// POST / PUT
|
||||
places: Place[];
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user