Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion app/Services/Trip/TripEditService.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,11 @@ public function updateTrip(Trip $trip, array $data): Trip
$attributes = [];

if (array_key_exists('category', $data)) {
$attributes['category'] = HafasTravelType::from($data['category']);
$category = HafasTravelType::from($data['category']);
$attributes['category'] = $category;
if ($category !== $trip->category) {
$attributes['mode'] = null;
}
}
if (array_key_exists('lineName', $data)) {
// Manual trips carry the line name in both fields //TODO: cleanup columns
Expand Down
2 changes: 2 additions & 0 deletions lang/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,7 @@
"generic.change": "Ändern",
"generic.error": "Fehler",
"generic.search": "Suchen",
"generic.unsaved": "Nicht gespeichert",
"generic.why": "Warum?",
"go-to-settings": "Zu den Einstellungen",
"help": "Hilfe",
Expand Down Expand Up @@ -1004,6 +1005,7 @@
"trip.edit.stopover-added": "Halt hinzugefügt.",
"trip.edit.stopover-deleted": "Halt gelöscht.",
"trip.edit.stopover-hint": "Die Reihenfolge der Halte ergibt sich aus den geplanten Zeiten. Änderungen berechnen Distanz und Punkte aller Check-ins dieser Fahrt neu.",
"trip.edit.stopover-in-use": "Dieser Halt wird von einem Check-in genutzt und kann nicht gelöscht werden. Passe zuerst den Check-in an.",
"trip.edit.stopovers-shifted": "Alle Halte wurden verschoben.",
"trip.edit.time-required": "Bitte gib mindestens eine geplante Ankunft oder Abfahrt an.",
"trip.edit.title": "Fahrt bearbeiten",
Expand Down
2 changes: 2 additions & 0 deletions lang/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,7 @@
"generic.change": "Change",
"generic.error": "Error",
"generic.search": "Search",
"generic.unsaved": "Unsaved",
"generic.why": "Why?",
"go-to-settings": "Go to settings",
"help": "Help",
Expand Down Expand Up @@ -1004,6 +1005,7 @@
"trip.edit.stopover-added": "Stopover added.",
"trip.edit.stopover-deleted": "Stopover deleted.",
"trip.edit.stopover-hint": "The order of the stopovers is derived from the planned times. Changes recalculate distance and points of all check-ins on this journey.",
"trip.edit.stopover-in-use": "This stop is used by a check-in and cannot be deleted. Change the check-in first.",
"trip.edit.stopovers-shifted": "All stopovers have been shifted.",
"trip.edit.time-required": "Please provide at least a planned arrival or departure.",
"trip.edit.title": "Edit journey",
Expand Down
2 changes: 2 additions & 0 deletions lang/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,7 @@
"generic.change": "Changer",
"generic.error": "Erreur",
"generic.search": "Recherche",
"generic.unsaved": "Non enregistré",
"generic.why": "Pourquoi ?",
"go-to-settings": "Vers les paramètres",
"help": "Aide",
Expand Down Expand Up @@ -1009,6 +1010,7 @@
"trip.edit.stopover-added": "Arrêt ajouté.",
"trip.edit.stopover-deleted": "Arrêt supprimé.",
"trip.edit.stopover-hint": "L’ordre des arrêts découle des horaires prévus. Les modifications recalculent la distance et les points de tous les enregistrements de ce trajet.",
"trip.edit.stopover-in-use": "Cet arrêt est utilisé par un check-in et ne peut pas être supprimé. Modifie d’abord le check-in.",
"trip.edit.stopovers-shifted": "Tous les arrêts ont été décalés.",
"trip.edit.time-required": "Merci d’indiquer au moins une arrivée ou un départ prévu.",
"trip.edit.title": "Modifier le trajet",
Expand Down
54 changes: 49 additions & 5 deletions resources/tailwind-app/components/Trip/StopoverEditor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ const arrivalPlatformReal = ref('');
const departurePlatformReal = ref('');
const cancelled = ref(false);

const syncedForm = ref('');

function toLocalInput(iso: string | null | undefined): string {
if (!iso) return '';
const dt = DateTime.fromISO(iso);
Expand All @@ -46,6 +48,23 @@ function toIso(local: string): string | null {
return dt.isValid ? dt.toISO() : null;
}

function formSnapshot(): string {
return JSON.stringify([
station.value?.uuid ?? null,
arrivalPlanned.value,
departurePlanned.value,
arrivalReal.value,
departureReal.value,
arrivalPlatformPlanned.value,
departurePlatformPlanned.value,
arrivalPlatformReal.value,
departurePlatformReal.value,
cancelled.value,
]);
}

const isDirty = computed((): boolean => formSnapshot() !== syncedForm.value);

function resetForm(): void {
station.value = props.stopover.station ?? null;
arrivalPlanned.value = toLocalInput(props.stopover.arrivalPlanned);
Expand All @@ -57,9 +76,30 @@ function resetForm(): void {
arrivalPlatformReal.value = props.stopover.arrivalPlatformReal ?? '';
departurePlatformReal.value = props.stopover.departurePlatformReal ?? '';
cancelled.value = props.stopover.cancelled ?? false;
syncedForm.value = formSnapshot();
}

watch(() => props.stopover, resetForm, { immediate: true });
resetForm();

watch(
() => props.stopover,
() => {
if (!isDirty.value) {
resetForm();
}
},
);

async function errorMessage(error: unknown, conflictMessage?: string): Promise<string> {
if (!(error instanceof Response)) {
return trans('generic.error');
}
if (error.status === 409 && conflictMessage) {
return conflictMessage;
}
const body = await error.json().catch(() => null);
return body?.message ?? trans('generic.error');
}

type TimeParts = { date: string; time: string };

Expand Down Expand Up @@ -102,9 +142,10 @@ async function save(): Promise<void> {
});
notyf?.success(trans('settings.saved'));
expanded.value = false;
syncedForm.value = formSnapshot();
emit('changed');
} catch {
notyf?.error(trans('generic.error'));
} catch (error) {
notyf?.error(await errorMessage(error));
} finally {
saving.value = false;
}
Expand All @@ -117,8 +158,8 @@ async function remove(): Promise<void> {
await api.trips.deleteTripStopover(props.tripUuid, props.stopover.uuid);
notyf?.success(trans('trip.edit.stopover-deleted'));
emit('changed');
} catch {
notyf?.error(trans('generic.error'));
} catch (error) {
notyf?.error(await errorMessage(error, trans('trip.edit.stopover-in-use')));
} finally {
deleting.value = false;
}
Expand Down Expand Up @@ -151,6 +192,9 @@ async function remove(): Promise<void> {
</span>
</span>
</span>
<span v-if="isDirty" class="badge badge-warning badge-sm">
{{ trans('generic.unsaved') }}
</span>
<span v-if="stopover.cancelled" class="badge badge-error badge-sm">
{{ trans('stationboard.stop-cancelled') }}
</span>
Expand Down
Loading