revert(collections): a saved place carries no price, website or phone again

Takes back the editable price, currency, website and phone on collection
places from 0df82185b and its review follow-up in a910c2a83. Costs are kept
inside a trip only; a collection does not carry them, and #2471 is a
feature request rather than a bug. The collection files are back to how
they were before, including the dimmed save button from f16698bdb, which
only mattered for the price field.
This commit is contained in:
Maurice
2026-09-23 20:32:41 +02:00
parent f16698bdb1
commit a1d6348c5f
40 changed files with 25 additions and 937 deletions
@@ -2,7 +2,7 @@ import { useEffect, useRef, useState } from 'react'
import Markdown from 'react-markdown'
import remarkGfm from 'remark-gfm'
import remarkBreaks from 'remark-breaks'
import { Banknote, Camera, Check, Copy, ExternalLink, Globe, Loader2, MapPin, Pencil, Phone, Trash2, X } from 'lucide-react'
import { Camera, Check, Copy, ExternalLink, Loader2, MapPin, Pencil, Trash2, X } from 'lucide-react'
import type { CollectionLabel, CollectionLink, CollectionPlace, CollectionStatus } from '@trek/shared'
import type { Category, TranslationFn } from '../../../types'
import { mapsApi } from '../../../api/client'
@@ -12,9 +12,6 @@ import { getApiErrorMessage } from '../../../utils/apiError'
import { normalizeLinkUrl, STATUS_ORDER } from '../../../pages/collections/collectionsModel'
import MSheet from '../../components/MSheet'
import PlaceRating from '../../../components/shared/StarRating'
import CustomSelect from '../../../components/shared/CustomSelect'
import { NumericInput } from '../../../components/shared/NumericInput'
import { useCollectionPlaceExtras, type CollectionPlaceExtrasPatch } from '../../../components/Collections/useCollectionPlaceExtras'
import MCollCategoryPicker from './MCollCategoryPicker'
import MCollLinksEditor from './MCollLinksEditor'
import { STATUS_SPEC } from './collectionsMobileModel'
@@ -30,9 +27,6 @@ const HERO_CAT_CHIP =
// Close and the cover controls beside it.
const HERO_BTN =
'flex h-8 w-8 items-center justify-center rounded-full bg-[rgba(0,0,0,.28)] text-white' // theme-lint-disable
// A saved link, and the website beside it.
const LINK_CHIP =
'inline-flex items-center gap-[5px] rounded-full border border-[color:var(--m-rowbr)] bg-[color:var(--m-sheet)] px-3 py-[7px] text-[0.71875rem] font-semibold text-m-ink'
interface MCollPlaceSheetProps {
place: CollectionPlace | null
@@ -42,7 +36,7 @@ interface MCollPlaceSheetProps {
labels: CollectionLabel[]
onClose: () => void
onSetStatus: (status: CollectionStatus) => void
onSave: (patch: { name?: string; description?: string | null; links?: CollectionLink[]; category_id?: number | null; label_ids?: number[]; image_url?: string | null; address?: string | null } & CollectionPlaceExtrasPatch) => Promise<void>
onSave: (patch: { name?: string; description?: string | null; links?: CollectionLink[]; category_id?: number | null; label_ids?: number[]; image_url?: string | null; address?: string | null }) => Promise<void>
onUploadImage?: (file: File) => Promise<void>
onCopyToTrip: () => void
onRemove: () => void
@@ -75,7 +69,6 @@ export default function MCollPlaceSheet({
const [links, setLinks] = useState<CollectionLink[]>([])
const [labelIds, setLabelIds] = useState<number[]>([])
const [saving, setSaving] = useState(false)
const extras = useCollectionPlaceExtras(held)
const [fetchedPhoto, setFetchedPhoto] = useState<string | null>(null)
const heldId = held?.id
@@ -107,7 +100,7 @@ export default function MCollPlaceSheet({
const cleanLinks = links.map(l => ({ label: l.label?.trim() || undefined, url: normalizeLinkUrl(l.url) })).filter(l => l.url)
setSaving(true)
try {
await onSave({ name: name.trim() || held.name, address: address.trim() || null, description: description.trim() || null, links: cleanLinks, category_id: categoryId, label_ids: labelIds, ...extras.patch() })
await onSave({ name: name.trim() || held.name, address: address.trim() || null, description: description.trim() || null, links: cleanLinks, category_id: categoryId, label_ids: labelIds })
setEditing(false)
} catch (err) {
toast.error(getApiErrorMessage(err, t('common.error')))
@@ -116,11 +109,6 @@ export default function MCollPlaceSheet({
}
}
const startEdit = () => {
extras.reset(held)
setEditing(true)
}
const cancelEdit = () => {
if (!held) return
setEditing(false)
@@ -224,20 +212,6 @@ export default function MCollPlaceSheet({
<MapPin size={13} strokeWidth={2} className="mt-[1px] flex-none" /> {held.address}
</div>
)}
{!editing && (extras.priceLabel || extras.phone) && (
<div className="mt-[6px] flex flex-wrap items-center gap-x-3 gap-y-1 font-geist text-[0.75rem] leading-[1.5] text-m-muted">
{extras.priceLabel && (
<span className="inline-flex items-center gap-[5px] font-semibold text-m-ink [font-variant-numeric:tabular-nums]">
<Banknote size={13} strokeWidth={2} className="flex-none" /> {extras.priceLabel}
</span>
)}
{extras.phone && extras.phoneHref && (
<a href={extras.phoneHref} className="inline-flex items-center gap-[5px]">
<Phone size={13} strokeWidth={2} className="flex-none" /> {extras.phone}
</a>
)}
</div>
)}
{/* Status cycle */}
<div className="mt-3 flex gap-[6px]">
@@ -277,26 +251,6 @@ export default function MCollPlaceSheet({
{/* Address (#1870): free text, same as the add sheet offers */}
<Eyebrow className="mb-[6px] mt-[14px]">{t('places.formAddress').toUpperCase()}</Eyebrow>
<input value={address} onChange={e => setAddress(e.target.value)} placeholder={t('places.formAddressPlaceholder')} className={INPUT_CLS} />
{/* Price (#2471): a rough cost such as an entry fee, always in its own currency */}
<Eyebrow className="mb-[6px] mt-[14px]">{t('collections.price').toUpperCase()}</Eyebrow>
<div className="flex items-center gap-2">
<div className="min-w-0 flex-1">
<NumericInput
{...extras.priceInput}
placeholder="0"
aria-label={t('collections.price')}
className={`${INPUT_CLS} aria-[invalid=true]:border-[color:var(--m-st-danger)]`}
/>
</div>
<div className="w-32 flex-none">
<CustomSelect {...extras.currencySelect} searchable size="sm" style={{ width: '100%' }} />
</div>
</div>
<div className="mt-[6px] font-geist text-[0.6875rem] leading-[1.45] text-m-muted">{t('collections.priceHint')}</div>
<Eyebrow className="mb-[6px] mt-[14px]">{t('places.formWebsite').toUpperCase()}</Eyebrow>
<input type="url" value={extras.draft.website} onChange={e => extras.set('website', e.target.value)} aria-label={t('places.formWebsite')} className={INPUT_CLS} />
<Eyebrow className="mb-[6px] mt-[14px]">{t('collections.phone').toUpperCase()}</Eyebrow>
<input type="tel" value={extras.draft.phone} onChange={e => extras.set('phone', e.target.value)} maxLength={60} aria-label={t('collections.phone')} className={INPUT_CLS} />
<Eyebrow className="mb-[6px] mt-[14px]">{t('collections.category').toUpperCase()}</Eyebrow>
<MCollCategoryPicker categories={categories} value={categoryId} onChange={setCategoryId} t={t} />
{labels.length > 0 && (
@@ -331,7 +285,7 @@ export default function MCollPlaceSheet({
<MCollLinksEditor links={links} onChange={setLinks} t={t} />
<div className="mt-4 flex items-center gap-2">
<CancelPill className="ml-auto" onClick={cancelEdit}>{t('common.cancel')}</CancelPill>
<PrimaryPill onClick={save} disabled={saving || !extras.priceValid}>
<PrimaryPill onClick={save} disabled={saving}>
<Check size={14} strokeWidth={2.4} /> {t('common.save')}
</PrimaryPill>
</div>
@@ -360,20 +314,15 @@ export default function MCollPlaceSheet({
<Markdown remarkPlugins={[remarkGfm, remarkBreaks]}>{held.description}</Markdown>
</div>
)}
{(extras.websiteHref || (held.links && held.links.length > 0)) && (
{held.links && held.links.length > 0 && (
<div className="mt-3 flex flex-wrap gap-[6px]">
{extras.websiteHref && (
<a href={extras.websiteHref} target="_blank" rel="noopener noreferrer" className={LINK_CHIP}>
<Globe size={13} strokeWidth={2} className="text-m-muted" /> {linkHost(extras.websiteHref)}
</a>
)}
{(held.links ?? []).map((l, i) => (
{held.links.map((l, i) => (
<a
key={i}
href={l.url}
target="_blank"
rel="noopener noreferrer"
className={LINK_CHIP}
className="inline-flex items-center gap-[5px] rounded-full border border-[color:var(--m-rowbr)] bg-[color:var(--m-sheet)] px-3 py-[7px] text-[0.71875rem] font-semibold text-m-ink"
>
<ExternalLink size={13} strokeWidth={2} className="text-m-muted" /> {l.label || linkHost(l.url)}
</a>
@@ -382,7 +331,7 @@ export default function MCollPlaceSheet({
)}
<div className="mt-[14px] flex gap-2">
{canEdit && (
<button type="button" onClick={startEdit} className={actionBtn}>
<button type="button" onClick={() => setEditing(true)} className={actionBtn}>
<Pencil size={13} strokeWidth={2.2} /> {t('common.edit')}
</button>
)}