01La lista: la pestaña Fletes, cards siempre
freights-mobile-switcher.tsx · freights-toolbar.tsx · freight-card.tsxLa web móvil ya tomó las decisiones duras y la app las hereda: el switcher Fletes / Mis envíos (estado local, no URL) bajo el título, y cards siempre — «una tabla a 390 px es scroll horizontal y texto truncado», dice el comentario de freights-mobile-switcher.tsx:44; el ViewToggle ni existe en móvil. Debajo, la toolbar compacta: buscador con debounce de 300 ms, el botón de filtros con su contador, y los cuatro chips de status en scroll horizontal con máscara de degradado. La card replica la web campo a campo, con el código en display extralight — Lemon Milk a peso 200, el gesto tipográfico de esta superficie.
El switcher que la web ya decidió
MobileSubNavtal cual: pill de 44, activo blanco con sombra. «Mis envíos» monta la lista de MF-04 dentro de la pestaña — el mismo par de vistas que la web móvil, sin navegación extra.Chips, no tabs
Los cuatro grupos de
list-status-groups.tsconaria-pressed. El contador viene defreights/status-countsy desaparece mientras carga — nunca un 0 falso ni un skeleton de dos dígitos. Activobrand-500sobre blanco.Scroll con máscara
Los chips ruedan en horizontal con la máscara de degradado del modo
compactde la web. En RN:ScrollView horizontal+MaskedView; el buscador y el botón de filtros quedan fijos arriba.La card, campo a campo
Icono de modo
brand-500(barco/avión), pill de status, código en display extralight 24, seis filas atributo y el CTA terciario «Ver detalle». ElCorridorBadgesolo aparece cuando el chip del shell está en «Todas las rutas» — con la ruta filtrada es redundante, igual que en la web.Radio 14, una deuda saldada
La card web lleva
rounded(4 px) — un descuido frente al resto del producto. La app unifica con el radio 14 de las cards del shell (MF-03). Queda anotado como divergencia deliberada.Infinite scroll en FlashList
useInfiniteFreights+ sentinel se vuelvenFlashListcononEndReached. Refinar filtros no vacía la lista: la página anterior queda al 60 % de opacidad (isPlaceholderData), como la web.
Los labels de la card («Código de envío», «# Envíos», «Origen»…) están hardcodeados en español en freight-card.tsx — la app los lleva a i18n es/en/zh desde el día uno; deuda anotada para goal-phases. La fecha usa Intl.DateTimeFormat('es-VE'), dd/mm/yyyy.
02Estados de la lista y el sheet de filtros
freights-list.tsx · freight-card-skeleton.tsx · freights-filters.tsxLos seis estados de FreightsList se calcan: skeleton anatómico en la primera carga, lista al 60 % mientras se refina un filtro, vacío honesto, error con reintento, y el error de paginación como línea roja subrayada al pie — la lista ya cargada nunca se tira. El menú «Filtros» de escritorio se vuelve sheet: los mismos tres selects (Estatus · Tipo de envío · Estado de pago), con «Limpiar» y «Aplicar» al pie.
Sin fletes aquí
No se encontraron fletes con los filtros seleccionados.
Quitar filtrosEl vacío usa el patrón EmptyState de mobile-ui (plate celeste + display) con el copy de la web — «No se encontraron fletes con los filtros seleccionados.» — y un atajo honesto para salir del filtro. El error de lista es el mismo bloque con icono de alerta y «Reintentar»; el error de paginación es la línea roja «No se pudieron cargar más fletes. Reintentar.» bajo la última card. El resumen de filtros activos («Tipo de envío: Marítimo · Estatus: En tránsito») aparece como línea bajo la toolbar, igual que la web.
03El detalle que la web nunca diseñó para móvil
freight-detail-content.tsx · freight-summary-card.tsx · freight-details-sidebar.tsx · stack-header.tsx (MF-04)La web renderiza en el teléfono las dos columnas de escritorio aplastadas — el hueco más grande de esta MF. La app lo diseña: StackHeader de MF-04 con el código como título display y la descarga del PDF como acción, la alerta de pago primero (es la única acción con plata), los tres tabs de producto, y el sidebar de 400 px convertido en la sección apilada «Detalles». Pantalla fullscreen fuera de (tabs), exactamente como my-shipments/[id].
StackHeader, no barra centrada
El patrón real de MF-04 (
stack-header.tsx): fila de atrás con hit de 44, acciones a la derecha, y el título display 24 debajo con «Detalle del flete» de subtítulo. La descarga del PDF — que en web vive en el sidebar — sube al header como trailing.Fullscreen, sin tab bar
La ruta vive fuera de
(tabs), comomy-shipments/[id]: el detalle empuja sobre el stack y la barra de pestañas desaparece. Atrás del header, gesto y botón Android son la misma respuesta.La alerta de pago abre la pantalla
FreightPaymentAlertcon las cifras netas (splitServiceFeesresta el fee de pago de total y pagado). Tres títulos según la cotización (pendiente / parcial / cancelado). «Pagar ahora» abre el portal de pagos — el sheet es de MF-07; aquí solo se enlaza.Tres tabs de producto
Información · Envíos · Seguimiento, default Información — los mismos de la web. El «Ver detalle» de la card de envíos salta al tab, no navega: mismo contrato que
setActiveTab('shipments').El sidebar muere apilado
Los siete campos del
FreightDetailsSidebar(contenedor, llegada, fechas, tipo, pagos) se vuelven la card «Detalles» a continuación del resumen — una columna, filas label-valor contabular-nums.Resumen con desglose
La card de resumen replica el grid 2×N de la web y, con promoción, el bloque «Desglose de tarifa»: subtotal, descuento en verde con signo −, total en negrita.
Una inconsistencia unificada
La web usa dos mapas de variantes para el estatus de pago (card:
PARTIAL→warning; sidebar:PARTIAL→default). La app unifica en el deQUOTATION_STATUS_VARIANTS— Pago parcial siempre ámbar. Anotado.Los tres estados de la pantalla
Skeleton anatómico (la web no dibuja los tabs en el skeleton — la app tampoco), error «Error al cargar el flete» con Reintentar, y «Flete no encontrado» con «Volver a fletes».
04Envíos: el acordeón de MF-04, reusado
freight-shipments-tab.tsx · shipment-accordion.tsx · shipment-files.tsx · image-gallery.tsxEl tab Envíos no diseña nada nuevo: un acordeón por orden con el tracking en display como trigger, y dentro el resumen del envío y sus archivos — los mismos primitivos que MF-04 dejó en el detalle de envío. Los cuatro bloques de archivos de la web se conservan: galería de cajas, packing list en verde, factura en rojo, y la mercancía recibida por Mogos.
Resumen del envío
Archivos
El trigger es el tracking
Display 16 (Lemon Milk regular), con fallback al código
MG-cuando no hay tracking del proveedor (resolveOrderTrackingWithFallback). Truncado contitle, nunca cortado en silencio.Resumen en grid de dos
Los siete campos de
ShipmentSummary— el gridsm:2 md:4de la web se asienta en dos columnas a 390. Aprobación como pill:successAprobado /neutralPendiente.Archivos con su código de color
Packing list en verde, factura en rojo — los
DocumentCardde la web tal cual, con la descarga a la derecha. Sin nada que mostrar: «Sin archivos».Galería 3 columnas, sin lightbox
La web no tiene lightbox y la app guarda la paridad; el tap queda inerte en esta MF. La tentación de abrir el visor nativo queda anotada como iteración, no diseñada.
Vacío honesto
«No hay envíos en este flete» centrado — el mismo copy del tab y de la card de información.
05Seguimiento: cinco pasos y las paradas dentro
freight-progress-section.tsx · freight-tracking-timeline.tsx · transit-stops-readonly.tsx · current-location-card.tsx (cantera)El tab Seguimiento apila las dos cards de la web: el progreso — la barra con el marcador barco/avión posicionado al porcentaje real — y el timeline de cinco pasos fijos de CLIENT_FREIGHT_STEPS, con los eventos del admin como tarjetas ámbar ancladas a su paso. Y dentro de «En tránsito», el panel de paradas de ruta: la tarjeta «Aquí ahora» de la cantera encabeza la lista de escalas con sus cuatro estados.
24 sep 2026
El marcador viaja con el dato
Burbuja
brand-50con anillo blanco y el barco/aviónbrand-500, posicionada enleft:{progress}%. El porcentaje escontainer.progressPercentsi el admin lo fijó; si no, la escala 20/40/60/80/100 con piso del 10 % pre-salida.Etiqueta de llegada dinámica
«Llegada estimada a puerto» / «a aeropuerto» según el modo; ya en destino, cambia a «Retiro» con «Aún no listo / Listo para retiro / Retirado» —
clientFreightArrivalKindtal cual.Tiempo real, solo cuando existe
SEA con MMSI: «Ver seguimiento en tiempo real» abre MarineTraffic en el browser (el dialog de la web no se porta). AIR: «No aplica para envíos aéreos». SEA sin MMSI: «Disponible cuando el buque inicie tránsito».
Cinco pasos, nunca más
CLIENT_FREIGHT_STEPS: iconos de 32 — hechobrand-700con check, actual con anillobrand-100y punto blanco, pendiente gris punteado — y la línea de 2 px que se tiñebrand-600al completarse. Entregado reemplaza el paso 5 por «Retirado del almacén destino».Eventos ámbar anclados
Los
StatusUpdatetipo EVENT se insertan bajo su paso como tarjetaamber-50con bordeamber-200— el canal del admin para contar lo que pasó sin romper los cinco pasos.Las paradas viven dentro de En tránsito
El panel
dashed brand-500con degradadobrand-50y la etiqueta flotante con el conteo — solo sistatus === IN_TRANSITy hay contenedor. Error y vacío tienen sus cajas propias («Aún no hay paradas registradas»).«Aquí ahora», de la cantera
La
current-location-carddeapps/mobile-client(DECISIONS #17) encabeza el panel: pill warning, 📍 con bandera, y la próxima parada con su ETA. Si no hay escala alcanzada, la card no aparece.Saltada, tachada — como la web
La web muestra las escalas SKIPPED tachadas; la cantera las filtra. La app sigue a la web (el dato honesto gana) y el filtro de la cantera se corrige al portar el componente.
06El PDF y la pantalla puente
freight-document-content.tsx · PdfViewer (MF-04) · by-code/[code]/page.tsxDos auxiliares sin diseño nuevo. El documento del flete abre el PdfViewer de MF-04 con el blob de freights/:id/document — el API lo renderiza en cada apertura, en marco neto y con el sello PAGADO cuando corresponde. Y by-code es una pantalla puente honesta: skeleton mientras resuelve y redirige; los 404/403 nunca revelan propiedad — van en silencio a la lista. /account/freight/[id] es solo un redirect de ruta, sin UI.
Ocurrió un problema temporal. Por favor intenta de nuevo.
Volver a mis envíosEl visor hereda de MF-04 el estado de error del documento: círculo destructive/10 con FileX, «Documento no encontrado», «No pudimos abrir el resumen en este momento. Vuelve a intentarlo en unos minutos.» y el CTA «Ver flete». El share del header comparte el PDF con el share sheet nativo — en el teléfono, descargar ES compartir.
07La nota de entrega: un documento, no una pantalla
delivery-signature-page.tsx · delivery-ink.ts · delivery-fonts.ts · doc-section.tsxLa única superficie de la web pensada desde el teléfono, y un artefacto legal: la app la replica al píxel. La paleta es INK literal — «la pantalla ES el documento», debe leerse igual en cualquier tema y en un teléfono roto —, la voz de etiqueta es Oswald (cargada solo aquí, como delivery-fonts.ts), y la marca es vector: el wordmark en el membrete marino, el monograma en el sello. Cinco secciones sobre papel: Recibe, Mercancía, Pago contra entrega, Recepción y Firma. Debajo, la barra fija marino con la promesa — «Copia firmada a tu correo» — y el botón que solo despierta cuando hay firma.
INK, no tokens de tema
delivery-ink.tsa propósito con valores literales — coinciden 1:1 con la capa de marca (marino, celeste-soft, paper) pero no responden a ningún tema. En la app: un StyleSheet local con la misma tabla, light siempre.Oswald, solo aquí
La voz de etiqueta del documento: 9,5–11 px, tracking .16em, mayúsculas — en los rótulos de sección, el «Nota de entrega» del membrete, el «Total» y el caption del sello. Se carga con
expo-fonten esta ruta, no con la app.El membrete es vector
Wordmark de 92 px sobre marino, punto rojo intacto; a la derecha del filete, código y fecha en 13 tabular. Radio del documento 14, membrete 13 — concéntricos.
Mercancía en líneas, no en tabla
Una línea por orden — tracking a la izquierda, cajas a la derecha — y el cierre Total en Oswald contra el número en bold. La web lo razonó: cuatro columnas en un teléfono son scroll horizontal y celdas vacías.
El saldo manda en la sección de pago
$412,50 en 22 bold tabular con «saldo del flete» debajo (o «sin saldo pendiente»); las cuatro pills — Efectivo · Zelle · USDT · Pago Móvil — con el activo en marino pleno, y el monto cobrado editable con el $ prefijado.
Recepción arranca sin valor
Conforme / Con observaciones es una decisión que el cliente toma, no un default que hereda. «Con observaciones» abre el textarea (placeholder «¿Qué observaste al recibir?…»), excluido de PostHog con
ph-no-capture.La barra fija promete
Marino, con «Copia firmada a {email}» a la izquierda y el botón blanco de 44 a la derecha — dormido al 45 % hasta que hay firma. Firmando: spinner + «Firmando…».
Tres puertas, un documento
/account/freights/[id]/delivery(auth),/freights/[id]/delivery?token=y/f/[token](públicas) montan la misma pantalla. Sin token: «Enlace inválido» con el copy de notificación o de QR según la puerta.
La ruta pública vive fuera del grupo autenticado — sin top bar, sin tabs, sin sesión: solo el documento sobre papel. El QR del courier resuelve signature-tokens/:token/resolve y todas las llamadas de esta superficie viajan con x-signature-token, nunca con el bearer del usuario.
08La firma y el sello
signature-canvas.tsx · delivery-stamp.tsx · delivery-success-modal.tsxEl canvas es react-native-signature-canvas — el mismo que ya firma en la app de delivery — con la pluma marino de 1 a 2,6 px y un detalle que la web aprendió a golpes: al rotar o al subir el teclado, la firma se snapshotea y se repinta, nunca se pierde. La línea de firma es real: la ✗ roja, la regla marino y el nombre con la cédula centrado debajo. Y al confirmar, el único momento orquestado de la MF: el sello con el monograma cae rotando — 420 ms, cubic-bezier(.34,1.2,.64,1) — sobre el modal de éxito.
fabrizio@correo.com
La pluma exacta
penColor #021B54, trazo 1 → 2,6 convelocityFilterWeight 0.7. El canvas mide 132 y estouch-none; en RN,react-native-signature-canvasya trae el mismo motor (signature_pad) que la web.La firma sobrevive
Rotación o teclado: se snapshotea a dataURL y se repinta — asignar
canvas.widthborraba firmas. En RN el WebView del canvas hereda la corrección; el borrador es el único que borra, con su hit invisible de 44.Validación en rojo INK
Cuatro mensajes bajo su sección: «La firma es requerida», «La firma debe ser una imagen válida», «Indica cómo recibiste la mercancía», «Cuéntanos qué observaste al recibir». Texto 12 en
INK.rojo, sin toasts para errores de campo.El botón despierta con la firma
El primer trazo activa «Confirmar entrega» (45 % → 100 %). Al enviar: spinner + «Firmando…», y la mutación viaja con
x-signature-tokenacapture-signature.El sello: 420 ms y quieto
De
rotate(-2°) scale(1.6)arotate(-8°) scale(1)con el spring corto. Monograma vectorial, caption Oswald «Entregado», fecha solo si se conoce — nunca inventa «hoy». Reduced motion: aparece ya estampado.El modal sin escape accidental
Sin ✗ y sin cierre por velo: las únicas salidas son «Descargar la nota» (solo si el PDF se generó) e «Ir al inicio». Además, el toast Sileo de éxito: «Entrega completada exitosamente».
09Estados terminales y el deep link
delivery-state-screen.tsx · f/[token]/page.tsx · app.config.ts (scheme mogosapp)Tres pantallas cierran el flujo con la misma estructura fija — wordmark, arte, título, salida — y copy honesto, sin disculpas. El token usado no es un error: es el sello ya puesto. El vencido explica el porqué («por seguridad, dura poco») y ofrece el WhatsApp de soporte — el botón se omite si la env var no está, nunca un link roto. Y el flete que aún no llega dice exactamente eso.
Esta nota ya está firmada
La entrega se confirmó y la nota firmada viajó a tu correo. Si no la encuentras, búscala en tus documentos dentro de tu cuenta.
Este enlace venció
Por seguridad, el enlace para firmar dura poco tiempo. Pide uno nuevo y firmas en el momento.
Tu flete aún viene en camino
Esta nota se firma cuando la mercancía llega a tu puerta. Te avisamos apenas esté lista para entregar.
mogosapp://f/<token>
→
signature-tokens/:token/resolve
→
la nota, sin sesión
/f/ existe por el QR: sin el UUID largo cada módulo es ~49 % más grande y se escanea a más distancia. En esta MF basta el scheme mogosapp:// + la ruta pública en la app; los universal links (que el mismo QR impreso abra la app desde Safari) son de MF-14. Mientras resuelve: el mismo fondo papel con tres skeletons — nunca un flash de error. El estado «no listo» cambia el icono según el modo (barco/avión) — única licencia sobre la web, que usa el reloj dos veces.
10Lo que hay que escribir en Moti
Moti + Reanimated · escala de MF-01 · useReducedMotion| Pieza | Qué anima | Duración · easing | Reduced motion |
|---|---|---|---|
| Cambio de tab del detalle | fade + slide 12 px del contenido; el trigger activo desliza el fondo blanco | 260 ms · ease-out | fade 80 ms |
| Chips de status | press scale .95; el contador aparece con fade cuando llega el dato | 160 ms · ease-out | swap directo |
| Sheet de filtros | slide-up con velo marino al 70 % | 260 ms · ease-out | fade 80 ms |
| Marcador de progreso | la barra crece 0 → % y la burbuja la sigue, una sola vez al montar | 420 ms · ease-out | estático al % |
| Timeline | pasos entran con rise 12 + stagger 40; la tarjeta ámbar y las paradas llegan con el suyo | 260 ms · ease-out | directo |
| El sello | rotate(−2°) scale(1.6) → rotate(−8°) scale(1), cayendo sobre el modal | 420 ms · cubic-bezier(.34,1.2,.64,1) | ya estampado |
| Toast de éxito | drop Sileo desde arriba | 640 ms · ease-spring | fade 80 ms |
Fuente de la escala: packages/mobile-ui/src/theme/motion.ts (MF-01). El halo de «Aquí» en las paradas no pulsa: el único latido del shell es el ping del chip de ruta, y el único momento orquestado de la MF, el sello. Nada supera los 640 ms.
11Lo que queda decidido
docs/specs/2026-09-15-mobile-fletes.md- Decisión 1 · propuesta 2026-09-15
La lista hereda el switcher de la web
Pestaña Fletes del shell con
MobileSubNavFletes / Mis envíos, cards siempre (la tabla y el ViewToggle no existen en móvil), chips con contadores que desaparecen al cargar, y filtros como sheet. - Decisión 2 · propuesta 2026-09-15
El detalle se diseña — la web no lo tenía
StackHeader de MF-04 (código display + descarga como trailing), alerta de pago primero, tres tabs de producto y el sidebar convertido en sección «Detalles». Fullscreen, fuera de
(tabs). - Decisión 3 · propuesta 2026-09-15
Las paradas viven dentro de En tránsito
Progreso + timeline de 5 pasos como la web, y el panel de paradas anidado bajo el paso actual, encabezado por la «Aquí ahora» de la cantera. Saltadas tachadas (la web gana); el filtro de la cantera se corrige al portar.
- Decisión 4 · propuesta 2026-09-15
PDF y by-code no diseñan nada nuevo
PdfViewerde MF-04 con share nativo; by-code es puente con skeleton que nunca revela propiedad (404/403 → lista, en silencio).freight/[id]es solo redirect. - Decisión 5 · propuesta 2026-09-15
La nota de entrega, fiel al píxel
Artefacto legal: paleta INK literal light-only, Oswald solo en esta ruta, marca vectorial, canvas
react-native-signature-canvascon snapshot al rotar, recepción sin default, barra fija que despierta con la firma, y los cuatro estados terminales calcados. - Decisión 6 · propuesta 2026-09-15
«El documento que se sella»
Lista y detalle son producto calmo; la marca aparece donde el flete viaja. El único momento orquestado es el sello de 420 ms sobre el modal de éxito. Deep link
mogosapp://f/<token>con el scheme; universal links en MF-14. - Reuso · consecuencia
Nada se dibuja dos veces
Shell y sheets de MF-03, StackHeader/acordeón/galería/PdfViewer de MF-04, pills y badges de MF-01, y
route-stepper+current-location-cardde la cantera (DECISIONS #17) — corregidos, no reinventados. - Deuda anotada · para goal-phases
Lo que la web debe y la app no repite
Labels de la card y toda la nota de entrega hardcodeados en español → i18n es/en/zh desde el día uno. Dos mapas de variantes para el pago (PARTIAL ámbar gana). Galería sin lightbox (paridad; visor nativo anotado como iteración). Sin eventos PostHog de fletes: definir
freight_*en la MF.