Import package tour activities and align day-indexed lodging scheduling
All checks were successful
Build and Push Image / docker-build-and-push (push) Successful in 2m22s
All checks were successful
Build and Push Image / docker-build-and-push (push) Successful in 2m22s
This commit is contained in:
@@ -474,6 +474,7 @@ export interface OperatorTourDayPlan {
|
|||||||
contact_number?: string | null;
|
contact_number?: string | null;
|
||||||
// Packing/todo fields
|
// Packing/todo fields
|
||||||
items_json?: string | null;
|
items_json?: string | null;
|
||||||
|
is_optional?: number | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function listPlansForOperatorTour(tourId: number): OperatorTourDayPlan[] {
|
export function listPlansForOperatorTour(tourId: number): OperatorTourDayPlan[] {
|
||||||
@@ -525,7 +526,8 @@ export function createOperatorTourDayPlan(
|
|||||||
end_time?: string | null;
|
end_time?: string | null;
|
||||||
end_timezone?: string | null;
|
end_timezone?: string | null;
|
||||||
},
|
},
|
||||||
checklistItemsJson?: string | null
|
checklistItemsJson?: string | null,
|
||||||
|
isOptional?: boolean
|
||||||
): OperatorTourDayPlan {
|
): OperatorTourDayPlan {
|
||||||
const maxPos = db.get<{ pos: number }>(
|
const maxPos = db.get<{ pos: number }>(
|
||||||
'SELECT COALESCE(MAX(position), -1) + 1 as pos FROM operator_tour_day_plans WHERE operator_tour_day_id = ?',
|
'SELECT COALESCE(MAX(position), -1) + 1 as pos FROM operator_tour_day_plans WHERE operator_tour_day_id = ?',
|
||||||
@@ -535,13 +537,14 @@ export function createOperatorTourDayPlan(
|
|||||||
|
|
||||||
const l = lodgingFields;
|
const l = lodgingFields;
|
||||||
const t = transportFields;
|
const t = transportFields;
|
||||||
let cols = 'operator_tour_day_id, type, title, notes, position';
|
let cols = 'operator_tour_day_id, type, title, notes, position, is_optional';
|
||||||
let vals: Array<string | number | null> = [
|
let vals: Array<string | number | null> = [
|
||||||
dayId,
|
dayId,
|
||||||
type,
|
type,
|
||||||
title.trim(),
|
title.trim(),
|
||||||
notes?.trim() || null,
|
notes?.trim() || null,
|
||||||
position
|
position,
|
||||||
|
isOptional ? 1 : 0
|
||||||
];
|
];
|
||||||
if (type === 'lodging' && l) {
|
if (type === 'lodging' && l) {
|
||||||
cols += ', chain, address_line1, address_line2, city_name, country, country_code, postal_code';
|
cols += ', chain, address_line1, address_line2, city_name, country, country_code, postal_code';
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ interface GAdventureComponent {
|
|||||||
end_location?: { id?: string; href?: string; name?: string };
|
end_location?: { id?: string; href?: string; name?: string };
|
||||||
accommodation_dossier?: { id: string; href: string; name: string };
|
accommodation_dossier?: { id: string; href: string; name: string };
|
||||||
transport_dossier?: { id: string; href: string; name: string };
|
transport_dossier?: { id: string; href: string; name: string };
|
||||||
|
activity_dossier?: { id?: string; href?: string; name?: string };
|
||||||
}
|
}
|
||||||
|
|
||||||
interface GAdventureItineraryDay {
|
interface GAdventureItineraryDay {
|
||||||
@@ -30,6 +31,9 @@ interface GAdventureItineraryDay {
|
|||||||
label?: string;
|
label?: string;
|
||||||
summary?: string;
|
summary?: string;
|
||||||
components?: GAdventureComponent[];
|
components?: GAdventureComponent[];
|
||||||
|
optional_activities?: Array<{
|
||||||
|
activity_dossier?: { id?: string; href?: string; name?: string };
|
||||||
|
}>;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Accommodation dossier detail response (from following accommodation_dossier href)
|
// Accommodation dossier detail response (from following accommodation_dossier href)
|
||||||
@@ -160,11 +164,30 @@ async function dayPlansFromComponents(components: GAdventureComponent[]): Promis
|
|||||||
if (details) lodgingFields = lodgingFieldsFromDossier(details);
|
if (details) lodgingFields = lodgingFieldsFromDossier(details);
|
||||||
}
|
}
|
||||||
plans.push({ type: 'lodging', title, notes: notes ?? undefined, lodgingFields });
|
plans.push({ type: 'lodging', title, notes: notes ?? undefined, lodgingFields });
|
||||||
|
} else if (type === 'ACTIVITY') {
|
||||||
|
const title = c.activity_dossier?.name?.trim() || c.summary?.trim() || 'Activity';
|
||||||
|
const notes = c.summary?.trim() || null;
|
||||||
|
plans.push({ type: 'activity', title, notes: notes ?? undefined, isOptional: false });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return plans;
|
return plans;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function optionalActivityPlansFromDay(day: GAdventureItineraryDay): TourDayPlan[] {
|
||||||
|
const plans: TourDayPlan[] = [];
|
||||||
|
for (const opt of day.optional_activities ?? []) {
|
||||||
|
const title = opt.activity_dossier?.name?.trim();
|
||||||
|
if (!title) continue;
|
||||||
|
plans.push({
|
||||||
|
type: 'activity',
|
||||||
|
title,
|
||||||
|
notes: 'Optional activity',
|
||||||
|
isOptional: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return plans;
|
||||||
|
}
|
||||||
|
|
||||||
export const GAdventuresProvider: TourProvider = {
|
export const GAdventuresProvider: TourProvider = {
|
||||||
name: 'G Adventures',
|
name: 'G Adventures',
|
||||||
|
|
||||||
@@ -203,7 +226,9 @@ export const GAdventuresProvider: TourProvider = {
|
|||||||
const days: TourDay[] = [];
|
const days: TourDay[] = [];
|
||||||
|
|
||||||
for (const d of rawDays) {
|
for (const d of rawDays) {
|
||||||
const dayPlans = await dayPlansFromComponents(d.components ?? []);
|
const includedDayPlans = await dayPlansFromComponents(d.components ?? []);
|
||||||
|
const optionalActivityPlans = optionalActivityPlansFromDay(d);
|
||||||
|
const dayPlans = [...includedDayPlans, ...optionalActivityPlans];
|
||||||
days.push({
|
days.push({
|
||||||
dayNumber: d.day,
|
dayNumber: d.day,
|
||||||
title: d.label ?? '',
|
title: d.label ?? '',
|
||||||
|
|||||||
@@ -31,9 +31,10 @@ export interface TourDayPlanTransportFields {
|
|||||||
|
|
||||||
/** A transport or lodging plan attached to a day (from provider components) */
|
/** A transport or lodging plan attached to a day (from provider components) */
|
||||||
export interface TourDayPlan {
|
export interface TourDayPlan {
|
||||||
type: 'transport' | 'lodging';
|
type: 'transport' | 'lodging' | 'activity';
|
||||||
title: string;
|
title: string;
|
||||||
notes?: string | null;
|
notes?: string | null;
|
||||||
|
isOptional?: boolean;
|
||||||
/** When type is 'lodging', structured address/location from provider */
|
/** When type is 'lodging', structured address/location from provider */
|
||||||
lodgingFields?: TourDayPlanLodgingFields;
|
lodgingFields?: TourDayPlanLodgingFields;
|
||||||
/** When type is 'transport', structured movement details from provider */
|
/** When type is 'transport', structured movement details from provider */
|
||||||
|
|||||||
@@ -507,7 +507,8 @@ export function runMigrations(db: Database): void {
|
|||||||
website TEXT,
|
website TEXT,
|
||||||
address TEXT,
|
address TEXT,
|
||||||
contact_number TEXT,
|
contact_number TEXT,
|
||||||
items_json TEXT
|
items_json TEXT,
|
||||||
|
is_optional INTEGER NOT NULL DEFAULT 0
|
||||||
)
|
)
|
||||||
`);
|
`);
|
||||||
db.run(`
|
db.run(`
|
||||||
@@ -515,13 +516,13 @@ export function runMigrations(db: Database): void {
|
|||||||
id, operator_tour_day_id, type, title, notes, position, created_at, updated_at,
|
id, operator_tour_day_id, type, title, notes, position, created_at, updated_at,
|
||||||
chain, address_line1, address_line2, city_name, country, country_code, postal_code,
|
chain, address_line1, address_line2, city_name, country, country_code, postal_code,
|
||||||
transport_kind, start_date, start_time, start_timezone, end_date, end_time, end_timezone,
|
transport_kind, start_date, start_time, start_timezone, end_date, end_time, end_timezone,
|
||||||
start_location, end_location
|
start_location, end_location, is_optional
|
||||||
)
|
)
|
||||||
SELECT
|
SELECT
|
||||||
id, operator_tour_day_id, type, title, notes, position, created_at, updated_at,
|
id, operator_tour_day_id, type, title, notes, position, created_at, updated_at,
|
||||||
chain, address_line1, address_line2, city_name, country, country_code, postal_code,
|
chain, address_line1, address_line2, city_name, country, country_code, postal_code,
|
||||||
transport_kind, start_date, start_time, start_timezone, end_date, end_time, end_timezone,
|
transport_kind, start_date, start_time, start_timezone, end_date, end_time, end_timezone,
|
||||||
NULL as start_location, NULL as end_location
|
NULL as start_location, NULL as end_location, 0 as is_optional
|
||||||
FROM operator_tour_day_plans
|
FROM operator_tour_day_plans
|
||||||
`);
|
`);
|
||||||
db.run('DROP TABLE operator_tour_day_plans');
|
db.run('DROP TABLE operator_tour_day_plans');
|
||||||
@@ -555,7 +556,8 @@ export function runMigrations(db: Database): void {
|
|||||||
'website TEXT',
|
'website TEXT',
|
||||||
'address TEXT',
|
'address TEXT',
|
||||||
'contact_number TEXT',
|
'contact_number TEXT',
|
||||||
'items_json TEXT'
|
'items_json TEXT',
|
||||||
|
'is_optional INTEGER NOT NULL DEFAULT 0'
|
||||||
]) {
|
]) {
|
||||||
try {
|
try {
|
||||||
db.run(`ALTER TABLE operator_tour_day_plans ADD COLUMN ${col}`);
|
db.run(`ALTER TABLE operator_tour_day_plans ADD COLUMN ${col}`);
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { createPlan } from './plans.js';
|
|||||||
import { createOtherTransport } from './other-transports.js';
|
import { createOtherTransport } from './other-transports.js';
|
||||||
import { createExperience } from './experiences.js';
|
import { createExperience } from './experiences.js';
|
||||||
import { createChecklist } from './checklists.js';
|
import { createChecklist } from './checklists.js';
|
||||||
|
import { createLodging } from './lodgings.js';
|
||||||
import { listDaysForOperatorTour, listPlansForOperatorTour } from './admin/data.js';
|
import { listDaysForOperatorTour, listPlansForOperatorTour } from './admin/data.js';
|
||||||
|
|
||||||
export interface PackageTour {
|
export interface PackageTour {
|
||||||
@@ -308,6 +309,12 @@ export function updateTourDay(input: {
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function addDaysToDate(date: string, offset: number): string {
|
||||||
|
const [year, month, day] = date.split('-').map(Number);
|
||||||
|
const ts = Date.UTC(year, month - 1, day + offset);
|
||||||
|
return new Date(ts).toISOString().slice(0, 10);
|
||||||
|
}
|
||||||
|
|
||||||
export function cloneTemplateDaysToTour(input: {
|
export function cloneTemplateDaysToTour(input: {
|
||||||
operatorTourId: number;
|
operatorTourId: number;
|
||||||
tripId: string;
|
tripId: string;
|
||||||
@@ -316,7 +323,13 @@ export function cloneTemplateDaysToTour(input: {
|
|||||||
}): void {
|
}): void {
|
||||||
const days = listDaysForOperatorTour(input.operatorTourId);
|
const days = listDaysForOperatorTour(input.operatorTourId);
|
||||||
const allDayPlans = listPlansForOperatorTour(input.operatorTourId);
|
const allDayPlans = listPlansForOperatorTour(input.operatorTourId);
|
||||||
|
const tourStartDate =
|
||||||
|
db.get<{ start_date: string | null }>(
|
||||||
|
'SELECT start_date FROM package_tours WHERE plan_id = ?',
|
||||||
|
[input.tourPlanId]
|
||||||
|
)?.start_date ?? null;
|
||||||
for (const day of days) {
|
for (const day of days) {
|
||||||
|
const dayDate = tourStartDate ? addDaysToDate(tourStartDate, day.day_number - 1) : null;
|
||||||
const newDay = createTourDay({
|
const newDay = createTourDay({
|
||||||
tripId: input.tripId,
|
tripId: input.tripId,
|
||||||
userId: input.userId,
|
userId: input.userId,
|
||||||
@@ -331,7 +344,7 @@ export function cloneTemplateDaysToTour(input: {
|
|||||||
tripId: input.tripId,
|
tripId: input.tripId,
|
||||||
userId: input.userId,
|
userId: input.userId,
|
||||||
parentId: newDay.plan_id,
|
parentId: newDay.plan_id,
|
||||||
status: 'idea',
|
status: dp.is_optional ? 'idea' : 'confirmed',
|
||||||
title: dp.title,
|
title: dp.title,
|
||||||
notes: dp.notes ?? undefined,
|
notes: dp.notes ?? undefined,
|
||||||
startDate: dp.start_date ?? undefined,
|
startDate: dp.start_date ?? undefined,
|
||||||
@@ -350,7 +363,7 @@ export function cloneTemplateDaysToTour(input: {
|
|||||||
type: dp.type,
|
type: dp.type,
|
||||||
name: dp.title,
|
name: dp.title,
|
||||||
parentId: newDay.plan_id,
|
parentId: newDay.plan_id,
|
||||||
status: 'idea',
|
status: dp.type === 'activity' ? (dp.is_optional ? 'idea' : 'confirmed') : 'idea',
|
||||||
bookingId: dp.booking_id ?? undefined,
|
bookingId: dp.booking_id ?? undefined,
|
||||||
totalCost: dp.total_cost ?? undefined,
|
totalCost: dp.total_cost ?? undefined,
|
||||||
description: dp.description ?? dp.notes ?? undefined,
|
description: dp.description ?? dp.notes ?? undefined,
|
||||||
@@ -364,6 +377,27 @@ export function cloneTemplateDaysToTour(input: {
|
|||||||
endTime: dp.end_time ?? undefined,
|
endTime: dp.end_time ?? undefined,
|
||||||
endTimezone: dp.end_timezone ?? undefined
|
endTimezone: dp.end_timezone ?? undefined
|
||||||
});
|
});
|
||||||
|
} else if (dp.type === 'lodging') {
|
||||||
|
createLodging({
|
||||||
|
tripId: input.tripId,
|
||||||
|
userId: input.userId,
|
||||||
|
parentId: newDay.plan_id,
|
||||||
|
status: dp.is_optional ? 'idea' : 'confirmed',
|
||||||
|
name: dp.title,
|
||||||
|
chain: dp.chain ?? undefined,
|
||||||
|
checkInDate: dp.start_date ?? dayDate ?? undefined,
|
||||||
|
checkInTime: dp.start_time ?? undefined,
|
||||||
|
checkInTimezone: dp.start_timezone ?? undefined,
|
||||||
|
checkOutDate: dp.end_date ?? dayDate ?? undefined,
|
||||||
|
checkOutTime: dp.end_time ?? undefined,
|
||||||
|
checkOutTimezone: dp.end_timezone ?? undefined,
|
||||||
|
addressLine1: dp.address_line1 ?? undefined,
|
||||||
|
addressLine2: dp.address_line2 ?? undefined,
|
||||||
|
cityName: dp.city_name ?? undefined,
|
||||||
|
country: dp.country ?? undefined,
|
||||||
|
countryCode: dp.country_code ?? undefined,
|
||||||
|
postalCode: dp.postal_code ?? undefined
|
||||||
|
});
|
||||||
} else if (dp.type === 'packing' || dp.type === 'todo') {
|
} else if (dp.type === 'packing' || dp.type === 'todo') {
|
||||||
let items: string[] = [];
|
let items: string[] = [];
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -101,9 +101,10 @@ export const actions: Actions = {
|
|||||||
title: string;
|
title: string;
|
||||||
description: string;
|
description: string;
|
||||||
dayPlans?: Array<{
|
dayPlans?: Array<{
|
||||||
type: 'transport' | 'lodging';
|
type: 'transport' | 'lodging' | 'activity';
|
||||||
title: string;
|
title: string;
|
||||||
notes?: string | null;
|
notes?: string | null;
|
||||||
|
isOptional?: boolean;
|
||||||
lodgingFields?: {
|
lodgingFields?: {
|
||||||
chain?: string | null;
|
chain?: string | null;
|
||||||
address_line1?: string | null;
|
address_line1?: string | null;
|
||||||
@@ -151,7 +152,10 @@ export const actions: Actions = {
|
|||||||
plan.title,
|
plan.title,
|
||||||
plan.notes ?? undefined,
|
plan.notes ?? undefined,
|
||||||
plan.type === 'lodging' && plan.lodgingFields ? plan.lodgingFields : undefined,
|
plan.type === 'lodging' && plan.lodgingFields ? plan.lodgingFields : undefined,
|
||||||
plan.type === 'transport' && plan.transportFields ? plan.transportFields : undefined
|
plan.type === 'transport' && plan.transportFields ? plan.transportFields : undefined,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
plan.isOptional ?? false
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -304,18 +304,18 @@
|
|||||||
? { start: tripDates[dayIndex], end: tripDates[dayIndex] }
|
? { start: tripDates[dayIndex], end: tripDates[dayIndex] }
|
||||||
: null
|
: null
|
||||||
: scheduleView === 'week'
|
: scheduleView === 'week'
|
||||||
? weekRanges[weekIndex] ?? null
|
? (weekRanges[weekIndex] ?? null)
|
||||||
: null
|
: null
|
||||||
);
|
);
|
||||||
|
|
||||||
const filteredTimeline = $derived(
|
const filteredTimeline = $derived(
|
||||||
currentRange
|
currentRange
|
||||||
? {
|
? {
|
||||||
scheduled: timeline.scheduled.filter(
|
scheduled: timeline.scheduled.filter(
|
||||||
(group) => group.date >= currentRange.start && group.date <= currentRange.end
|
(group) => group.date >= currentRange.start && group.date <= currentRange.end
|
||||||
),
|
),
|
||||||
unscheduled: []
|
unscheduled: []
|
||||||
}
|
}
|
||||||
: timeline
|
: timeline
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -357,9 +357,7 @@
|
|||||||
);
|
);
|
||||||
|
|
||||||
const visibleLodgings = $derived(
|
const visibleLodgings = $derived(
|
||||||
filteredPlanIds
|
filteredPlanIds ? lodgings.filter((lodging) => filteredPlanIds.has(lodging.plan_id)) : lodgings
|
||||||
? lodgings.filter((lodging) => filteredPlanIds.has(lodging.plan_id))
|
|
||||||
: lodgings
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const visibleActivities = $derived(
|
const visibleActivities = $derived(
|
||||||
@@ -868,7 +866,7 @@
|
|||||||
{#if scheduleView === 'day' && tripDates.length > 1}
|
{#if scheduleView === 'day' && tripDates.length > 1}
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="absolute left-3 top-1/2 -translate-y-1/2 rounded-md border border-gray-200 px-2 py-1 text-xs text-gray-500 hover:bg-gray-50 disabled:cursor-not-allowed disabled:opacity-40"
|
class="absolute top-1/2 left-3 -translate-y-1/2 rounded-md border border-gray-200 px-2 py-1 text-xs text-gray-500 hover:bg-gray-50 disabled:cursor-not-allowed disabled:opacity-40"
|
||||||
onclick={() => (dayIndex = Math.max(0, dayIndex - 1))}
|
onclick={() => (dayIndex = Math.max(0, dayIndex - 1))}
|
||||||
disabled={dayIndex === 0}
|
disabled={dayIndex === 0}
|
||||||
aria-label="Previous day"
|
aria-label="Previous day"
|
||||||
@@ -879,7 +877,7 @@
|
|||||||
{#if scheduleView === 'week' && weekRanges.length > 1}
|
{#if scheduleView === 'week' && weekRanges.length > 1}
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="absolute left-3 top-1/2 -translate-y-1/2 rounded-md border border-gray-200 px-2 py-1 text-xs text-gray-500 hover:bg-gray-50 disabled:cursor-not-allowed disabled:opacity-40"
|
class="absolute top-1/2 left-3 -translate-y-1/2 rounded-md border border-gray-200 px-2 py-1 text-xs text-gray-500 hover:bg-gray-50 disabled:cursor-not-allowed disabled:opacity-40"
|
||||||
onclick={() => (weekIndex = Math.max(0, weekIndex - 1))}
|
onclick={() => (weekIndex = Math.max(0, weekIndex - 1))}
|
||||||
disabled={weekIndex === 0}
|
disabled={weekIndex === 0}
|
||||||
aria-label="Previous week"
|
aria-label="Previous week"
|
||||||
@@ -905,7 +903,7 @@
|
|||||||
{#if scheduleView === 'day' && tripDates.length > 1}
|
{#if scheduleView === 'day' && tripDates.length > 1}
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="absolute right-3 top-1/2 -translate-y-1/2 rounded-md border border-gray-200 px-2 py-1 text-xs text-gray-500 hover:bg-gray-50 disabled:cursor-not-allowed disabled:opacity-40"
|
class="absolute top-1/2 right-3 -translate-y-1/2 rounded-md border border-gray-200 px-2 py-1 text-xs text-gray-500 hover:bg-gray-50 disabled:cursor-not-allowed disabled:opacity-40"
|
||||||
onclick={() => (dayIndex = Math.min(tripDates.length - 1, dayIndex + 1))}
|
onclick={() => (dayIndex = Math.min(tripDates.length - 1, dayIndex + 1))}
|
||||||
disabled={dayIndex >= tripDates.length - 1}
|
disabled={dayIndex >= tripDates.length - 1}
|
||||||
aria-label="Next day"
|
aria-label="Next day"
|
||||||
@@ -916,7 +914,7 @@
|
|||||||
{#if scheduleView === 'week' && weekRanges.length > 1}
|
{#if scheduleView === 'week' && weekRanges.length > 1}
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="absolute right-3 top-1/2 -translate-y-1/2 rounded-md border border-gray-200 px-2 py-1 text-xs text-gray-500 hover:bg-gray-50 disabled:cursor-not-allowed disabled:opacity-40"
|
class="absolute top-1/2 right-3 -translate-y-1/2 rounded-md border border-gray-200 px-2 py-1 text-xs text-gray-500 hover:bg-gray-50 disabled:cursor-not-allowed disabled:opacity-40"
|
||||||
onclick={() => (weekIndex = Math.min(weekRanges.length - 1, weekIndex + 1))}
|
onclick={() => (weekIndex = Math.min(weekRanges.length - 1, weekIndex + 1))}
|
||||||
disabled={weekIndex >= weekRanges.length - 1}
|
disabled={weekIndex >= weekRanges.length - 1}
|
||||||
aria-label="Next week"
|
aria-label="Next week"
|
||||||
@@ -1270,6 +1268,26 @@
|
|||||||
onDelete={submitForm}
|
onDelete={submitForm}
|
||||||
/>
|
/>
|
||||||
</form>
|
</form>
|
||||||
|
{:else}
|
||||||
|
{@const formId = `remove-plan-timeline-${plan.id}`}
|
||||||
|
{@const submitForm = () => {
|
||||||
|
const form = document.getElementById(formId) as HTMLFormElement;
|
||||||
|
form?.requestSubmit();
|
||||||
|
}}
|
||||||
|
<form
|
||||||
|
id={formId}
|
||||||
|
method="POST"
|
||||||
|
action="?/removePlan"
|
||||||
|
use:enhance={() => {
|
||||||
|
return ({ update }) => {
|
||||||
|
update();
|
||||||
|
};
|
||||||
|
}}
|
||||||
|
class="contents"
|
||||||
|
>
|
||||||
|
<input type="hidden" name="plan_id" value={plan.id} />
|
||||||
|
<PlanCard {plan} onDelete={submitForm} />
|
||||||
|
</form>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -1288,8 +1306,8 @@
|
|||||||
<div class="h-px flex-1 bg-gray-200"></div>
|
<div class="h-px flex-1 bg-gray-200"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-4 flex flex-col gap-4">
|
<div class="mt-4 flex flex-col gap-4">
|
||||||
{#each filteredTimeline.unscheduled as entry (entry.id)}
|
{#each filteredTimeline.unscheduled as entry (entry.id)}
|
||||||
{#if entry.kind === 'day'}
|
{#if entry.kind === 'day'}
|
||||||
<div
|
<div
|
||||||
class="rounded-lg border border-gray-200 bg-gray-50 px-4 py-2"
|
class="rounded-lg border border-gray-200 bg-gray-50 px-4 py-2"
|
||||||
style="border-left: 4px solid {entry.tour.highlightColor ?? '#E5E7EB'}"
|
style="border-left: 4px solid {entry.tour.highlightColor ?? '#E5E7EB'}"
|
||||||
@@ -1597,6 +1615,26 @@
|
|||||||
onDelete={submitForm}
|
onDelete={submitForm}
|
||||||
/>
|
/>
|
||||||
</form>
|
</form>
|
||||||
|
{:else}
|
||||||
|
{@const formId = `remove-plan-timeline-${plan.id}`}
|
||||||
|
{@const submitForm = () => {
|
||||||
|
const form = document.getElementById(formId) as HTMLFormElement;
|
||||||
|
form?.requestSubmit();
|
||||||
|
}}
|
||||||
|
<form
|
||||||
|
id={formId}
|
||||||
|
method="POST"
|
||||||
|
action="?/removePlan"
|
||||||
|
use:enhance={() => {
|
||||||
|
return ({ update }) => {
|
||||||
|
update();
|
||||||
|
};
|
||||||
|
}}
|
||||||
|
class="contents"
|
||||||
|
>
|
||||||
|
<input type="hidden" name="plan_id" value={plan.id} />
|
||||||
|
<PlanCard {plan} onDelete={submitForm} />
|
||||||
|
</form>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -1674,20 +1712,20 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Transportation section -->
|
<!-- Transportation section -->
|
||||||
{#if
|
{#if visibleFlightBookings.length > 0 || visiblePrivateVehicles.length > 0 || visibleOtherTransports.length > 0}
|
||||||
visibleFlightBookings.length > 0 ||
|
|
||||||
visiblePrivateVehicles.length > 0 ||
|
|
||||||
visibleOtherTransports.length > 0
|
|
||||||
}
|
|
||||||
<div class="mt-8">
|
<div class="mt-8">
|
||||||
<h2 class="mb-3 text-sm font-semibold tracking-wider text-gray-400 uppercase">
|
<h2 class="mb-3 text-sm font-semibold tracking-wider text-gray-400 uppercase">
|
||||||
Transportation
|
Transportation
|
||||||
</h2>
|
</h2>
|
||||||
<div class="flex flex-col gap-3">
|
<div class="flex flex-col gap-3">
|
||||||
{#each visiblePlans.filter((p) => p.type === 'transport') as plan (plan.id)}
|
{#each visiblePlans.filter((p) => p.type === 'transport') as plan (plan.id)}
|
||||||
{@const flightBooking = visibleFlightBookings.find((b) => b.plan_id === plan.id)}
|
{@const flightBooking = visibleFlightBookings.find((b) => b.plan_id === plan.id)}
|
||||||
{@const privateVehicle = visiblePrivateVehicles.find((pv) => pv.plan_id === plan.id)}
|
{@const privateVehicle = visiblePrivateVehicles.find(
|
||||||
{@const otherTransport = visibleOtherTransports.find((ot) => ot.plan_id === plan.id)}
|
(pv) => pv.plan_id === plan.id
|
||||||
|
)}
|
||||||
|
{@const otherTransport = visibleOtherTransports.find(
|
||||||
|
(ot) => ot.plan_id === plan.id
|
||||||
|
)}
|
||||||
{@const packageTourContext = byTypeTourContextByPlanId.get(plan.id)}
|
{@const packageTourContext = byTypeTourContextByPlanId.get(plan.id)}
|
||||||
{#if plan}
|
{#if plan}
|
||||||
{@const formId = `remove-plan-${plan.id}`}
|
{@const formId = `remove-plan-${plan.id}`}
|
||||||
@@ -1795,8 +1833,8 @@
|
|||||||
Attractions & Activities
|
Attractions & Activities
|
||||||
</h2>
|
</h2>
|
||||||
<div class="flex flex-col gap-3">
|
<div class="flex flex-col gap-3">
|
||||||
{#each visibleActivities as activity (activity.id)}
|
{#each visibleActivities as activity (activity.id)}
|
||||||
{@const plan = visiblePlans.find((p) => p.id === activity.plan_id)}
|
{@const plan = visiblePlans.find((p) => p.id === activity.plan_id)}
|
||||||
{#if plan}
|
{#if plan}
|
||||||
{@const formId = `remove-plan-${plan.id}`}
|
{@const formId = `remove-plan-${plan.id}`}
|
||||||
{@const packageTourContext = byTypeTourContextByPlanId.get(plan.id)}
|
{@const packageTourContext = byTypeTourContextByPlanId.get(plan.id)}
|
||||||
@@ -1871,8 +1909,8 @@
|
|||||||
Restaurants
|
Restaurants
|
||||||
</h2>
|
</h2>
|
||||||
<div class="flex flex-col gap-3">
|
<div class="flex flex-col gap-3">
|
||||||
{#each visibleRestaurants as restaurant (restaurant.id)}
|
{#each visibleRestaurants as restaurant (restaurant.id)}
|
||||||
{@const plan = visiblePlans.find((p) => p.id === restaurant.plan_id)}
|
{@const plan = visiblePlans.find((p) => p.id === restaurant.plan_id)}
|
||||||
{#if plan}
|
{#if plan}
|
||||||
{@const formId = `remove-plan-${plan.id}`}
|
{@const formId = `remove-plan-${plan.id}`}
|
||||||
{@const packageTourContext = byTypeTourContextByPlanId.get(plan.id)}
|
{@const packageTourContext = byTypeTourContextByPlanId.get(plan.id)}
|
||||||
@@ -1947,8 +1985,8 @@
|
|||||||
Packing Lists
|
Packing Lists
|
||||||
</h2>
|
</h2>
|
||||||
<div class="flex flex-col gap-3">
|
<div class="flex flex-col gap-3">
|
||||||
{#each visiblePackingLists as list (list.id)}
|
{#each visiblePackingLists as list (list.id)}
|
||||||
{@const plan = visiblePlans.find((p) => p.id === list.plan_id)}
|
{@const plan = visiblePlans.find((p) => p.id === list.plan_id)}
|
||||||
{#if plan}
|
{#if plan}
|
||||||
{@const formId = `remove-plan-${plan.id}`}
|
{@const formId = `remove-plan-${plan.id}`}
|
||||||
{@const submitForm = () => {
|
{@const submitForm = () => {
|
||||||
@@ -1988,8 +2026,8 @@
|
|||||||
To-dos
|
To-dos
|
||||||
</h2>
|
</h2>
|
||||||
<div class="flex flex-col gap-3">
|
<div class="flex flex-col gap-3">
|
||||||
{#each visibleTodos as list (list.id)}
|
{#each visibleTodos as list (list.id)}
|
||||||
{@const plan = visiblePlans.find((p) => p.id === list.plan_id)}
|
{@const plan = visiblePlans.find((p) => p.id === list.plan_id)}
|
||||||
{#if plan}
|
{#if plan}
|
||||||
{@const formId = `remove-plan-${plan.id}`}
|
{@const formId = `remove-plan-${plan.id}`}
|
||||||
{@const submitForm = () => {
|
{@const submitForm = () => {
|
||||||
@@ -2029,8 +2067,8 @@
|
|||||||
Lodgings
|
Lodgings
|
||||||
</h2>
|
</h2>
|
||||||
<div class="flex flex-col gap-3">
|
<div class="flex flex-col gap-3">
|
||||||
{#each visibleLodgings as lodging (lodging.id)}
|
{#each visibleLodgings as lodging (lodging.id)}
|
||||||
{@const plan = visiblePlans.find((p) => p.id === lodging.plan_id)}
|
{@const plan = visiblePlans.find((p) => p.id === lodging.plan_id)}
|
||||||
{#if plan}
|
{#if plan}
|
||||||
{@const formId = `remove-plan-${plan.id}`}
|
{@const formId = `remove-plan-${plan.id}`}
|
||||||
{@const packageTourContext = byTypeTourContextByPlanId.get(plan.id)}
|
{@const packageTourContext = byTypeTourContextByPlanId.get(plan.id)}
|
||||||
@@ -2105,8 +2143,8 @@
|
|||||||
Package Tours
|
Package Tours
|
||||||
</h2>
|
</h2>
|
||||||
<div class="flex flex-col gap-3">
|
<div class="flex flex-col gap-3">
|
||||||
{#each visiblePackageTours as tour (tour.id)}
|
{#each visiblePackageTours as tour (tour.id)}
|
||||||
{@const plan = visiblePlans.find((p) => p.id === tour.plan_id)}
|
{@const plan = visiblePlans.find((p) => p.id === tour.plan_id)}
|
||||||
{#if plan}
|
{#if plan}
|
||||||
{@const formId = `remove-plan-${plan.id}`}
|
{@const formId = `remove-plan-${plan.id}`}
|
||||||
{@const submitForm = () => {
|
{@const submitForm = () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user