mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-11-14 08:11:03 +00:00
fix(planner): a place added from a collection keeps its category (#3074)
The place form guessed the category of a picked place from its kind, so a place taken from a collection inside a trip lost the category it was saved under, while adding it from the collection kept it. A picked place that carries a category this server has now brings it along; a category chosen in the form by hand still wins.
This commit is contained in:
@@ -410,3 +410,15 @@ export function formPin(form: Pick<PlaceFormData, 'lat' | 'lng'>): { lat: number
|
||||
if (!Number.isFinite(lat) || !Number.isFinite(lng) || Math.abs(lat) > 90 || Math.abs(lng) > 180) return null
|
||||
return { lat, lng }
|
||||
}
|
||||
|
||||
/**
|
||||
* The category a picked place already carries, as the form's value, when this server
|
||||
* has it. A place saved in a collection keeps its category_id, and categories are the
|
||||
* server's own, so it fits the trip as it stands. Guessing from the place's kind
|
||||
* instead dropped it (#3074).
|
||||
*/
|
||||
export function savedCategoryId(result: Record<string, unknown>, categories: readonly { id: number }[]): string | null {
|
||||
const id = result.category_id
|
||||
if (typeof id !== 'number') return null
|
||||
return categories.some(c => c.id === id) ? String(id) : null
|
||||
}
|
||||
|
||||
@@ -2378,6 +2378,36 @@ describe('PlaceFormModal on the dialog frame', () => {
|
||||
expect(onClose).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('FE-PLANNER-PLACEFORM-125: a place picked from a collection keeps the category it was saved under (#3074)', async () => {
|
||||
withCollections();
|
||||
vi.spyOn(collectionsApi, 'get').mockResolvedValue({
|
||||
collection: { id: 1, owner_id: 1, name: 'Tokyo 2026', color: '#ec4899' },
|
||||
places: [
|
||||
{
|
||||
id: 10,
|
||||
collection_id: 1,
|
||||
name: 'Zebra Cafe',
|
||||
status: 'idea',
|
||||
lat: 35.66,
|
||||
lng: 139.7,
|
||||
category_id: 7,
|
||||
category: { id: 7, name: 'Must see', color: '#f59e0b', icon: 'Star' },
|
||||
},
|
||||
],
|
||||
});
|
||||
const onSave = vi.fn().mockResolvedValue(undefined);
|
||||
// A cafe saved as "Must see": the guess from its kind would be the cafe category.
|
||||
const categories = [
|
||||
{ id: 3, name: 'Cafe', color: '#7c3aed', icon: 'Coffee' },
|
||||
{ id: 7, name: 'Must see', color: '#f59e0b', icon: 'Star' },
|
||||
];
|
||||
render(<PlaceFormModal {...defaultProps} categories={categories} onSave={onSave} />);
|
||||
fireEvent.click(await screen.findByText('Zebra Cafe'));
|
||||
fireEvent.click(screen.getByRole('button', { name: /^Add$/i }));
|
||||
await waitFor(() => expect(onSave).toHaveBeenCalled());
|
||||
expect(onSave).toHaveBeenCalledWith(expect.objectContaining({ name: 'Zebra Cafe', category_id: '7' }));
|
||||
});
|
||||
|
||||
it('FE-PLANNER-PLACEFORM-099: Escape with nothing open closes the dialog', () => {
|
||||
const onClose = vi.fn();
|
||||
render(<PlaceFormModal {...defaultProps} onClose={onClose} />);
|
||||
|
||||
@@ -19,7 +19,7 @@ import { weekFromPeriods } from './placeHours'
|
||||
import type { PlaceOpeningHours } from '@trek/shared'
|
||||
import {
|
||||
DEFAULT_FORM, endsBeforeStart, findDuplicatePlace, formPin, mergeResult, parseCoordinatePair, placeEditForm, placeFormPayload,
|
||||
prefillForm, type PlaceFormData, type PlacePrefill,
|
||||
prefillForm, savedCategoryId, type PlaceFormData, type PlacePrefill,
|
||||
} from './PlaceFormModal.helpers'
|
||||
import { useNewCategory, usePlaceForm } from './usePlaceForm'
|
||||
import { usePlaceSearch } from './usePlaceSearch'
|
||||
@@ -233,6 +233,12 @@ function usePlaceFormModal(props: PlaceFormModalProps) {
|
||||
setForm(prev => {
|
||||
const merged = mergeResult(prev, result, autoFilledRef.current)
|
||||
if (prev.category_id && !categoryGuessedRef.current) return merged
|
||||
// A place from a collection brings the category it was saved under (#3074).
|
||||
const saved = savedCategoryId(result, categories || [])
|
||||
if (saved) {
|
||||
categoryGuessedRef.current = false
|
||||
return { ...merged, category_id: saved }
|
||||
}
|
||||
return { ...merged, category_id: guessedCategory(result) }
|
||||
})
|
||||
setPickedSource(label)
|
||||
|
||||
Reference in New Issue
Block a user