MF-08 · cotizaciones · sep 2026

Mobile · cotizaciones de servicio

Pide, decide y paga lo que te cotizamos.

Las cotizaciones de servicio en el teléfono, a paridad con /account/service-quotes/**. La lista usa el stack compartido de MF-06 (búsqueda con debounce, chips de estatus, secciones Pendientes y Finalizadas). La solicitud se arma en una columna con los productos en una hoja que sube con el teclado. El detalle le da a cada estado una sola cosa que hacer: aprobar o rechazar, pagar con el portal de MF-07, o leer en qué va. El PDF abre en el visor de MF-04. Paridad estricta, web = verdad: elegir proveedor y el historial no existen en la web, así que tampoco en la app, ni siquiera como botón: la única acción de la lista es «Nueva cotización».

Rutas
lista · new · [id] · document
Estados visibles
6 · NEW/SOURCING nunca
Acciones
aprobar · rechazar · pagar
Paridad
estricta · web = verdad
Reuso
lists · PdfViewer · portal
Pantallas
19 a 390×844

01La lista, con el stack de listas que ya existe

service-quotes/page.tsx · service-quotes-filters.tsx · service-quote-card.tsx

/(app)/service-quotes, hoy un placeholder de MF-03, pasa a ser una pantalla de stack (se entra desde Más, desde «Crear» y desde Pagos). Lleva el encabezado y la descripción de la web, una sola acción («Nueva cotización»), y debajo el stack de listas compartido (DECISIONS #28): ListToolbar solo con búsqueda (?q, 300 ms) y StatusChips en lugar del Select «Estatus». Las cards se agrupan en Pendientes y Finalizadas como en la web, y una sección vacía no se muestra.

9:41●●●
Cotizaciones
Solicita una cotización personalizada para tus productos y consulta el estado de las cotizaciones existentes.
Nueva cotización
Buscar
TodosBorradorPendienteAprobadaRechazadaVencida
Pendientes
COT-20260918-0014
Código de cotización
EstatusPendiente
Fecha de creación18 sep, 2026
MotivoBúsqueda
Ver detalle
COT-20260921-0017
Código de cotización
EstatusBorrador
Fecha de creación21 sep, 2026
  1. La pantalla solo compone

    StackHeader de MF-04, ListToolbar, StatusChips, InfiniteList* y useInfiniteListState de components/lists, con filtros persistidos por createPersistedListFilters. Lo propio del dominio es poco: ServiceQuoteCard, el mapa estatus → badge y la regla de agrupado. La lista cabe en unas 4 piezas finas de menos de 300 líneas, como fletes y envíos.

  2. Una sola acción: «Nueva cotización»

    Pasa por el gate de perfil (§03) y abre /new. Va a lo ancho y sin ícono, como el w-full de la web móvil. No hay botón «Historial»: la web lo tiene como stub «Muy pronto», pero Fabrizio lo sacó del todo. No está deshabilitado, no lleva badge y no abre diálogo. Tampoco hay historial en ningún otro lugar de la app.

  3. Chips en lugar del Select, con los mismos 7 valores

    Todos · Borrador · Pendiente · Aprobada · Rechazada · Vencida · Cancelada, con las etiquetas de serviceQuotes.status.*. Nueva y En búsqueda no aparecen porque el API nunca se las entrega al cliente. El chip activo va a ?status=. ListToolbar no tiene aquí filtros secundarios, así que su botón «Filtros» pasa a ser opcional: una prop más, sin clonar el componente.

  4. La card, campo a campo

    El código en display 200 con «Código de cotización» debajo, y las filas Estatus (badge), Fecha de creación (d MMM, yyyy en el idioma del usuario) y Motivo (Búsqueda, Consolidación, Control de calidad o Sourcing). Cierra con «Ver detalle →». Los colores del badge: warning para Pendiente, success para Aprobada, error para Rechazada y neutral para el resto, los mismos en la lista y en el detalle.

  5. Con scroll infinito, a diferencia de la web

    La web pide solo la página 1 (perPage=20) y nunca muestra más, así que la cotización 21 no existe para el cliente: es un bug de la web. La app usa InfiniteList*, y las secciones se recalculan a medida que llegan páginas.

02Buscar, quedarse sin nada, esperar

useListSearch · InfiniteListEmpty · loading.tsx

La búsqueda es la de la web: el API busca por código (contiene, sin distinguir mayúsculas). Se aplica tras 300 ms y a partir del mínimo de useListSearch. El vacío usa la copia de la web tal cual y no lleva CTA, porque «Nueva cotización» ya está arriba. Con un filtro activo, la misma copia suma «Limpiar filtros». La carga es un skeleton con la forma de la card: código, etiqueta, tres filas y botón.

Buscando ?q=0014 · ?status=PENDING
Sin cotizaciones la copia de la web
9:41●●●
Cotizaciones
Solicita una cotización personalizada para tus productos y consulta el estado de las cotizaciones existentes.
Nueva cotización
Buscar
TodosBorradorPendienteAprobadaRechazada

No tienes cotizaciones por el momento.

Tus cotizaciones de servicio aparecerán aquí.

Cargando skeleton con forma de card
9:41●●●
Cotizaciones
Solicita una cotización personalizada para tus productos y consulta el estado de las cotizaciones existentes.
Nueva cotización
Buscar
TodosBorradorPendienteAprobadaRechazada

Error de red: InfiniteListEmpty en variante error con «Error al cargar las cotizaciones» y Reintentar. La web muestra error.message en crudo; la app nunca muestra el mensaje técnico. Sin conexión: ConnectionAlert global de MF-03.

03Por dónde se entra, y quién puede pedir

mas.tsx (MF-03) · create-items.ts · use-profile-gate.ts · profile-gate-modal.tsx

Las tres puertas ya existen y no se rediseñan. La fila Cotizaciones de Más muestra pendingServiceQuotes (DRAFT + PENDING, de users/sidebar-counts) como número gris: es lo que tienes en curso, no una alarma, y por eso no lleva la pastilla roja de Pagos, igual que en la web. El ítem «Nueva cotización» del menú Crear (orbe) abre /new. «Ver cotización» de Pagos (MF-07), que hoy cae en la lista, pasa a abrir el detalle. El gate de perfil solo bloquea «Nueva cotización»: la lista y el detalle se ven con el perfil incompleto, como en la web.

Más · Cuenta el contador ya está cableado (MF-03)
9:41●●●
China
3FS
FS
Fabrizio Spiotta
fabrizio@cresco.so

Cuenta

Pagos2
Cotizaciones2
Mis direcciones

Accesos

Catálogo
Sedes Mogos
Enviar sugerencia
El gate «Nueva cotización» con el perfil incompleto
9:41●●●
Cotizaciones
Solicita una cotización personalizada para tus productos y consulta el estado de las cotizaciones existentes.
Nueva cotización
Buscar
TodosBorradorPendiente
Pendientes
COT-20260918-0014
Código de cotización

El gate es el useProfileGate + modal que MF-03 ya portó, con claves es/en/zh (la web los tiene en español fijo). Si el perfil se completa con el modal abierto, la navegación retenida sigue sola hacia /new, igual que en la web.

04La solicitud, en una columna

new/page.tsx · create-quote-form.tsx · service-details-section.tsx · create-service-quote-schema.ts

Las dos cards de la web, una debajo de la otra: Detalles del servicio y Productos solicitados. Hay un solo CTA, «Crear cotización», y el server guarda la cotización en Borrador: no existe «Guardar borrador». Va en un pie fijo sobre el home indicator, así que siempre está al alcance del pulgar aunque la lista de productos crezca. Nada es obligatorio más allá de los dos tipos, que ya vienen con valor por defecto (Búsqueda de productos y Marítimo): se puede enviar una solicitud con solo la descripción, que es exactamente lo que hace quien pega su conversación de WhatsApp.

9:41●●●
Nueva cotización
Crea una solicitud de cotización para que nuestro equipo busque los mejores proveedores para ti.
Detalles del servicio
Tipo de servicio *Búsqueda de productos
Tipo de envío *Marítimo
Descripción de tu solicitud (Opcional)
Describe lo que necesitas. Puedes pegar tu conversación de WhatsApp o incluir cualquier detalle relevante...
Productos solicitadosAgregar producto
No hay productos agregados

Agrega los productos que deseas cotizar (opcional)

Agregar producto
Crear cotización
  1. Tipo de servicio: el Select de mobile-ui

    Cuatro opciones con su nombre largo: Búsqueda de productos, Consolidación, Control de calidad y Sourcing personalizado. El Select de MF-01 abre una hoja con esos cuatro valores. Por defecto, PRODUCT_SEARCH.

  2. Tipo de envío: el mismo Select

    Aéreo y Marítimo en el Select de mobile-ui, como la web; por defecto SEA. Los dos tipos se eligen igual, sin controles propios.

  3. La descripción es el corazón del pedido

    El placeholder de la web invita a pegar la conversación de WhatsApp, así que el campo crece con el texto (multiline, mínimo 120 como la web) y no tiene límite visible. La etiqueta dice «(Opcional)» como texto, en el mismo estilo del label, y el campo puede quedar vacío: la solicitud se envía igual.

  4. El pie fijo y el teclado

    «Crear cotización» vive en un pie fijo con KeyboardAvoidingView: al escribir la descripción el pie sube con el teclado y el scroll lleva el campo enfocado sobre él. Mientras envía, el botón muestra el spinner y «Creando...», y el formulario queda deshabilitado. La app escribe «Crear cotización» con tilde: la web tiene la errata «Crear cotizacion» en el locale, anotada como deuda.

  5. Mismo cuerpo que la web

    POST service-quotes con {clientId, serviceType, shippingType, originalRequest?, requestedProducts?[]}. El API fuerza el clientId del token y la cotización nace en Borrador, así que aparece en Pendientes enseguida (§05). Un error de red no borra lo escrito.

05Productos: filas, una hoja y el teclado

products-section.tsx · add-product-dialog.tsx

En la web los productos son una tabla (Producto, Marca sugerida, Especificaciones, Cantidad). En 390 px son filas: nombre y cantidad arriba, marca y especificaciones debajo (dos líneas como máximo) y los botones de editar y eliminar a la derecha. AddProductDialog se vuelve una hoja que sube con el teclado, con los mismos cuatro campos y los mismos mensajes. Es texto libre, sin catálogo ni búsqueda, porque la web tampoco los tiene: el brief preguntaba por catalogs y el inventario dice que no.

Con dos productos scroll hasta la card
9:41●●●
Descripción de tu solicitud (Opcional)
Necesito audífonos y cargadores para reventa en Valencia. Es un pedido de prueba; si sale bien lo repito cada mes.
Productos solicitadosAgregar producto
Audífonos inalámbricos×50Soundcore o similarBluetooth 5.3, estuche de carga, color negro
Cargador USB-C 65W×100Anker o similarGaN, dos puertos, enchufe tipo A
Crear cotización
Agregar producto la hoja sobre el teclado
9:41●●●
Productos solicitados
Audífonos inalámbricos×50Soundcore o similar
Creada toast y la nueva en Pendientes
9:41●●●
Cotizaciones
Solicita una cotización personalizada para tus productos y consulta el estado de las cotizaciones existentes.
Nueva cotización
Buscar
TodosBorradorPendienteAprobadaRechazada
Pendientes
COT-20260922-0018
Código de cotización
EstatusBorrador
Fecha de creación22 sep, 2026
MotivoBúsqueda
Ver detalle
Cotización creada
  1. La fila reemplaza a la tabla

    La cantidad va en mono a la derecha, a la altura del nombre, que es donde se compara. La marca sugerida va tal cual la escribió el cliente («Soundcore o similar»). Las especificaciones ocupan dos líneas como máximo y se leen completas al editar. Una celda vacía no pinta «-» como la web: simplemente no aparece.

  2. Editar y eliminar, con 44 px de toque

    El lápiz reabre la hoja precargada con «Editar producto», «Modifica los detalles del producto.» y el botón «Guardar cambios». La papelera borra sin confirmar, como la web, porque el producto todavía no se ha enviado: la fila se pliega en 260 ms y el formulario no pierde nada más.

  3. La hoja sube con el teclado

    Es el riesgo del brief («formulario con productos dinámicos en móvil»). La hoja es un BottomSheet con keyboardBehavior="interactive": con el teclado abierto se ve el campo enfocado y el pie «Cancelar | Agregar» sin tener que cerrarlo. «Siguiente» en el teclado salta de campo, y en el último agrega el producto.

  4. Cantidad: un input numérico

    Es el input de la web: numérico (keyboardType="number-pad"), mínimo 1 y 1 por defecto, sin stepper. Si llega un valor menor que 1, aparece «La cantidad mínima es 1» bajo el campo. «El nombre del producto es requerido» aparece bajo el nombre en rojo, con el campo marcado.

  5. Al crear: toast y de vuelta a la lista

    Como en la web, la app vuelve a la lista y la refresca. La cotización nueva queda arriba de Pendientes, en Borrador, con un anillo de marca que se apaga en 1,2 s para que se encuentre de un vistazo. Si falla, sale el toast de error «No se pudo crear la cotización» y el formulario sigue intacto.

06El detalle: qué te recomendamos y cuánto cuesta

[id]/service-quote-detail-content.tsx · components/service-quotes/detail/*

Una sola columna, con los bloques de la web en el orden de la web: encabezado, enlace al PDF, La recomendación de Mogos, Total y acciones. Hay dos cambios de forma. El encabezado se funde con el StackHeader (título «Búsqueda · Marítimo» y el código en mono debajo), y la acción, cuando la hay, baja a un pie fijo: en una pantalla larga, «Aprobar» no puede quedar tres scrolls más abajo del total que la justifica.

9:41●●●
Búsqueda · Marítimo
COT-20260918-0014
PendienteChina → VenezuelaVigente hasta 2 oct 2026
La recomendación de Mogos
Elegimos un proveedor por producto. Esto es lo que incluye tu cotización.
Shenzhen Audio tiene la mejor garantía y entrega en 12 días. Para los cargadores, Anker directo de fábrica.
Audífonos inalámbricos×50Soundcore · Shenzhen Audio Tech12 días de entrega · Garantía 12 meses · Bluetooth 5.3
Cargador USB-C 65W×100Anker · Dongguan Power Co.9 días de entrega · Garantía 6 meses
TotalUSD4,860.00
Revisa la recomendación y apruébala para que empecemos.
RechazarAprobar
9:41●●●
Cargador USB-C 65W×100Anker · Dongguan Power Co.9 días de entrega · Garantía 6 meses
TotalUSD4,860.00
Entrega estimada en 38 días
Desglose
Productos4,120.00
Flete marítimo estimado480.00
Gestión (5 %)206.00
Seguro54.00
Revisa la recomendación y apruébala para que empecemos.
RechazarAprobar
  1. El encabezado es el StackHeader

    La web pinta una card con miga, código en mono y el título {tipo} · {envío}. En la app el título va en el StackHeader, el código debajo en mono (se lee y se copia con long-press), y la fila de metadatos abre el cuerpo: badge de estatus, corredor y «Vigente hasta {fecha}».

  2. Un color por estatus, en todas partes

    El pill de la web usa amber, emerald y orange de Tailwind, que no están en los tokens del producto y además no coinciden con los badges de su propia lista. La app usa un solo mapa estatus → Badge (warning, success, error, neutral) en la lista, el detalle y el historial, igual que MF-07 llevó sus entity-types a la escala del sistema.

  3. El PDF, solo cuando existe

    La fila «Ver cotización en PDF» sale cuando hay documentUrl y documentGeneratedAt. En Borrador no hay documento (el API responde 400) y la fila no se muestra. Tocarla abre [id]/document (§10).

  4. La recomendación, sin precio por producto

    Nombre en display, «{marca} · {proveedor}» (la opción elegida o, si no hay, la recomendada), y días de entrega, garantía y descripción unidos con « · ». A la derecha, la cantidad. No hay precio unitario, a propósito: el mapper del API lo quita para el cliente. La nota del agente (clientNotes) va citada arriba. Sin proveedor, la fila dice «Todavía sin recomendación» o «Sin propuestas todavía». La fila es de solo lectura, como la web: el cliente aprueba o rechaza la recomendación tal cual, y no puede elegir ni cambiar el proveedor.

  5. El total, en mono y en su moneda

    «USD» pequeño delante de la cifra, formato en-US con 2 decimales (el de la web), «Entrega estimada en {n} días» y el Desglose con las líneas de la factura; las negativas van en rojo. Con un pago parcial aparecen Pagado y Por pagar (§07). Con total 0: «El equipo Mogos publicará el monto cuando la cotización esté lista.»

  6. Rechazar ghost, como la web

    «Rechazar» es ghost y «Aprobar» es primary, lado a lado en el pie. Aprobar va a la derecha, bajo el pulgar. Son las mismas variantes de la web.

07Aprobar, rechazar, pagar

service-quote-actions.tsx · POST /:id/approve · /:id/reject · PaymentPortalSheet (MF-07)

Aprobar no pide confirmación, como en la web: el total y la recomendación están a la vista y el botón dice lo que hace. Rechazar sí la pide, con un diálogo destructivo y un motivo opcional de hasta 500 caracteres que se guarda en el historial. Las dos acciones son optimistas: el badge y el pie cambian al instante y vuelven atrás si el API falla. Una cotización aprobada y con saldo cambia su pie a «Pagar ahora», que abre el portal de pagos de MF-07 con entityType SERVICE_QUOTE.

Rechazar diálogo destructivo + motivo
9:41●●●
Búsqueda · Marítimo
COT-20260918-0014
PendienteChina → Venezuela
La recomendación de Mogos
Revisa la recomendación y apruébala para que empecemos.
RechazarAprobar
¿Rechazar esta cotización?
El equipo Mogos la revisará y podrá proponerte otra opción. Si quieres, cuéntanos por qué.
Motivo (opcional)
El precio está por encima de mi presupuesto.44/500
Rechazar cotizaciónCancelar
Aprobada el pie pasa a «Pagar ahora»
9:41●●●
Búsqueda · Marítimo
COT-20260918-0014
AprobadaChina → VenezuelaVigente hasta 2 oct 2026
La recomendación de Mogos
Elegimos un proveedor por producto. Esto es lo que incluye tu cotización.
Audífonos inalámbricos×50Soundcore · Shenzhen Audio Tech12 días de entrega · Garantía 12 meses
Cargador USB-C 65W×100Anker · Dongguan Power Co.9 días de entrega · Garantía 6 meses
Cotización aprobada

Ya puedes pagarla cuando quieras.

Tu cotización está aprobada. Paga para que iniciemos la compra.
Pagar ahora
Pago parcial Pagado · Por pagar
9:41●●●
Cargador USB-C 65W×100Anker · Dongguan Power Co.9 días de entrega · Garantía 6 meses
TotalUSD4,860.00
PagadoUSD 2,000.00
Por pagarUSD 2,860.00
Entrega estimada en 38 días
Desglose
Productos4,120.00
Flete marítimo estimado480.00
Gestión (5 %)206.00
Seguro54.00
Tu cotización está aprobada. Paga para que iniciemos la compra.
Pagar ahora
  1. La copia de la web, completa

    Diálogo: «¿Rechazar esta cotización?», el texto de la web, «Motivo (opcional)» con su placeholder, y los botones «Rechazar cotización» y «Cancelar». Toasts: «Cotización aprobada / Ya puedes pagarla cuando quieras.», «Cotización rechazada / El equipo Mogos la revisará.», «No pudimos aprobar la cotización», «No pudimos rechazar la cotización» y «Por favor intenta de nuevo». Háptica: success al aprobar y warning al abrir el diálogo de rechazo.

  2. Solo desde Pendiente

    El API acepta aprobar y rechazar solo en PENDING y responde 400 en cualquier otro estado, así que el pie de decisión solo existe en Pendiente. Si otro dispositivo ya decidió, el 400 revierte lo optimista, refresca el detalle y muestra el toast de error: no queda ningún botón huérfano.

  3. Pagar es el portal de MF-07, no otro

    PaymentPortalSheet con entityType SERVICE_QUOTE, el id de la cotización y la descripción «Pago de la cotización {code}». Mientras el portal abre, el botón muestra el spinner; si no abre, sale «No pudimos abrir el portal de pago». Al volver del portal, la cotización se refresca y el pie pasa a «Pagada» (§08). No se diseña nada nuevo.

  4. Pago parcial: dos cifras con color

    La web lo escribe en una línea («Pagado USD x · Por pagar USD y»). En la app son dos celdas lado a lado (verde lo pagado, ámbar lo pendiente), dentro de la card del Total y con los mismos números en mono. Mientras quede saldo, el pie sigue siendo «Pagar ahora».

08Cada estado dice una cosa

service-quote-actions.tsx · getActionState · serviceQuotes.actions.*

La web tiene un mensaje por estado en la card de acciones. En la app, solo los dos estados con acción (Decidir y Pagar) van en el pie fijo. Los demás son informativos y suben a una nota bajo el encabezado, la primera línea que se lee, y el cuerpo usa todo el alto. Nueva y En búsqueda no existen para el cliente: el API las filtra en la lista y responde 404 en el detalle, así que la app no les dedica copia ni color.

Borrador sin PDF, sin monto, sin pie
9:41●●●
Búsqueda · Marítimo
COT-20260922-0018
BorradorChina → Venezuela
El equipo Mogos está preparando tu cotización.
La recomendación de Mogos
Elegimos un proveedor por producto. Esto es lo que incluye tu cotización.
Audífonos inalámbricos×50Sin propuestas todavía
Cargador USB-C 65W×100Sin propuestas todavía
Total

El equipo Mogos publicará el monto cuando la cotización esté lista.

Los demás la nota, recortada 1:1
Aprobadasin monto aún
Aprobada. El equipo Mogos publicará el monto a pagar en breve.
AprobadapaymentStatus PAID · CLOSED
Pagada. Ya estamos trabajando en tu pedido.
RechazadaREJECTED
Rechazaste esta cotización.
VencidaEXPIRED
Esta cotización venció. Solicita una nueva si todavía la necesitas.
CanceladaCANCELLED
Esta cotización fue cancelada.
Estado (API)BadgeQué muestra el detallePDFAcción
NEW · SOURCING—nunca llegan al cliente (lista filtrada, detalle 404)——
DRAFTBorradornota «El equipo Mogos está preparando tu cotización.» · total sin montononinguna
PENDINGPendientepie «Revisa la recomendación y apruébala para que empecemos.»síRechazar · Aprobar
APPROVED + saldoAprobadapie «Tu cotización está aprobada. Paga para que iniciemos la compra.»síPagar ahora
APPROVED · monto 0Aprobadanota info «Aprobada. El equipo Mogos publicará el monto a pagar en breve.»síninguna
APPROVED · PAID/CLOSEDAprobadanota success «Pagada. Ya estamos trabajando en tu pedido.»sí · sello PAGADOninguna
REJECTEDRechazadanota error «Rechazaste esta cotización.»síninguna
EXPIREDVencidanota «Esta cotización venció. Solicita una nueva si todavía la necesitas.»síninguna
CANCELLEDCanceladanota «Esta cotización fue cancelada.»síninguna

Estados de carga del detalle: skeleton con la forma del encabezado y de las tres cards (la web usa 4 bloques genéricos). Error: DetailStateShell de MF-06 con «Error al cargar la cotización» y Reintentar. No encontrada: «Cotización no encontrada», el mismo 404 silencioso que protege la propiedad. Analytics: quotation_viewed al montar y quotation_dismissed {reason} al salir, los dos que dispara la web.

09El documento, en el visor que ya existe

[id]/document · use-service-quote-document.ts · PdfViewer (MF-04) · DocumentFallback

/(app)/service-quotes/[id]/document baja el PDF fresco de GET service-quotes/:id/document cada vez que se abre: el API lo renderiza con los pagos del momento y el sello PAGADO cuando corresponde. Lo pinta el PdfViewer nativo de MF-04 (react-native-pdf, no un WebView, porque Android no dibuja un PDF firmado dentro de un WebView), con compartir en el encabezado. Si el visor falla, DocumentFallback se lo pasa al visor del sistema. Nada nuevo que diseñar: la pantalla solo compone.

El documento PdfViewer + compartir
9:41●●●
Cotización
COT-20260918-0014
MOGOS GROUP
COTIZACIÓNCOT-20260918-0014
Producto · proveedorCant.
Audífonos inalámbricos · Shenzhen Audio Tech50
Cargador USB-C 65W · Dongguan Power Co.100
Flete marítimo estimado480.00
Gestión (5 %)206.00
Seguro54.00
TOTAL USD4,860.00
Página 1 de 1
Cargando DocumentSkeleton
9:41●●●
Cotización
COT-20260918-0014
Cargando documento...
No se pudo vuelve al detalle
9:41●●●
Cotización
COT-20260918-0014

Documento no encontrado

No pudimos abrir el documento en este momento. Vuelve a intentarlo en unos minutos.

Ver cotización

El documento del ejemplo es un esquema: el contenido real (datos del emisor, cuentas de pago, proforma bilingüe) lo decide el API y la propuesta mogos-cotizaciones de la web. La app sigue a la web: si la plantilla cambia, el visor no cambia. El título es «Cotización» con el código en mono debajo, como el visor de fletes. La web lo escribe fijo en español y la app lo pasa a i18n.

10Lo que hay que escribir en Moti

Moti + Reanimated · escala de MF-01 · useReducedMotion
PiezaQué animaDuración · easingReduced motion
Chips · búsquedala lista cambia con fundido corto; el skeleton solo aparece si la respuesta tarda más de 160 ms160 ms · ease-outswap directo
Card · filas · chipsPressScale de MF-01 al tocar80 mssin escala
Hoja de productosube con el teclado (curva del sistema); abre 420, cierra 260420 / 260 msfundido 80 ms
Fila de productoentra con fundido + 12 px; al eliminar se pliega y las de abajo suben260 ms · ease-in-outaparece / desaparece
Cotización creadatoast Sileo; anillo de marca en la card nueva que se apaga a los 1,2 s640 spring · 420toast directo, sin anillo
Aprobar (optimista)el badge cambia con fundido; el pie cambia de alto (Decidir → Pagar) con layout animation160 · 260 msswap directo
Rechazarvelo marino 70 % + diálogo desde escala .96260 ms · ease-outfundido 80 ms
PDFla página entra con fundido cuando termina de renderizar260 msdirecto

No hay momento orquestado: la MF es de lectura y decisión, y todo el motion sale de piezas que ya existen (Sileo, PressScale, hojas, layout animation). Nada pulsa ni dura más de 640 ms. Háptica: success al crear y al aprobar, warning al abrir el diálogo de rechazo.

11Lo cerrado y lo que decide Fabrizio

docs/specs/2026-09-22-mobile-cotizaciones.md · HOLD hasta OK
  • Cerrada · Fabrizio 2026-09-22

    Paridad estricta: web = verdad

    Fuera elegir o cambiar proveedor: no hay chip ni UI de select-options, y la recomendación es de solo lectura. Fuera el historial, en el detalle y en la lista. La descripción lleva «(Opcional)» como texto. Un solo CTA, «Crear cotización», que el server guarda en Borrador (no hay «Guardar borrador»). Productos en texto libre con cantidad numérica (mínimo 1). El DoD es aprobar la recomendación, como en la web.

  • Cerrada · Fabrizio 2026-09-22

    Sin botón «Historial»

    Se saca del todo, aunque la web lo tenga como ComingSoonButton: no está deshabilitado, no lleva badge «Pronto» y no abre el diálogo «Muy pronto». La lista tiene una sola acción, «Nueva cotización», más el stack de búsqueda y chips. Es la única diferencia a propósito con la web en esta pantalla. En la web queda como deuda un stub que no hace nada.

  • Cerrada · ley #28

    La lista es el stack de MF-06

    ListToolbar (el botón de filtros pasa a ser opcional), StatusChips con los 7 valores del Select de la web, InfiniteList*, useListSearch (?q, 300 ms) y createPersistedListFilters. Dominio nuevo: ServiceQuoteCard, el mapa estatus → badge y el agrupado Pendientes/Finalizadas. Hooks en hooks/service-quotes/, schemas en schemas/service-quotes/ con contract test, y las rutas solo componen.

  • Cerrada · mejora con motivo

    Scroll infinito, no página 1

    La web muestra solo 20 cotizaciones (perPage=20, sin paginar), lo cual es un bug. La app pagina con InfiniteList* y recalcula las secciones al cargar cada página. Queda anotado como deuda de la web.

  • Cerrada · paridad

    La solicitud es la de la web

    Dos cards, los mismos campos, defaults y mensajes zod, POST service-quotes, y la cotización nace en Borrador. Un solo CTA, «Crear cotización». La descripción lleva «(Opcional)» y puede ir vacía. Un único cambio de forma, porque la tabla no cabe en 390 px: productos como filas + hoja con teclado, con cantidad numérica (mínimo 1). Texto libre, sin catálogo, como la web.

  • Cerrada · forma

    El pie fijo solo si hay algo que hacer

    Decidir (Rechazar | Aprobar) y Pagar van en un pie fijo sobre el home indicator. Los estados informativos van en una nota bajo el encabezado. Aprobar sin confirmación, rechazar con diálogo + motivo de 500, las dos optimistas con rollback. Pagar es PaymentPortalSheet de MF-07.

  • Cerrada · reuso

    El PDF y los puentes ya existen

    PdfViewer nativo de MF-04 con compartir, DocumentFallback y skeleton. /code/:code entra como puente by-code/[code] con el CodeResolveScreen de MF-06 (404/403 → lista, en silencio), para cuando MF-10 cablee la notificación SERVICE_QUOTE → detalle. «Ver cotización» de Pagos (entity-types.ts) pasa a abrir el detalle.

  • Corrección del brief

    Lo que el inventario desmintió

    No hay eventos quote_* en esta superficie (son de la calculadora): la app porta quotation_viewed y quotation_dismissed. No hay catálogo en AddProductDialog. El historial y elegir opciones no existen en la web, así que tampoco en la app. El gate de perfil solo bloquea «Nueva cotización».

  • Deuda anotada

    Lo que la web debe y la app no repite

    La errata «Crear cotizacion»; el pill del detalle con amber, emerald y orange fuera de tokens y distinto de sus badges; perPage=20 sin paginar; error.message en crudo; «Cotización {code}» fijo sin i18n; claves legacy sin uso (summaryCard, resultsCard…); select-options sin guardia de estado (backend).

  • Testing

    DoD en iPhone = Fabrizio

    Crear una cotización con dos productos, verla en la lista en Borrador, recibir la respuesta del admin (Fabrizio desde el admin web), aprobar la recomendación, pagar desde el portal, abrir el PDF, y rechazar otra con motivo. C9 automática: expo export --platform web + visual-qa a 390×844 contra estas 19 maquetas (DECISIONS #4/#24).