Sprint 4 — Etapa 7B completada.
Some checks failed
/ Deploy to Cloudflare Pages (push) Has been cancelled
Some checks failed
/ Deploy to Cloudflare Pages (push) Has been cancelled
This commit is contained in:
158
sprints/sprint-4/ETAPA_7B_PROMPT.md
Normal file
158
sprints/sprint-4/ETAPA_7B_PROMPT.md
Normal file
@@ -0,0 +1,158 @@
|
||||
# Sprint 4 — Etapa 7B: Tres fixes post-validación visual
|
||||
|
||||
## Contexto
|
||||
|
||||
InQ ROI — React 18 + Vite + TypeScript + TanStack Router + Zustand + shadcn/ui + Tailwind.
|
||||
Etapa 7 completada con OK formal. Durante la validación visual del director se detectaron tres issues que entran en esta etapa.
|
||||
|
||||
---
|
||||
|
||||
## Fix 1 — Catálogo con contexto de proceso (Opción A aprobada)
|
||||
|
||||
### Problema
|
||||
|
||||
Cuando el usuario navega desde el ResourcesPanel del workspace al catálogo (`/recursos`), no hay forma de volver al proceso de origen ni de indicar que un recurso está disponible para usar en ese proceso.
|
||||
|
||||
### Solución
|
||||
|
||||
**Paso 1: ResourcesPanel — pasar contexto en la URL**
|
||||
|
||||
En `src/features/workspace/ResourcesPanel.tsx`, el link "Ver catálogo completo" debe incluir el `processId` del proceso actual como query param:
|
||||
|
||||
```typescript
|
||||
// Antes:
|
||||
navigate({ to: '/recursos' })
|
||||
|
||||
// Después:
|
||||
navigate({ to: '/recursos', search: { fromProcess: currentProcess.id } })
|
||||
```
|
||||
|
||||
**Paso 2: ResourceCatalogPage — detectar contexto y mostrar UI de retorno**
|
||||
|
||||
En `src/features/resources/ResourceCatalogPage.tsx`:
|
||||
|
||||
Leer el query param `fromProcess` (puede ser undefined si el usuario navegó directamente).
|
||||
|
||||
Si `fromProcess` está presente:
|
||||
|
||||
1. **Banner contextual** en la parte superior de la página (antes de la barra de herramientas), con fondo suave naranja InQ:
|
||||
```
|
||||
[←] Estás viendo el catálogo desde el proceso "[nombre del proceso]"
|
||||
Seleccioná un recurso y usalo en una actividad al volver al workspace.
|
||||
[← Volver al proceso]
|
||||
```
|
||||
- El nombre del proceso se resuelve buscando `fromProcess` en el store o con una query puntual a Supabase
|
||||
- El botón "← Volver al proceso" navega de vuelta a `/workspace/:processId`
|
||||
|
||||
2. **Botón "← Usar en proceso" en cada fila de la tabla** (columna Acciones, junto a editar/eliminar):
|
||||
- Solo visible cuando `fromProcess` está presente
|
||||
- Al hacer click: navega a `/workspace/:processId`
|
||||
- No hace ninguna asignación automática — la asignación sigue siendo en ActivityPanel
|
||||
- Tooltip: "Volver al workspace para asignar este recurso a una actividad"
|
||||
|
||||
**Colores del banner:**
|
||||
- Fondo: `#FEF3E7` (naranja InQ muy suave)
|
||||
- Borde izquierdo: `#F59845` (naranja InQ)
|
||||
- Texto secundario: `var(--color-text-secondary)`
|
||||
- Botón "Volver": estilo secundario (borde, sin relleno)
|
||||
|
||||
**Si `fromProcess` no está presente** (usuario llegó al catálogo directamente): sin banner, sin botón extra. La página funciona exactamente igual que en Etapa 7.
|
||||
|
||||
---
|
||||
|
||||
## Fix 2 — Redondeo del costo por hora para valores pequeños
|
||||
|
||||
### Problema
|
||||
|
||||
Un recurso con costo `$0.037/h` se muestra como `$0.04` — pérdida de información para recursos de bajo costo unitario (licencias de software, servicios cloud por hora, etc.).
|
||||
|
||||
### Solución
|
||||
|
||||
Crear o actualizar la función de formateo de costo por hora para que use precisión dinámica. Ubicar en `src/lib/format.ts` (o donde esté la función `formatCurrency` / `formatCostPerHour`):
|
||||
|
||||
```typescript
|
||||
export function formatCostPerHour(value: number, currency = 'USD'): string {
|
||||
if (value === 0) return '$0'
|
||||
|
||||
// Determinar decimales según magnitud
|
||||
let decimals: number
|
||||
if (value >= 100) decimals = 0 // $150/h → $150
|
||||
else if (value >= 10) decimals = 1 // $12.5/h → $12.5
|
||||
else if (value >= 1) decimals = 2 // $1.23/h → $1.23
|
||||
else if (value >= 0.1) decimals = 3 // $0.123/h → $0.123
|
||||
else decimals = 4 // $0.0123/h → $0.0123
|
||||
|
||||
return `$${value.toFixed(decimals)}`
|
||||
}
|
||||
```
|
||||
|
||||
Aplicar esta función en todos los lugares donde se muestra el costo por hora de un recurso:
|
||||
- Tabla del catálogo `/recursos`
|
||||
- ResourcesPanel (lista de recursos usados en el proceso)
|
||||
- ActivityPanel (selector de recursos y fila de recurso asignado)
|
||||
- Cualquier otro lugar donde aparezca `costPerHour`
|
||||
|
||||
**Verificación:** ingresar un recurso con costo `0.037` y confirmar que se muestra `$0.037` (no `$0.04`).
|
||||
|
||||
---
|
||||
|
||||
## Fix 3 — Google OAuth: forzar selector de cuenta
|
||||
|
||||
### Problema
|
||||
|
||||
Al hacer click en "Iniciar sesión con Google", el navegador usa directamente la sesión anterior sin mostrar el selector de cuentas de Google. Impide cambiar de cuenta o seleccionar entre múltiples cuentas del navegador.
|
||||
|
||||
### Solución
|
||||
|
||||
En `src/auth/SupabaseAuthService.ts`, en el método `signInWithGoogle()`, agregar `prompt: 'select_account'` en los `queryParams`:
|
||||
|
||||
```typescript
|
||||
async signInWithGoogle(): Promise<void> {
|
||||
const { error } = await supabase.auth.signInWithOAuth({
|
||||
provider: 'google',
|
||||
options: {
|
||||
redirectTo: `${window.location.origin}/auth/callback`,
|
||||
queryParams: {
|
||||
prompt: 'select_account', // 🆕 fuerza el selector de cuentas de Google
|
||||
},
|
||||
},
|
||||
})
|
||||
if (error) throw error
|
||||
}
|
||||
```
|
||||
|
||||
`prompt: 'select_account'` es un parámetro estándar de OAuth 2.0 / OpenID Connect que instruye a Google a siempre mostrar el selector de cuentas, incluso si hay una sesión activa.
|
||||
|
||||
---
|
||||
|
||||
## Qué NO entra en esta etapa
|
||||
|
||||
- Asignación automática de recursos desde el catálogo (eso sería Opción B — diferida)
|
||||
- Cambios en PDF, simulación o workspace salvo los indicados
|
||||
- Ningún cambio de schema en Supabase
|
||||
|
||||
---
|
||||
|
||||
## Orden de ejecución
|
||||
|
||||
1. Fix 3 — `SupabaseAuthService.signInWithGoogle()` (1 línea, más fácil de verificar primero)
|
||||
2. Fix 2 — función `formatCostPerHour` con precisión dinámica + aplicar en todos los contextos
|
||||
3. Fix 1 — query param en ResourcesPanel + banner + botón en ResourceCatalogPage
|
||||
4. `npm run build` — debe pasar sin errores TypeScript
|
||||
5. `npm run test` — debe mantener 521+ tests verdes
|
||||
6. Commit: `fix(sprint-4/etapa-7b): selector cuenta Google + redondeo costo/hora + contexto catálogo`
|
||||
|
||||
---
|
||||
|
||||
## Criterios de validación
|
||||
|
||||
- [ ] Login muestra el selector de cuentas de Google (no auto-login)
|
||||
- [ ] Recurso con costo `0.037` se muestra como `$0.037`, no `$0.04`
|
||||
- [ ] Recurso con costo `45` se muestra como `$45`, no `$45.00` (sin decimales innecesarios)
|
||||
- [ ] Navegar desde ResourcesPanel → catálogo muestra el banner con nombre del proceso
|
||||
- [ ] Botón "← Usar en proceso" aparece en cada fila cuando hay contexto de proceso
|
||||
- [ ] Click en "← Usar en proceso" navega a `/workspace/:processId`
|
||||
- [ ] Navegar a `/recursos` directamente (sin `fromProcess`) no muestra banner ni botón extra
|
||||
- [ ] Build limpio sin errores TypeScript
|
||||
- [ ] 521+ tests verdes
|
||||
- [ ] **Validación visual del director** antes del OK formal
|
||||
Reference in New Issue
Block a user