mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-21 22:46:32 +00:00
feat(collections): import a whole trip's places into a list (#1903)
* feat(collections): preview which of a trip's places a list already holds The bulk import endpoint has been there since the select-mode copy, but nothing calls it and it only reports duplicates after the fact. A dialog needs the verdict up front, so /:id/importable/:tripId returns the trip's places with the duplicate check the import itself applies, plus whether any day holds the place. * feat(collections): import a whole trip's places into a list Two steps: pick a trip, then tick its places. Places already on the list are greyed out and unpickable, and the ones no day holds start selected — those are the plans a trip left behind, which is the reason to import at all. Sorted so a mostly-saved trip reads as the two that are left rather than a wall of grey. * feat(collections): reach the trip import from the filter row and an empty list * i18n(collections): translate the trip import into all locales * fix(collections): stop the label dialog's buttons wrapping mid-word Three actions in a max-w-sm footer wrapped into two lines each. The assign button also painted white text on the accent, which disappears on a light one. * docs(collections): document the trip import
This commit is contained in:
@@ -314,3 +314,28 @@ export const collectionMembershipSchema = z.object({
|
||||
lists: z.array(z.object({ collection_id: z.number(), name: z.string(), place_id: z.number() })),
|
||||
});
|
||||
export type CollectionMembership = z.infer<typeof collectionMembershipSchema>;
|
||||
|
||||
/** One trip place as offered by the import preview. `already_in_list` is the SAME dedup
|
||||
* verdict the bulk import applies (name, or coordinates within tolerance), resolved on the
|
||||
* server so the dialog can never disagree with what the write path then does. `scheduled`
|
||||
* is false for a place no day holds — the ones a trip left behind, which is exactly what
|
||||
* the import is for, so the dialog pre-selects them. */
|
||||
export const collectionImportablePlaceSchema = z.object({
|
||||
place_id: z.number(),
|
||||
name: z.string(),
|
||||
address: z.string().nullable(),
|
||||
lat: z.number().nullable(),
|
||||
lng: z.number().nullable(),
|
||||
category_id: z.number().nullable(),
|
||||
image_url: z.string().nullable(),
|
||||
already_in_list: z.boolean(),
|
||||
scheduled: z.boolean(),
|
||||
day_number: z.number().nullable(),
|
||||
date: z.string().nullable(),
|
||||
});
|
||||
export type CollectionImportablePlace = z.infer<typeof collectionImportablePlaceSchema>;
|
||||
|
||||
export const collectionImportablesResponseSchema = z.object({
|
||||
places: z.array(collectionImportablePlaceSchema),
|
||||
});
|
||||
export type CollectionImportablesResponse = z.infer<typeof collectionImportablesResponseSchema>;
|
||||
|
||||
Reference in New Issue
Block a user