@greatapps/common 1.1.455 → 1.1.456

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
1
  "use server";
2
- import { processImage } from "../services/image-processing.service";
3
2
  async function processImageAction(input) {
4
3
  try {
4
+ const { processImage } = await import("../services/image-processing.service");
5
5
  const base64Data = input.base64Image.replace(/^data:image\/\w+;base64,/, "");
6
6
  const binaryString = atob(base64Data);
7
7
  const bytes = new Uint8Array(binaryString.length);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/modules/images/actions/process-image.action.ts"],"sourcesContent":["'use server'\n\nimport { processImage } from '../services/image-processing.service'\nimport type {\n ProcessImageActionInput,\n ProcessImageActionOutput,\n} from '../types/image.type'\n\nexport async function processImageAction(\n input: ProcessImageActionInput\n): Promise<ProcessImageActionOutput> {\n try {\n const base64Data = input.base64Image.replace(/^data:image\\/\\w+;base64,/, '')\n const binaryString = atob(base64Data)\n const bytes = new Uint8Array(binaryString.length)\n for (let i = 0; i < binaryString.length; i++) {\n bytes[i] = binaryString.charCodeAt(i)\n }\n\n const result = await processImage({\n imageBytes: bytes,\n targetWidth: input.targetWidth,\n targetHeight: input.targetHeight,\n })\n\n const base64Output = btoa(String.fromCharCode(...result.bytes))\n\n return {\n success: true,\n base64Image: `data:${result.format};base64,${base64Output}`,\n }\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Erro ao processar imagem',\n }\n }\n}\n"],"mappings":";AAEA,SAAS,oBAAoB;AAM7B,eAAsB,mBACpB,OACmC;AACnC,MAAI;AACF,UAAM,aAAa,MAAM,YAAY,QAAQ,4BAA4B,EAAE;AAC3E,UAAM,eAAe,KAAK,UAAU;AACpC,UAAM,QAAQ,IAAI,WAAW,aAAa,MAAM;AAChD,aAAS,IAAI,GAAG,IAAI,aAAa,QAAQ,KAAK;AAC5C,YAAM,CAAC,IAAI,aAAa,WAAW,CAAC;AAAA,IACtC;AAEA,UAAM,SAAS,MAAM,aAAa;AAAA,MAChC,YAAY;AAAA,MACZ,aAAa,MAAM;AAAA,MACnB,cAAc,MAAM;AAAA,IACtB,CAAC;AAED,UAAM,eAAe,KAAK,OAAO,aAAa,GAAG,OAAO,KAAK,CAAC;AAE9D,WAAO;AAAA,MACL,SAAS;AAAA,MACT,aAAa,QAAQ,OAAO,MAAM,WAAW,YAAY;AAAA,IAC3D;AAAA,EACF,SAAS,OAAO;AACd,WAAO;AAAA,MACL,SAAS;AAAA,MACT,OAAO,iBAAiB,QAAQ,MAAM,UAAU;AAAA,IAClD;AAAA,EACF;AACF;","names":[]}
1
+ {"version":3,"sources":["../../../../src/modules/images/actions/process-image.action.ts"],"sourcesContent":["'use server'\n\nimport type {\n ProcessImageActionInput,\n ProcessImageActionOutput,\n} from '../types/image.type'\n\nexport async function processImageAction(\n input: ProcessImageActionInput\n): Promise<ProcessImageActionOutput> {\n try {\n // Import dinâmico para evitar erro de fs.createReadStream no edge runtime\n const { processImage } = await import('../services/image-processing.service')\n\n const base64Data = input.base64Image.replace(/^data:image\\/\\w+;base64,/, '')\n const binaryString = atob(base64Data)\n const bytes = new Uint8Array(binaryString.length)\n for (let i = 0; i < binaryString.length; i++) {\n bytes[i] = binaryString.charCodeAt(i)\n }\n\n const result = await processImage({\n imageBytes: bytes,\n targetWidth: input.targetWidth,\n targetHeight: input.targetHeight,\n })\n\n const base64Output = btoa(String.fromCharCode(...result.bytes))\n\n return {\n success: true,\n base64Image: `data:${result.format};base64,${base64Output}`,\n }\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Erro ao processar imagem',\n }\n }\n}\n"],"mappings":";AAOA,eAAsB,mBACpB,OACmC;AACnC,MAAI;AAEF,UAAM,EAAE,aAAa,IAAI,MAAM,OAAO,sCAAsC;AAE5E,UAAM,aAAa,MAAM,YAAY,QAAQ,4BAA4B,EAAE;AAC3E,UAAM,eAAe,KAAK,UAAU;AACpC,UAAM,QAAQ,IAAI,WAAW,aAAa,MAAM;AAChD,aAAS,IAAI,GAAG,IAAI,aAAa,QAAQ,KAAK;AAC5C,YAAM,CAAC,IAAI,aAAa,WAAW,CAAC;AAAA,IACtC;AAEA,UAAM,SAAS,MAAM,aAAa;AAAA,MAChC,YAAY;AAAA,MACZ,aAAa,MAAM;AAAA,MACnB,cAAc,MAAM;AAAA,IACtB,CAAC;AAED,UAAM,eAAe,KAAK,OAAO,aAAa,GAAG,OAAO,KAAK,CAAC;AAE9D,WAAO;AAAA,MACL,SAAS;AAAA,MACT,aAAa,QAAQ,OAAO,MAAM,WAAW,YAAY;AAAA,IAC3D;AAAA,EACF,SAAS,OAAO;AACd,WAAO;AAAA,MACL,SAAS;AAAA,MACT,OAAO,iBAAiB,QAAQ,MAAM,UAAU;AAAA,IAClD;AAAA,EACF;AACF;","names":[]}
@@ -1,29 +1,14 @@
1
1
  "use client";
2
2
  import { useState, useCallback } from "react";
3
- import { useMutation } from "@tanstack/react-query";
4
3
  import { compressImage } from "../utils/compress-image";
5
4
  import { cropImageToCanvas } from "../utils/crop-image";
6
5
  import { validateImage } from "../utils/validate-image";
7
- import { processImageAction } from "../actions/process-image.action";
8
6
  function useImageUpload(options) {
9
7
  const { config, onSuccess, onError } = options;
10
8
  const [originalImage, setOriginalImage] = useState(null);
11
9
  const [croppedPreview, setCroppedPreview] = useState(null);
12
10
  const [showCropModal, setShowCropModal] = useState(false);
13
- const processMutation = useMutation({
14
- mutationFn: processImageAction,
15
- onSuccess: (result) => {
16
- if (result.success && result.base64Image) {
17
- setCroppedPreview(result.base64Image);
18
- onSuccess?.(result.base64Image);
19
- } else {
20
- onError?.(result.error || "Erro desconhecido");
21
- }
22
- },
23
- onError: (error) => {
24
- onError?.(error instanceof Error ? error.message : "Erro ao processar");
25
- }
26
- });
11
+ const [isProcessing, setIsProcessing] = useState(false);
27
12
  const handleFileSelect = useCallback(
28
13
  async (file) => {
29
14
  const validation = validateImage(file);
@@ -47,6 +32,7 @@ function useImageUpload(options) {
47
32
  );
48
33
  const handleCropConfirm = useCallback(
49
34
  async (imageElement, cropArea) => {
35
+ setIsProcessing(true);
50
36
  try {
51
37
  const croppedBase64 = await cropImageToCanvas(
52
38
  imageElement,
@@ -56,23 +42,14 @@ function useImageUpload(options) {
56
42
  );
57
43
  setCroppedPreview(croppedBase64);
58
44
  setShowCropModal(false);
59
- processMutation.mutate({
60
- base64Image: croppedBase64,
61
- targetWidth: config.width,
62
- targetHeight: config.height,
63
- cropArea: {
64
- x: cropArea.x,
65
- y: cropArea.y,
66
- width: cropArea.width,
67
- height: cropArea.height,
68
- unit: cropArea.unit
69
- }
70
- });
45
+ onSuccess?.(croppedBase64);
71
46
  } catch {
72
47
  onError?.("Erro ao aplicar crop");
48
+ } finally {
49
+ setIsProcessing(false);
73
50
  }
74
51
  },
75
- [config, processMutation, onError]
52
+ [config, onSuccess, onError]
76
53
  );
77
54
  const clear = useCallback(() => {
78
55
  setOriginalImage(null);
@@ -83,7 +60,7 @@ function useImageUpload(options) {
83
60
  croppedPreview,
84
61
  showCropModal,
85
62
  config,
86
- isProcessing: processMutation.isPending,
63
+ isProcessing,
87
64
  handleFileSelect,
88
65
  handleCropConfirm,
89
66
  setShowCropModal,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/modules/images/hooks/use-image-upload.hook.ts"],"sourcesContent":["'use client'\n\nimport { useState, useCallback } from 'react'\nimport { useMutation } from '@tanstack/react-query'\nimport type { Crop } from 'react-image-crop'\nimport { compressImage } from '../utils/compress-image'\nimport { cropImageToCanvas } from '../utils/crop-image'\nimport { validateImage } from '../utils/validate-image'\nimport { processImageAction } from '../actions/process-image.action'\nimport type { ImageConfig } from '../types/image.type'\n\nexport interface UseImageUploadOptions {\n config: ImageConfig\n onSuccess?: (base64Image: string) => void\n onError?: (error: string) => void\n}\n\nexport function useImageUpload(options: UseImageUploadOptions) {\n const { config, onSuccess, onError } = options\n\n const [originalImage, setOriginalImage] = useState<string | null>(null)\n const [croppedPreview, setCroppedPreview] = useState<string | null>(null)\n const [showCropModal, setShowCropModal] = useState(false)\n\n const processMutation = useMutation({\n mutationFn: processImageAction,\n onSuccess: (result) => {\n if (result.success && result.base64Image) {\n setCroppedPreview(result.base64Image)\n onSuccess?.(result.base64Image)\n } else {\n onError?.(result.error || 'Erro desconhecido')\n }\n },\n onError: (error) => {\n onError?.(error instanceof Error ? error.message : 'Erro ao processar')\n },\n })\n\n const handleFileSelect = useCallback(\n async (file: File) => {\n const validation = validateImage(file)\n if (!validation.valid) {\n onError?.(validation.error || 'Arquivo inválido')\n return\n }\n\n try {\n const compressed = await compressImage(file)\n const reader = new FileReader()\n reader.onload = (e) => {\n setOriginalImage(e.target?.result as string)\n setShowCropModal(true)\n }\n reader.readAsDataURL(compressed)\n } catch {\n onError?.('Erro ao processar imagem')\n }\n },\n [onError]\n )\n\n const handleCropConfirm = useCallback(\n async (imageElement: HTMLImageElement, cropArea: Crop) => {\n try {\n const croppedBase64 = await cropImageToCanvas(\n imageElement,\n cropArea,\n config.width,\n config.height\n )\n\n setCroppedPreview(croppedBase64)\n setShowCropModal(false)\n\n processMutation.mutate({\n base64Image: croppedBase64,\n targetWidth: config.width,\n targetHeight: config.height,\n cropArea: {\n x: cropArea.x,\n y: cropArea.y,\n width: cropArea.width,\n height: cropArea.height,\n unit: cropArea.unit,\n },\n })\n } catch {\n onError?.('Erro ao aplicar crop')\n }\n },\n [config, processMutation, onError]\n )\n\n const clear = useCallback(() => {\n setOriginalImage(null)\n setCroppedPreview(null)\n }, [])\n\n return {\n originalImage,\n croppedPreview,\n showCropModal,\n config,\n isProcessing: processMutation.isPending,\n handleFileSelect,\n handleCropConfirm,\n setShowCropModal,\n clear,\n }\n}\n"],"mappings":";AAEA,SAAS,UAAU,mBAAmB;AACtC,SAAS,mBAAmB;AAE5B,SAAS,qBAAqB;AAC9B,SAAS,yBAAyB;AAClC,SAAS,qBAAqB;AAC9B,SAAS,0BAA0B;AAS5B,SAAS,eAAe,SAAgC;AAC7D,QAAM,EAAE,QAAQ,WAAW,QAAQ,IAAI;AAEvC,QAAM,CAAC,eAAe,gBAAgB,IAAI,SAAwB,IAAI;AACtE,QAAM,CAAC,gBAAgB,iBAAiB,IAAI,SAAwB,IAAI;AACxE,QAAM,CAAC,eAAe,gBAAgB,IAAI,SAAS,KAAK;AAExD,QAAM,kBAAkB,YAAY;AAAA,IAClC,YAAY;AAAA,IACZ,WAAW,CAAC,WAAW;AACrB,UAAI,OAAO,WAAW,OAAO,aAAa;AACxC,0BAAkB,OAAO,WAAW;AACpC,oBAAY,OAAO,WAAW;AAAA,MAChC,OAAO;AACL,kBAAU,OAAO,SAAS,mBAAmB;AAAA,MAC/C;AAAA,IACF;AAAA,IACA,SAAS,CAAC,UAAU;AAClB,gBAAU,iBAAiB,QAAQ,MAAM,UAAU,mBAAmB;AAAA,IACxE;AAAA,EACF,CAAC;AAED,QAAM,mBAAmB;AAAA,IACvB,OAAO,SAAe;AACpB,YAAM,aAAa,cAAc,IAAI;AACrC,UAAI,CAAC,WAAW,OAAO;AACrB,kBAAU,WAAW,SAAS,qBAAkB;AAChD;AAAA,MACF;AAEA,UAAI;AACF,cAAM,aAAa,MAAM,cAAc,IAAI;AAC3C,cAAM,SAAS,IAAI,WAAW;AAC9B,eAAO,SAAS,CAAC,MAAM;AACrB,2BAAiB,EAAE,QAAQ,MAAgB;AAC3C,2BAAiB,IAAI;AAAA,QACvB;AACA,eAAO,cAAc,UAAU;AAAA,MACjC,QAAQ;AACN,kBAAU,0BAA0B;AAAA,MACtC;AAAA,IACF;AAAA,IACA,CAAC,OAAO;AAAA,EACV;AAEA,QAAM,oBAAoB;AAAA,IACxB,OAAO,cAAgC,aAAmB;AACxD,UAAI;AACF,cAAM,gBAAgB,MAAM;AAAA,UAC1B;AAAA,UACA;AAAA,UACA,OAAO;AAAA,UACP,OAAO;AAAA,QACT;AAEA,0BAAkB,aAAa;AAC/B,yBAAiB,KAAK;AAEtB,wBAAgB,OAAO;AAAA,UACrB,aAAa;AAAA,UACb,aAAa,OAAO;AAAA,UACpB,cAAc,OAAO;AAAA,UACrB,UAAU;AAAA,YACR,GAAG,SAAS;AAAA,YACZ,GAAG,SAAS;AAAA,YACZ,OAAO,SAAS;AAAA,YAChB,QAAQ,SAAS;AAAA,YACjB,MAAM,SAAS;AAAA,UACjB;AAAA,QACF,CAAC;AAAA,MACH,QAAQ;AACN,kBAAU,sBAAsB;AAAA,MAClC;AAAA,IACF;AAAA,IACA,CAAC,QAAQ,iBAAiB,OAAO;AAAA,EACnC;AAEA,QAAM,QAAQ,YAAY,MAAM;AAC9B,qBAAiB,IAAI;AACrB,sBAAkB,IAAI;AAAA,EACxB,GAAG,CAAC,CAAC;AAEL,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,cAAc,gBAAgB;AAAA,IAC9B;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;","names":[]}
1
+ {"version":3,"sources":["../../../../src/modules/images/hooks/use-image-upload.hook.ts"],"sourcesContent":["'use client'\n\nimport { useState, useCallback } from 'react'\nimport type { Crop } from 'react-image-crop'\nimport { compressImage } from '../utils/compress-image'\nimport { cropImageToCanvas } from '../utils/crop-image'\nimport { validateImage } from '../utils/validate-image'\nimport type { ImageConfig } from '../types/image.type'\n\nexport interface UseImageUploadOptions {\n config: ImageConfig\n onSuccess?: (base64Image: string) => void\n onError?: (error: string) => void\n}\n\nexport function useImageUpload(options: UseImageUploadOptions) {\n const { config, onSuccess, onError } = options\n\n const [originalImage, setOriginalImage] = useState<string | null>(null)\n const [croppedPreview, setCroppedPreview] = useState<string | null>(null)\n const [showCropModal, setShowCropModal] = useState(false)\n const [isProcessing, setIsProcessing] = useState(false)\n\n const handleFileSelect = useCallback(\n async (file: File) => {\n const validation = validateImage(file)\n if (!validation.valid) {\n onError?.(validation.error || 'Arquivo inválido')\n return\n }\n\n try {\n const compressed = await compressImage(file)\n const reader = new FileReader()\n reader.onload = (e) => {\n setOriginalImage(e.target?.result as string)\n setShowCropModal(true)\n }\n reader.readAsDataURL(compressed)\n } catch {\n onError?.('Erro ao processar imagem')\n }\n },\n [onError]\n )\n\n const handleCropConfirm = useCallback(\n async (imageElement: HTMLImageElement, cropArea: Crop) => {\n setIsProcessing(true)\n try {\n // Crop é feito inteiramente no cliente via Canvas\n // Já produz imagem no tamanho final (config.width x config.height)\n const croppedBase64 = await cropImageToCanvas(\n imageElement,\n cropArea,\n config.width,\n config.height\n )\n\n setCroppedPreview(croppedBase64)\n setShowCropModal(false)\n onSuccess?.(croppedBase64)\n } catch {\n onError?.('Erro ao aplicar crop')\n } finally {\n setIsProcessing(false)\n }\n },\n [config, onSuccess, onError]\n )\n\n const clear = useCallback(() => {\n setOriginalImage(null)\n setCroppedPreview(null)\n }, [])\n\n return {\n originalImage,\n croppedPreview,\n showCropModal,\n config,\n isProcessing,\n handleFileSelect,\n handleCropConfirm,\n setShowCropModal,\n clear,\n }\n}\n"],"mappings":";AAEA,SAAS,UAAU,mBAAmB;AAEtC,SAAS,qBAAqB;AAC9B,SAAS,yBAAyB;AAClC,SAAS,qBAAqB;AASvB,SAAS,eAAe,SAAgC;AAC7D,QAAM,EAAE,QAAQ,WAAW,QAAQ,IAAI;AAEvC,QAAM,CAAC,eAAe,gBAAgB,IAAI,SAAwB,IAAI;AACtE,QAAM,CAAC,gBAAgB,iBAAiB,IAAI,SAAwB,IAAI;AACxE,QAAM,CAAC,eAAe,gBAAgB,IAAI,SAAS,KAAK;AACxD,QAAM,CAAC,cAAc,eAAe,IAAI,SAAS,KAAK;AAEtD,QAAM,mBAAmB;AAAA,IACvB,OAAO,SAAe;AACpB,YAAM,aAAa,cAAc,IAAI;AACrC,UAAI,CAAC,WAAW,OAAO;AACrB,kBAAU,WAAW,SAAS,qBAAkB;AAChD;AAAA,MACF;AAEA,UAAI;AACF,cAAM,aAAa,MAAM,cAAc,IAAI;AAC3C,cAAM,SAAS,IAAI,WAAW;AAC9B,eAAO,SAAS,CAAC,MAAM;AACrB,2BAAiB,EAAE,QAAQ,MAAgB;AAC3C,2BAAiB,IAAI;AAAA,QACvB;AACA,eAAO,cAAc,UAAU;AAAA,MACjC,QAAQ;AACN,kBAAU,0BAA0B;AAAA,MACtC;AAAA,IACF;AAAA,IACA,CAAC,OAAO;AAAA,EACV;AAEA,QAAM,oBAAoB;AAAA,IACxB,OAAO,cAAgC,aAAmB;AACxD,sBAAgB,IAAI;AACpB,UAAI;AAGF,cAAM,gBAAgB,MAAM;AAAA,UAC1B;AAAA,UACA;AAAA,UACA,OAAO;AAAA,UACP,OAAO;AAAA,QACT;AAEA,0BAAkB,aAAa;AAC/B,yBAAiB,KAAK;AACtB,oBAAY,aAAa;AAAA,MAC3B,QAAQ;AACN,kBAAU,sBAAsB;AAAA,MAClC,UAAE;AACA,wBAAgB,KAAK;AAAA,MACvB;AAAA,IACF;AAAA,IACA,CAAC,QAAQ,WAAW,OAAO;AAAA,EAC7B;AAEA,QAAM,QAAQ,YAAY,MAAM;AAC9B,qBAAiB,IAAI;AACrB,sBAAkB,IAAI;AAAA,EACxB,GAAG,CAAC,CAAC;AAEL,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@greatapps/common",
3
- "version": "1.1.455",
3
+ "version": "1.1.456",
4
4
  "description": "Shared library for GreatApps frontend applications",
5
5
  "main": "./dist/index.mjs",
6
6
  "types": "./src/index.ts",
@@ -1,6 +1,5 @@
1
1
  'use server'
2
2
 
3
- import { processImage } from '../services/image-processing.service'
4
3
  import type {
5
4
  ProcessImageActionInput,
6
5
  ProcessImageActionOutput,
@@ -10,6 +9,9 @@ export async function processImageAction(
10
9
  input: ProcessImageActionInput
11
10
  ): Promise<ProcessImageActionOutput> {
12
11
  try {
12
+ // Import dinâmico para evitar erro de fs.createReadStream no edge runtime
13
+ const { processImage } = await import('../services/image-processing.service')
14
+
13
15
  const base64Data = input.base64Image.replace(/^data:image\/\w+;base64,/, '')
14
16
  const binaryString = atob(base64Data)
15
17
  const bytes = new Uint8Array(binaryString.length)
@@ -1,12 +1,10 @@
1
1
  'use client'
2
2
 
3
3
  import { useState, useCallback } from 'react'
4
- import { useMutation } from '@tanstack/react-query'
5
4
  import type { Crop } from 'react-image-crop'
6
5
  import { compressImage } from '../utils/compress-image'
7
6
  import { cropImageToCanvas } from '../utils/crop-image'
8
7
  import { validateImage } from '../utils/validate-image'
9
- import { processImageAction } from '../actions/process-image.action'
10
8
  import type { ImageConfig } from '../types/image.type'
11
9
 
12
10
  export interface UseImageUploadOptions {
@@ -21,21 +19,7 @@ export function useImageUpload(options: UseImageUploadOptions) {
21
19
  const [originalImage, setOriginalImage] = useState<string | null>(null)
22
20
  const [croppedPreview, setCroppedPreview] = useState<string | null>(null)
23
21
  const [showCropModal, setShowCropModal] = useState(false)
24
-
25
- const processMutation = useMutation({
26
- mutationFn: processImageAction,
27
- onSuccess: (result) => {
28
- if (result.success && result.base64Image) {
29
- setCroppedPreview(result.base64Image)
30
- onSuccess?.(result.base64Image)
31
- } else {
32
- onError?.(result.error || 'Erro desconhecido')
33
- }
34
- },
35
- onError: (error) => {
36
- onError?.(error instanceof Error ? error.message : 'Erro ao processar')
37
- },
38
- })
22
+ const [isProcessing, setIsProcessing] = useState(false)
39
23
 
40
24
  const handleFileSelect = useCallback(
41
25
  async (file: File) => {
@@ -62,7 +46,10 @@ export function useImageUpload(options: UseImageUploadOptions) {
62
46
 
63
47
  const handleCropConfirm = useCallback(
64
48
  async (imageElement: HTMLImageElement, cropArea: Crop) => {
49
+ setIsProcessing(true)
65
50
  try {
51
+ // Crop é feito inteiramente no cliente via Canvas
52
+ // Já produz imagem no tamanho final (config.width x config.height)
66
53
  const croppedBase64 = await cropImageToCanvas(
67
54
  imageElement,
68
55
  cropArea,
@@ -72,24 +59,14 @@ export function useImageUpload(options: UseImageUploadOptions) {
72
59
 
73
60
  setCroppedPreview(croppedBase64)
74
61
  setShowCropModal(false)
75
-
76
- processMutation.mutate({
77
- base64Image: croppedBase64,
78
- targetWidth: config.width,
79
- targetHeight: config.height,
80
- cropArea: {
81
- x: cropArea.x,
82
- y: cropArea.y,
83
- width: cropArea.width,
84
- height: cropArea.height,
85
- unit: cropArea.unit,
86
- },
87
- })
62
+ onSuccess?.(croppedBase64)
88
63
  } catch {
89
64
  onError?.('Erro ao aplicar crop')
65
+ } finally {
66
+ setIsProcessing(false)
90
67
  }
91
68
  },
92
- [config, processMutation, onError]
69
+ [config, onSuccess, onError]
93
70
  )
94
71
 
95
72
  const clear = useCallback(() => {
@@ -102,7 +79,7 @@ export function useImageUpload(options: UseImageUploadOptions) {
102
79
  croppedPreview,
103
80
  showCropModal,
104
81
  config,
105
- isProcessing: processMutation.isPending,
82
+ isProcessing,
106
83
  handleFileSelect,
107
84
  handleCropConfirm,
108
85
  setShowCropModal,