@greatapps/common 1.1.473 → 1.1.474

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.
Files changed (83) hide show
  1. package/dist/components/account/sections/MyProfileSection.mjs +1 -2
  2. package/dist/components/account/sections/MyProfileSection.mjs.map +1 -1
  3. package/dist/components/embeds/CrispEmbed.mjs +24 -60
  4. package/dist/components/embeds/CrispEmbed.mjs.map +1 -1
  5. package/dist/components/embeds/FrillEmbed.mjs +3 -10
  6. package/dist/components/embeds/FrillEmbed.mjs.map +1 -1
  7. package/dist/components/layouts/ProfilePopover.mjs +1 -2
  8. package/dist/components/layouts/ProfilePopover.mjs.map +1 -1
  9. package/dist/components/modals/cards/AddCardModal.mjs +6 -10
  10. package/dist/components/modals/cards/AddCardModal.mjs.map +1 -1
  11. package/dist/components/modals/cards/CardFormFields.mjs +15 -47
  12. package/dist/components/modals/cards/CardFormFields.mjs.map +1 -1
  13. package/dist/components/navigation/subcomponents/BottomLinks.mjs +2 -2
  14. package/dist/components/navigation/subcomponents/BottomLinks.mjs.map +1 -1
  15. package/dist/components/navigation/subcomponents/ProjectSelector.mjs +1 -1
  16. package/dist/components/navigation/subcomponents/ProjectSelector.mjs.map +1 -1
  17. package/dist/components/pages/notifications/Notifications.mjs +17 -27
  18. package/dist/components/pages/notifications/Notifications.mjs.map +1 -1
  19. package/dist/components/ui/form/Select.mjs +1 -1
  20. package/dist/components/ui/form/Select.mjs.map +1 -1
  21. package/dist/components/ui/overlay/Dialog.mjs +1 -2
  22. package/dist/components/ui/overlay/Dialog.mjs.map +1 -1
  23. package/dist/components/ui/overlay/Popover.mjs +1 -1
  24. package/dist/components/ui/overlay/Popover.mjs.map +1 -1
  25. package/dist/components/ui/overlay/Sheet.mjs +6 -8
  26. package/dist/components/ui/overlay/Sheet.mjs.map +1 -1
  27. package/dist/components/ui/overlay/Tooltip.mjs +1 -1
  28. package/dist/components/ui/overlay/Tooltip.mjs.map +1 -1
  29. package/dist/index.mjs +2 -50
  30. package/dist/index.mjs.map +1 -1
  31. package/dist/infra/utils/date.mjs +0 -11
  32. package/dist/infra/utils/date.mjs.map +1 -1
  33. package/dist/modules/auth/services/auth.service.mjs +1 -2
  34. package/dist/modules/auth/services/auth.service.mjs.map +1 -1
  35. package/dist/modules/plans/hooks/use-plan-by-id.hook.mjs +2 -21
  36. package/dist/modules/plans/hooks/use-plan-by-id.hook.mjs.map +1 -1
  37. package/dist/modules/plans/services/plans.service.mjs +10 -71
  38. package/dist/modules/plans/services/plans.service.mjs.map +1 -1
  39. package/dist/modules/plans/types/plan.type.mjs +0 -1
  40. package/dist/modules/plans/types/plan.type.mjs.map +1 -1
  41. package/dist/modules/subscriptions/types/subscription.type.mjs +1 -31
  42. package/dist/modules/subscriptions/types/subscription.type.mjs.map +1 -1
  43. package/dist/server.mjs +0 -6
  44. package/dist/server.mjs.map +1 -1
  45. package/package.json +1 -1
  46. package/src/components/navigation/ProjectSelectorPopover.tsx +1 -1
  47. package/src/components/ui/overlay/Sheet.tsx +9 -13
  48. package/dist/components/embeds/EmbedWidgets.mjs +0 -45
  49. package/dist/components/embeds/EmbedWidgets.mjs.map +0 -1
  50. package/dist/components/widgets/ImageUpload/ImageCropModal.mjs +0 -212
  51. package/dist/components/widgets/ImageUpload/ImageCropModal.mjs.map +0 -1
  52. package/dist/components/widgets/ImageUpload/ImageTooSmallModal.mjs +0 -51
  53. package/dist/components/widgets/ImageUpload/ImageTooSmallModal.mjs.map +0 -1
  54. package/dist/components/widgets/ImageUpload/ImageUpload.mjs +0 -122
  55. package/dist/components/widgets/ImageUpload/ImageUpload.mjs.map +0 -1
  56. package/dist/components/widgets/ImageUpload/index.mjs +0 -9
  57. package/dist/components/widgets/ImageUpload/index.mjs.map +0 -1
  58. package/dist/modules/images/actions/process-image.action.mjs +0 -31
  59. package/dist/modules/images/actions/process-image.action.mjs.map +0 -1
  60. package/dist/modules/images/constants/image.constants.mjs +0 -14
  61. package/dist/modules/images/constants/image.constants.mjs.map +0 -1
  62. package/dist/modules/images/hooks/use-image-upload.hook.mjs +0 -132
  63. package/dist/modules/images/hooks/use-image-upload.hook.mjs.map +0 -1
  64. package/dist/modules/images/services/image-processing.service.mjs +0 -65
  65. package/dist/modules/images/services/image-processing.service.mjs.map +0 -1
  66. package/dist/modules/images/types/image.type.mjs +0 -1
  67. package/dist/modules/images/types/image.type.mjs.map +0 -1
  68. package/dist/modules/images/utils/base64.mjs +0 -24
  69. package/dist/modules/images/utils/base64.mjs.map +0 -1
  70. package/dist/modules/images/utils/compress-image.mjs +0 -17
  71. package/dist/modules/images/utils/compress-image.mjs.map +0 -1
  72. package/dist/modules/images/utils/crop-image.mjs +0 -31
  73. package/dist/modules/images/utils/crop-image.mjs.map +0 -1
  74. package/dist/modules/images/utils/validate-image.mjs +0 -58
  75. package/dist/modules/images/utils/validate-image.mjs.map +0 -1
  76. package/dist/modules/plans/actions/list-plans.action.mjs +0 -17
  77. package/dist/modules/plans/actions/list-plans.action.mjs.map +0 -1
  78. package/dist/modules/plans/hooks/list-plans.hook.mjs +0 -22
  79. package/dist/modules/plans/hooks/list-plans.hook.mjs.map +0 -1
  80. package/dist/modules/plans/utils/map-api-plan-to-ui.mjs +0 -58
  81. package/dist/modules/plans/utils/map-api-plan-to-ui.mjs.map +0 -1
  82. package/dist/utils/format/currency.mjs +0 -13
  83. package/dist/utils/format/currency.mjs.map +0 -1
@@ -1,51 +0,0 @@
1
- "use client";
2
- import { jsx, jsxs } from "react/jsx-runtime";
3
- import {
4
- Dialog,
5
- DialogContent,
6
- DialogFooter,
7
- DialogHeader,
8
- DialogTitle
9
- } from "../../ui/overlay/Dialog";
10
- import { Button } from "../../ui/buttons/Button";
11
- function ImageTooSmallModal({
12
- open,
13
- onOpenChange,
14
- fileName,
15
- minWidth,
16
- minHeight,
17
- onSelectAnother,
18
- onCancel
19
- }) {
20
- const dimensionText = `${minWidth}x${minHeight}px`;
21
- return /* @__PURE__ */ jsx(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxs(
22
- DialogContent,
23
- {
24
- className: "w-full md:w-[480px]! lg:w-[480px]! max-w-[480px]! max-[480px]:w-[calc(100%-32px)] p-0 gap-0 z-[1003]!",
25
- overlayClassName: "z-[1002]!",
26
- children: [
27
- /* @__PURE__ */ jsx(DialogHeader, { className: "p-5", children: /* @__PURE__ */ jsxs(DialogTitle, { className: "text-center text-[16px]!", children: [
28
- "Foto menor que ",
29
- dimensionText
30
- ] }) }),
31
- /* @__PURE__ */ jsx("div", { className: "px-5 pb-5", children: /* @__PURE__ */ jsxs("p", { className: "paragraph-small-regular text-zinc-600 text-center", children: [
32
- 'O arquivo "',
33
- fileName,
34
- '" \xE9 menor que ',
35
- dimensionText,
36
- ". Fa\xE7a envio de uma imagem com pelo menos ",
37
- dimensionText,
38
- " para continuar."
39
- ] }) }),
40
- /* @__PURE__ */ jsxs(DialogFooter, { className: "flex-row! items-center justify-start! gap-3 p-5 border-t border-zinc-200", children: [
41
- /* @__PURE__ */ jsx(Button, { onClick: onSelectAnother, children: "Enviar outra" }),
42
- /* @__PURE__ */ jsx(Button, { variant: "secondary", onClick: onCancel, children: "Cancelar" })
43
- ] })
44
- ]
45
- }
46
- ) });
47
- }
48
- export {
49
- ImageTooSmallModal
50
- };
51
- //# sourceMappingURL=ImageTooSmallModal.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../../../src/components/widgets/ImageUpload/ImageTooSmallModal.tsx"],"sourcesContent":["'use client'\n\nimport {\n Dialog,\n DialogContent,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} from '../../ui/overlay/Dialog'\nimport { Button } from '../../ui/buttons/Button'\n\ninterface ImageTooSmallModalProps {\n open: boolean\n onOpenChange: (open: boolean) => void\n fileName: string\n minWidth: number\n minHeight: number\n onSelectAnother: () => void\n onCancel: () => void\n}\n\nexport function ImageTooSmallModal({\n open,\n onOpenChange,\n fileName,\n minWidth,\n minHeight,\n onSelectAnother,\n onCancel,\n}: ImageTooSmallModalProps) {\n const dimensionText = `${minWidth}x${minHeight}px`\n\n return (\n <Dialog open={open} onOpenChange={onOpenChange}>\n <DialogContent\n className=\"w-full md:w-[480px]! lg:w-[480px]! max-w-[480px]! max-[480px]:w-[calc(100%-32px)] p-0 gap-0 z-[1003]!\"\n overlayClassName=\"z-[1002]!\"\n >\n <DialogHeader className=\"p-5\">\n <DialogTitle className=\"text-center text-[16px]!\">\n Foto menor que {dimensionText}\n </DialogTitle>\n </DialogHeader>\n\n <div className=\"px-5 pb-5\">\n <p className=\"paragraph-small-regular text-zinc-600 text-center\">\n O arquivo \"{fileName}\" é menor que {dimensionText}. Faça envio de\n uma imagem com pelo menos {dimensionText} para continuar.\n </p>\n </div>\n\n <DialogFooter className=\"flex-row! items-center justify-start! gap-3 p-5 border-t border-zinc-200\">\n <Button onClick={onSelectAnother}>Enviar outra</Button>\n <Button variant=\"secondary\" onClick={onCancel}>\n Cancelar\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n )\n}\n"],"mappings":";AAsCQ,cACE,YADF;AApCR;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,cAAc;AAYhB,SAAS,mBAAmB;AAAA,EACjC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA4B;AAC1B,QAAM,gBAAgB,GAAG,QAAQ,IAAI,SAAS;AAE9C,SACE,oBAAC,UAAO,MAAY,cAClB;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MACV,kBAAiB;AAAA,MAEjB;AAAA,4BAAC,gBAAa,WAAU,OACtB,+BAAC,eAAY,WAAU,4BAA2B;AAAA;AAAA,UAChC;AAAA,WAClB,GACF;AAAA,QAEA,oBAAC,SAAI,WAAU,aACb,+BAAC,OAAE,WAAU,qDAAoD;AAAA;AAAA,UACnD;AAAA,UAAS;AAAA,UAAe;AAAA,UAAc;AAAA,UACvB;AAAA,UAAc;AAAA,WAC3C,GACF;AAAA,QAEA,qBAAC,gBAAa,WAAU,4EACtB;AAAA,8BAAC,UAAO,SAAS,iBAAiB,0BAAY;AAAA,UAC9C,oBAAC,UAAO,SAAQ,aAAY,SAAS,UAAU,sBAE/C;AAAA,WACF;AAAA;AAAA;AAAA,EACF,GACF;AAEJ;","names":[]}
@@ -1,122 +0,0 @@
1
- "use client";
2
- import { jsx, jsxs } from "react/jsx-runtime";
3
- import { useRef } from "react";
4
- import { useImageUpload } from "../../../modules/images/hooks/use-image-upload.hook";
5
- import { ACCEPTED_IMAGE_FORMATS_STRING } from "../../../modules/images/constants/image.constants";
6
- import { ImageCropModal } from "./ImageCropModal";
7
- import { Button } from "../../ui/buttons/Button";
8
- function ImageUpload({
9
- config,
10
- value,
11
- onChange,
12
- onError,
13
- className
14
- }) {
15
- const inputRef = useRef(null);
16
- const {
17
- originalImage,
18
- croppedPreview,
19
- showCropModal,
20
- isProcessing,
21
- handleFileSelect,
22
- handleCropConfirm,
23
- setShowCropModal,
24
- clear
25
- } = useImageUpload({
26
- config,
27
- onSuccess: (base64) => onChange?.(base64),
28
- onError
29
- });
30
- const displayImage = croppedPreview || value;
31
- return /* @__PURE__ */ jsxs("div", { className, children: [
32
- /* @__PURE__ */ jsx(
33
- "input",
34
- {
35
- ref: inputRef,
36
- type: "file",
37
- accept: ACCEPTED_IMAGE_FORMATS_STRING,
38
- className: "hidden",
39
- onChange: (e) => {
40
- const file = e.target.files?.[0];
41
- if (file) handleFileSelect(file);
42
- e.target.value = "";
43
- }
44
- }
45
- ),
46
- displayImage ? /* @__PURE__ */ jsxs("div", { className: "relative", children: [
47
- /* @__PURE__ */ jsx(
48
- "div",
49
- {
50
- className: "overflow-hidden rounded-lg border border-gray-200",
51
- style: { aspectRatio: config.aspectRatio },
52
- children: /* @__PURE__ */ jsx(
53
- "img",
54
- {
55
- src: displayImage,
56
- alt: "Preview",
57
- className: "w-full h-full object-cover"
58
- }
59
- )
60
- }
61
- ),
62
- /* @__PURE__ */ jsxs("div", { className: "flex gap-2 mt-2", children: [
63
- /* @__PURE__ */ jsx(
64
- Button,
65
- {
66
- variant: "secondary",
67
- size: "sm",
68
- onClick: () => inputRef.current?.click(),
69
- disabled: isProcessing,
70
- children: "Trocar"
71
- }
72
- ),
73
- /* @__PURE__ */ jsx(
74
- Button,
75
- {
76
- variant: "secondary",
77
- size: "sm",
78
- onClick: () => {
79
- clear();
80
- onChange?.("");
81
- },
82
- disabled: isProcessing,
83
- children: "Remover"
84
- }
85
- )
86
- ] }),
87
- isProcessing && /* @__PURE__ */ jsx("p", { className: "paragraph-small-regular text-gray-500 mt-2", children: "Processando..." })
88
- ] }) : /* @__PURE__ */ jsxs(
89
- "button",
90
- {
91
- type: "button",
92
- onClick: () => inputRef.current?.click(),
93
- className: "w-full border-2 border-dashed border-gray-300 rounded-lg p-8 text-center hover:border-gray-400 transition-colors",
94
- style: { aspectRatio: config.aspectRatio },
95
- children: [
96
- /* @__PURE__ */ jsx("p", { className: "paragraph-medium-regular text-gray-600", children: "Clique para enviar imagem" }),
97
- /* @__PURE__ */ jsxs("p", { className: "paragraph-small-regular text-gray-400 mt-1", children: [
98
- "Tamanho recomendado: ",
99
- config.width,
100
- " x ",
101
- config.height,
102
- " pixels"
103
- ] })
104
- ]
105
- }
106
- ),
107
- originalImage && /* @__PURE__ */ jsx(
108
- ImageCropModal,
109
- {
110
- open: showCropModal,
111
- onOpenChange: setShowCropModal,
112
- imageSrc: originalImage,
113
- aspectRatio: config.aspectRatio,
114
- onConfirm: handleCropConfirm
115
- }
116
- )
117
- ] });
118
- }
119
- export {
120
- ImageUpload
121
- };
122
- //# sourceMappingURL=ImageUpload.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../../../src/components/widgets/ImageUpload/ImageUpload.tsx"],"sourcesContent":["'use client'\n\nimport { useRef } from 'react'\nimport { useImageUpload } from '../../../modules/images/hooks/use-image-upload.hook'\nimport { ACCEPTED_IMAGE_FORMATS_STRING } from '../../../modules/images/constants/image.constants'\nimport { ImageCropModal } from './ImageCropModal'\nimport { Button } from '../../ui/buttons/Button'\nimport type { ImageConfig } from '../../../modules/images/types/image.type'\n\ninterface ImageUploadProps {\n config: ImageConfig\n value?: string\n onChange?: (value: string) => void\n onError?: (error: string) => void\n className?: string\n}\n\nexport function ImageUpload({\n config,\n value,\n onChange,\n onError,\n className,\n}: ImageUploadProps) {\n const inputRef = useRef<HTMLInputElement>(null)\n\n const {\n originalImage,\n croppedPreview,\n showCropModal,\n isProcessing,\n handleFileSelect,\n handleCropConfirm,\n setShowCropModal,\n clear,\n } = useImageUpload({\n config,\n onSuccess: (base64) => onChange?.(base64),\n onError,\n })\n\n const displayImage = croppedPreview || value\n\n return (\n <div className={className}>\n <input\n ref={inputRef}\n type=\"file\"\n accept={ACCEPTED_IMAGE_FORMATS_STRING}\n className=\"hidden\"\n onChange={(e) => {\n const file = e.target.files?.[0]\n if (file) handleFileSelect(file)\n e.target.value = ''\n }}\n />\n\n {displayImage ? (\n <div className=\"relative\">\n <div\n className=\"overflow-hidden rounded-lg border border-gray-200\"\n style={{ aspectRatio: config.aspectRatio }}\n >\n <img\n src={displayImage}\n alt=\"Preview\"\n className=\"w-full h-full object-cover\"\n />\n </div>\n\n <div className=\"flex gap-2 mt-2\">\n <Button\n variant=\"secondary\"\n size=\"sm\"\n onClick={() => inputRef.current?.click()}\n disabled={isProcessing}\n >\n Trocar\n </Button>\n <Button\n variant=\"secondary\"\n size=\"sm\"\n onClick={() => {\n clear()\n onChange?.('')\n }}\n disabled={isProcessing}\n >\n Remover\n </Button>\n </div>\n\n {isProcessing && (\n <p className=\"paragraph-small-regular text-gray-500 mt-2\">\n Processando...\n </p>\n )}\n </div>\n ) : (\n <button\n type=\"button\"\n onClick={() => inputRef.current?.click()}\n className=\"w-full border-2 border-dashed border-gray-300 rounded-lg p-8 text-center hover:border-gray-400 transition-colors\"\n style={{ aspectRatio: config.aspectRatio }}\n >\n <p className=\"paragraph-medium-regular text-gray-600\">\n Clique para enviar imagem\n </p>\n <p className=\"paragraph-small-regular text-gray-400 mt-1\">\n Tamanho recomendado: {config.width} x {config.height} pixels\n </p>\n </button>\n )}\n\n {originalImage && (\n <ImageCropModal\n open={showCropModal}\n onOpenChange={setShowCropModal}\n imageSrc={originalImage}\n aspectRatio={config.aspectRatio}\n onConfirm={handleCropConfirm}\n />\n )}\n </div>\n )\n}\n"],"mappings":";AA6CM,cAyBI,YAzBJ;AA3CN,SAAS,cAAc;AACvB,SAAS,sBAAsB;AAC/B,SAAS,qCAAqC;AAC9C,SAAS,sBAAsB;AAC/B,SAAS,cAAc;AAWhB,SAAS,YAAY;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAqB;AACnB,QAAM,WAAW,OAAyB,IAAI;AAE9C,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI,eAAe;AAAA,IACjB;AAAA,IACA,WAAW,CAAC,WAAW,WAAW,MAAM;AAAA,IACxC;AAAA,EACF,CAAC;AAED,QAAM,eAAe,kBAAkB;AAEvC,SACE,qBAAC,SAAI,WACH;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,KAAK;AAAA,QACL,MAAK;AAAA,QACL,QAAQ;AAAA,QACR,WAAU;AAAA,QACV,UAAU,CAAC,MAAM;AACf,gBAAM,OAAO,EAAE,OAAO,QAAQ,CAAC;AAC/B,cAAI,KAAM,kBAAiB,IAAI;AAC/B,YAAE,OAAO,QAAQ;AAAA,QACnB;AAAA;AAAA,IACF;AAAA,IAEC,eACC,qBAAC,SAAI,WAAU,YACb;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,WAAU;AAAA,UACV,OAAO,EAAE,aAAa,OAAO,YAAY;AAAA,UAEzC;AAAA,YAAC;AAAA;AAAA,cACC,KAAK;AAAA,cACL,KAAI;AAAA,cACJ,WAAU;AAAA;AAAA,UACZ;AAAA;AAAA,MACF;AAAA,MAEA,qBAAC,SAAI,WAAU,mBACb;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,SAAQ;AAAA,YACR,MAAK;AAAA,YACL,SAAS,MAAM,SAAS,SAAS,MAAM;AAAA,YACvC,UAAU;AAAA,YACX;AAAA;AAAA,QAED;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC,SAAQ;AAAA,YACR,MAAK;AAAA,YACL,SAAS,MAAM;AACb,oBAAM;AACN,yBAAW,EAAE;AAAA,YACf;AAAA,YACA,UAAU;AAAA,YACX;AAAA;AAAA,QAED;AAAA,SACF;AAAA,MAEC,gBACC,oBAAC,OAAE,WAAU,8CAA6C,4BAE1D;AAAA,OAEJ,IAEA;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,SAAS,MAAM,SAAS,SAAS,MAAM;AAAA,QACvC,WAAU;AAAA,QACV,OAAO,EAAE,aAAa,OAAO,YAAY;AAAA,QAEzC;AAAA,8BAAC,OAAE,WAAU,0CAAyC,uCAEtD;AAAA,UACA,qBAAC,OAAE,WAAU,8CAA6C;AAAA;AAAA,YAClC,OAAO;AAAA,YAAM;AAAA,YAAI,OAAO;AAAA,YAAO;AAAA,aACvD;AAAA;AAAA;AAAA,IACF;AAAA,IAGD,iBACC;AAAA,MAAC;AAAA;AAAA,QACC,MAAM;AAAA,QACN,cAAc;AAAA,QACd,UAAU;AAAA,QACV,aAAa,OAAO;AAAA,QACpB,WAAW;AAAA;AAAA,IACb;AAAA,KAEJ;AAEJ;","names":[]}
@@ -1,9 +0,0 @@
1
- import { ImageUpload } from "./ImageUpload";
2
- import { ImageCropModal } from "./ImageCropModal";
3
- import { ImageTooSmallModal } from "./ImageTooSmallModal";
4
- export {
5
- ImageCropModal,
6
- ImageTooSmallModal,
7
- ImageUpload
8
- };
9
- //# sourceMappingURL=index.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../../../src/components/widgets/ImageUpload/index.ts"],"sourcesContent":["export { ImageUpload } from './ImageUpload'\nexport { ImageCropModal } from './ImageCropModal'\nexport { ImageTooSmallModal } from './ImageTooSmallModal'\n"],"mappings":"AAAA,SAAS,mBAAmB;AAC5B,SAAS,sBAAsB;AAC/B,SAAS,0BAA0B;","names":[]}
@@ -1,31 +0,0 @@
1
- "use server";
2
- async function processImageAction(input) {
3
- try {
4
- const { processImage } = await import("../services/image-processing.service");
5
- const base64Data = input.base64Image.replace(/^data:image\/\w+;base64,/, "");
6
- const binaryString = atob(base64Data);
7
- const bytes = new Uint8Array(binaryString.length);
8
- for (let i = 0; i < binaryString.length; i++) {
9
- bytes[i] = binaryString.charCodeAt(i);
10
- }
11
- const result = await processImage({
12
- imageBytes: bytes,
13
- targetWidth: input.targetWidth,
14
- targetHeight: input.targetHeight
15
- });
16
- const base64Output = btoa(String.fromCharCode(...result.bytes));
17
- return {
18
- success: true,
19
- base64Image: `data:${result.format};base64,${base64Output}`
20
- };
21
- } catch (error) {
22
- return {
23
- success: false,
24
- error: error instanceof Error ? error.message : "Erro ao processar imagem"
25
- };
26
- }
27
- }
28
- export {
29
- processImageAction
30
- };
31
- //# sourceMappingURL=process-image.action.mjs.map
@@ -1 +0,0 @@
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,14 +0,0 @@
1
- const ACCEPTED_IMAGE_FORMATS = [
2
- "image/png",
3
- "image/jpeg",
4
- "image/webp",
5
- "image/gif"
6
- ];
7
- const ACCEPTED_IMAGE_FORMATS_STRING = ACCEPTED_IMAGE_FORMATS.join(",");
8
- const MAX_FILE_SIZE_MB = 100;
9
- export {
10
- ACCEPTED_IMAGE_FORMATS,
11
- ACCEPTED_IMAGE_FORMATS_STRING,
12
- MAX_FILE_SIZE_MB
13
- };
14
- //# sourceMappingURL=image.constants.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../../../src/modules/images/constants/image.constants.ts"],"sourcesContent":["export const ACCEPTED_IMAGE_FORMATS = [\n 'image/png',\n 'image/jpeg',\n 'image/webp',\n 'image/gif',\n] as const\n\n/** String para usar no atributo accept de inputs de arquivo */\nexport const ACCEPTED_IMAGE_FORMATS_STRING = ACCEPTED_IMAGE_FORMATS.join(',')\n\nexport const MAX_FILE_SIZE_MB = 100\n"],"mappings":"AAAO,MAAM,yBAAyB;AAAA,EACpC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAGO,MAAM,gCAAgC,uBAAuB,KAAK,GAAG;AAErE,MAAM,mBAAmB;","names":[]}
@@ -1,132 +0,0 @@
1
- "use client";
2
- import { useState, useCallback, useRef, useEffect } from "react";
3
- import { cropImageToCanvas } from "../utils/crop-image";
4
- import { validateImage } from "../utils/validate-image";
5
- function useImageUpload(options) {
6
- const { config, onSuccess, onError } = options;
7
- const onSuccessRef = useRef(onSuccess);
8
- const onErrorRef = useRef(onError);
9
- useEffect(() => {
10
- onSuccessRef.current = onSuccess;
11
- onErrorRef.current = onError;
12
- }, [onSuccess, onError]);
13
- const [originalImage, setOriginalImage] = useState(null);
14
- const [croppedPreview, setCroppedPreview] = useState(null);
15
- const [showCropModal, setShowCropModal] = useState(false);
16
- const [showTooSmallModal, setShowTooSmallModal] = useState(false);
17
- const [tooSmallError, setTooSmallError] = useState(null);
18
- const [isProcessing, setIsProcessing] = useState(false);
19
- const fileInputRef = useRef(null);
20
- const currentFileName = useRef("");
21
- const checkMinimumDimensions = useCallback(
22
- (naturalWidth, naturalHeight) => {
23
- const { width: minW, height: minH, aspectRatio } = config;
24
- const imgAspect = naturalWidth / naturalHeight;
25
- if (imgAspect >= aspectRatio) {
26
- const cropHeight = naturalHeight;
27
- const cropWidth = cropHeight * aspectRatio;
28
- return cropWidth >= minW && cropHeight >= minH;
29
- } else {
30
- const cropWidth = naturalWidth;
31
- const cropHeight = cropWidth / aspectRatio;
32
- return cropWidth >= minW && cropHeight >= minH;
33
- }
34
- },
35
- [config]
36
- );
37
- const handleFileSelect = useCallback(
38
- (file) => {
39
- const validation = validateImage(file);
40
- if (!validation.valid) {
41
- onErrorRef.current?.(validation.error || "Arquivo inv\xE1lido");
42
- return;
43
- }
44
- currentFileName.current = file.name;
45
- const reader = new FileReader();
46
- reader.onload = (e) => {
47
- const base64 = e.target?.result;
48
- setOriginalImage(base64);
49
- const img = new Image();
50
- img.onload = () => {
51
- const { naturalWidth, naturalHeight } = img;
52
- if (checkMinimumDimensions(naturalWidth, naturalHeight)) {
53
- setShowCropModal(true);
54
- } else {
55
- setTooSmallError({
56
- fileName: currentFileName.current,
57
- minWidth: config.width,
58
- minHeight: config.height
59
- });
60
- setShowTooSmallModal(true);
61
- }
62
- };
63
- img.src = base64;
64
- };
65
- reader.readAsDataURL(file);
66
- },
67
- [config, checkMinimumDimensions]
68
- );
69
- const handleImageLoadInModal = useCallback(
70
- (_naturalWidth, _naturalHeight) => {
71
- },
72
- []
73
- );
74
- const handleSelectAnotherFile = useCallback(() => {
75
- setShowTooSmallModal(false);
76
- setTooSmallError(null);
77
- fileInputRef.current?.click();
78
- }, []);
79
- const handleCancelTooSmall = useCallback(() => {
80
- setShowTooSmallModal(false);
81
- setShowCropModal(false);
82
- setTooSmallError(null);
83
- setOriginalImage(null);
84
- }, []);
85
- const handleCropConfirm = useCallback(
86
- async (imageElement, cropArea) => {
87
- setIsProcessing(true);
88
- try {
89
- const croppedBase64 = await cropImageToCanvas(
90
- imageElement,
91
- cropArea,
92
- config.width,
93
- config.height
94
- );
95
- setCroppedPreview(croppedBase64);
96
- setShowCropModal(false);
97
- onSuccessRef.current?.(croppedBase64);
98
- } catch {
99
- onErrorRef.current?.("Erro ao aplicar crop");
100
- } finally {
101
- setIsProcessing(false);
102
- }
103
- },
104
- [config]
105
- );
106
- const clear = useCallback(() => {
107
- setOriginalImage(null);
108
- setCroppedPreview(null);
109
- }, []);
110
- return {
111
- originalImage,
112
- croppedPreview,
113
- showCropModal,
114
- showTooSmallModal,
115
- tooSmallError,
116
- config,
117
- isProcessing,
118
- fileInputRef,
119
- handleFileSelect,
120
- handleCropConfirm,
121
- handleImageLoadInModal,
122
- handleSelectAnotherFile,
123
- handleCancelTooSmall,
124
- setShowCropModal,
125
- setShowTooSmallModal,
126
- clear
127
- };
128
- }
129
- export {
130
- useImageUpload
131
- };
132
- //# sourceMappingURL=use-image-upload.hook.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../../../src/modules/images/hooks/use-image-upload.hook.ts"],"sourcesContent":["'use client'\n\nimport { useState, useCallback, useRef, useEffect } from 'react'\nimport type { Crop } from 'react-image-crop'\nimport { cropImageToCanvas } from '../utils/crop-image'\nimport { validateImage } from '../utils/validate-image'\nimport type { ImageConfig } from '../types/image.type'\n\nexport interface ImageTooSmallError {\n fileName: string\n minWidth: number\n minHeight: number\n}\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 // Refs para manter callbacks sempre atualizados (evita stale closures)\n const onSuccessRef = useRef(onSuccess)\n const onErrorRef = useRef(onError)\n useEffect(() => {\n onSuccessRef.current = onSuccess\n onErrorRef.current = onError\n }, [onSuccess, onError])\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 [showTooSmallModal, setShowTooSmallModal] = useState(false)\n const [tooSmallError, setTooSmallError] = useState<ImageTooSmallError | null>(null)\n const [isProcessing, setIsProcessing] = useState(false)\n const fileInputRef = useRef<HTMLInputElement>(null)\n const currentFileName = useRef<string>('')\n\n // Verifica se a imagem cabe o crop mínimo\n const checkMinimumDimensions = useCallback(\n (naturalWidth: number, naturalHeight: number): boolean => {\n const { width: minW, height: minH, aspectRatio } = config\n const imgAspect = naturalWidth / naturalHeight\n\n if (imgAspect >= aspectRatio) {\n const cropHeight = naturalHeight\n const cropWidth = cropHeight * aspectRatio\n return cropWidth >= minW && cropHeight >= minH\n } else {\n const cropWidth = naturalWidth\n const cropHeight = cropWidth / aspectRatio\n return cropWidth >= minW && cropHeight >= minH\n }\n },\n [config]\n )\n\n // Valida dimensões ANTES de abrir qualquer modal\n const handleFileSelect = useCallback(\n (file: File) => {\n const validation = validateImage(file)\n if (!validation.valid) {\n onErrorRef.current?.(validation.error || 'Arquivo inválido')\n return\n }\n\n currentFileName.current = file.name\n\n // Converte para base64\n const reader = new FileReader()\n reader.onload = (e) => {\n const base64 = e.target?.result as string\n setOriginalImage(base64)\n\n // Carrega imagem em memória para verificar dimensões ANTES de abrir modal\n const img = new Image()\n img.onload = () => {\n const { naturalWidth, naturalHeight } = img\n\n if (checkMinimumDimensions(naturalWidth, naturalHeight)) {\n // Dimensões OK - abre modal de crop\n setShowCropModal(true)\n } else {\n // Imagem muito pequena - abre modal de erro diretamente\n setTooSmallError({\n fileName: currentFileName.current,\n minWidth: config.width,\n minHeight: config.height,\n })\n setShowTooSmallModal(true)\n }\n }\n img.src = base64\n }\n reader.readAsDataURL(file)\n },\n [config, checkMinimumDimensions]\n )\n\n // Mantido para compatibilidade, mas não mais necessário para validação\n const handleImageLoadInModal = useCallback(\n (_naturalWidth: number, _naturalHeight: number) => {\n // Validação agora é feita antes de abrir a modal\n // Este callback pode ser usado para outros propósitos se necessário\n },\n []\n )\n\n const handleSelectAnotherFile = useCallback(() => {\n setShowTooSmallModal(false)\n setTooSmallError(null)\n fileInputRef.current?.click()\n }, [])\n\n const handleCancelTooSmall = useCallback(() => {\n setShowTooSmallModal(false)\n setShowCropModal(false)\n setTooSmallError(null)\n setOriginalImage(null)\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 onSuccessRef.current?.(croppedBase64)\n } catch {\n onErrorRef.current?.('Erro ao aplicar crop')\n } finally {\n setIsProcessing(false)\n }\n },\n [config]\n )\n\n const clear = useCallback(() => {\n setOriginalImage(null)\n setCroppedPreview(null)\n }, [])\n\n return {\n originalImage,\n croppedPreview,\n showCropModal,\n showTooSmallModal,\n tooSmallError,\n config,\n isProcessing,\n fileInputRef,\n handleFileSelect,\n handleCropConfirm,\n handleImageLoadInModal,\n handleSelectAnotherFile,\n handleCancelTooSmall,\n setShowCropModal,\n setShowTooSmallModal,\n clear,\n }\n}\n"],"mappings":"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","names":[]}
@@ -1,65 +0,0 @@
1
- async function processImage(input) {
2
- const {
3
- imageBytes,
4
- targetWidth,
5
- targetHeight,
6
- outputFormat = "jpeg",
7
- quality = 85
8
- } = input;
9
- const { PhotonImage, resize, crop, SamplingFilter } = await import("@cf-wasm/photon/edge-light");
10
- const image = PhotonImage.new_from_byteslice(imageBytes);
11
- try {
12
- const sourceWidth = image.get_width();
13
- const sourceHeight = image.get_height();
14
- const targetAspect = targetWidth / targetHeight;
15
- const sourceAspect = sourceWidth / sourceHeight;
16
- let cropX1 = 0;
17
- let cropY1 = 0;
18
- let cropX2 = sourceWidth;
19
- let cropY2 = sourceHeight;
20
- if (sourceAspect > targetAspect) {
21
- const cropWidth = Math.round(sourceHeight * targetAspect);
22
- cropX1 = Math.round((sourceWidth - cropWidth) / 2);
23
- cropX2 = cropX1 + cropWidth;
24
- } else if (sourceAspect < targetAspect) {
25
- const cropHeight = Math.round(sourceWidth / targetAspect);
26
- cropY1 = Math.round((sourceHeight - cropHeight) / 2);
27
- cropY2 = cropY1 + cropHeight;
28
- }
29
- const cropped = crop(image, cropX1, cropY1, cropX2, cropY2);
30
- const resized = resize(
31
- cropped,
32
- targetWidth,
33
- targetHeight,
34
- SamplingFilter.Triangle
35
- );
36
- let outputBytes;
37
- switch (outputFormat) {
38
- case "jpeg":
39
- outputBytes = resized.get_bytes_jpeg(quality);
40
- break;
41
- case "png":
42
- outputBytes = resized.get_bytes();
43
- break;
44
- case "webp":
45
- outputBytes = resized.get_bytes_webp();
46
- break;
47
- default:
48
- outputBytes = resized.get_bytes_jpeg(quality);
49
- }
50
- cropped.free();
51
- resized.free();
52
- return {
53
- bytes: outputBytes,
54
- width: targetWidth,
55
- height: targetHeight,
56
- format: `image/${outputFormat}`
57
- };
58
- } finally {
59
- image.free();
60
- }
61
- }
62
- export {
63
- processImage
64
- };
65
- //# sourceMappingURL=image-processing.service.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../../../src/modules/images/services/image-processing.service.ts"],"sourcesContent":["import type { ProcessImageInput, ProcessImageOutput } from '../types/image.type'\n\nexport async function processImage(input: ProcessImageInput): Promise<ProcessImageOutput> {\n const {\n imageBytes,\n targetWidth,\n targetHeight,\n outputFormat = 'jpeg',\n quality = 85,\n } = input\n\n // Dynamic import to avoid fs.createReadStream error in edge runtime\n const { PhotonImage, resize, crop, SamplingFilter } = await import(\n '@cf-wasm/photon/edge-light'\n )\n\n const image = PhotonImage.new_from_byteslice(imageBytes)\n\n try {\n const sourceWidth = image.get_width()\n const sourceHeight = image.get_height()\n const targetAspect = targetWidth / targetHeight\n const sourceAspect = sourceWidth / sourceHeight\n\n let cropX1 = 0\n let cropY1 = 0\n let cropX2 = sourceWidth\n let cropY2 = sourceHeight\n\n if (sourceAspect > targetAspect) {\n const cropWidth = Math.round(sourceHeight * targetAspect)\n cropX1 = Math.round((sourceWidth - cropWidth) / 2)\n cropX2 = cropX1 + cropWidth\n } else if (sourceAspect < targetAspect) {\n const cropHeight = Math.round(sourceWidth / targetAspect)\n cropY1 = Math.round((sourceHeight - cropHeight) / 2)\n cropY2 = cropY1 + cropHeight\n }\n\n const cropped = crop(image, cropX1, cropY1, cropX2, cropY2)\n const resized = resize(\n cropped,\n targetWidth,\n targetHeight,\n SamplingFilter.Triangle\n )\n\n let outputBytes: Uint8Array\n switch (outputFormat) {\n case 'jpeg':\n outputBytes = resized.get_bytes_jpeg(quality)\n break\n case 'png':\n outputBytes = resized.get_bytes()\n break\n case 'webp':\n outputBytes = resized.get_bytes_webp()\n break\n default:\n outputBytes = resized.get_bytes_jpeg(quality)\n }\n\n cropped.free()\n resized.free()\n\n return {\n bytes: outputBytes,\n width: targetWidth,\n height: targetHeight,\n format: `image/${outputFormat}`,\n }\n } finally {\n image.free()\n }\n}\n"],"mappings":"AAEA,eAAsB,aAAa,OAAuD;AACxF,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA,eAAe;AAAA,IACf,UAAU;AAAA,EACZ,IAAI;AAGJ,QAAM,EAAE,aAAa,QAAQ,MAAM,eAAe,IAAI,MAAM,OAC1D,4BACF;AAEA,QAAM,QAAQ,YAAY,mBAAmB,UAAU;AAEvD,MAAI;AACF,UAAM,cAAc,MAAM,UAAU;AACpC,UAAM,eAAe,MAAM,WAAW;AACtC,UAAM,eAAe,cAAc;AACnC,UAAM,eAAe,cAAc;AAEnC,QAAI,SAAS;AACb,QAAI,SAAS;AACb,QAAI,SAAS;AACb,QAAI,SAAS;AAEb,QAAI,eAAe,cAAc;AAC/B,YAAM,YAAY,KAAK,MAAM,eAAe,YAAY;AACxD,eAAS,KAAK,OAAO,cAAc,aAAa,CAAC;AACjD,eAAS,SAAS;AAAA,IACpB,WAAW,eAAe,cAAc;AACtC,YAAM,aAAa,KAAK,MAAM,cAAc,YAAY;AACxD,eAAS,KAAK,OAAO,eAAe,cAAc,CAAC;AACnD,eAAS,SAAS;AAAA,IACpB;AAEA,UAAM,UAAU,KAAK,OAAO,QAAQ,QAAQ,QAAQ,MAAM;AAC1D,UAAM,UAAU;AAAA,MACd;AAAA,MACA;AAAA,MACA;AAAA,MACA,eAAe;AAAA,IACjB;AAEA,QAAI;AACJ,YAAQ,cAAc;AAAA,MACpB,KAAK;AACH,sBAAc,QAAQ,eAAe,OAAO;AAC5C;AAAA,MACF,KAAK;AACH,sBAAc,QAAQ,UAAU;AAChC;AAAA,MACF,KAAK;AACH,sBAAc,QAAQ,eAAe;AACrC;AAAA,MACF;AACE,sBAAc,QAAQ,eAAe,OAAO;AAAA,IAChD;AAEA,YAAQ,KAAK;AACb,YAAQ,KAAK;AAEb,WAAO;AAAA,MACL,OAAO;AAAA,MACP,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,QAAQ,SAAS,YAAY;AAAA,IAC/B;AAAA,EACF,UAAE;AACA,UAAM,KAAK;AAAA,EACb;AACF;","names":[]}
@@ -1 +0,0 @@
1
- //# sourceMappingURL=image.type.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -1,24 +0,0 @@
1
- function base64ToFile(base64, filename) {
2
- const arr = base64.split(",");
3
- const mime = arr[0].match(/:(.*?);/)?.[1] || "image/webp";
4
- const bstr = atob(arr[1]);
5
- let n = bstr.length;
6
- const u8arr = new Uint8Array(n);
7
- while (n--) {
8
- u8arr[n] = bstr.charCodeAt(n);
9
- }
10
- return new File([u8arr], filename, { type: mime });
11
- }
12
- function fileToBase64(file) {
13
- return new Promise((resolve, reject) => {
14
- const reader = new FileReader();
15
- reader.onload = () => resolve(reader.result);
16
- reader.onerror = reject;
17
- reader.readAsDataURL(file);
18
- });
19
- }
20
- export {
21
- base64ToFile,
22
- fileToBase64
23
- };
24
- //# sourceMappingURL=base64.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../../../src/modules/images/utils/base64.ts"],"sourcesContent":["/**\n * Converts a base64 string to a File object\n */\nexport function base64ToFile(base64: string, filename: string): File {\n const arr = base64.split(',')\n const mime = arr[0].match(/:(.*?);/)?.[1] || 'image/webp'\n const bstr = atob(arr[1])\n let n = bstr.length\n const u8arr = new Uint8Array(n)\n while (n--) {\n u8arr[n] = bstr.charCodeAt(n)\n }\n return new File([u8arr], filename, { type: mime })\n}\n\n/**\n * Converts a File to a base64 string\n */\nexport function fileToBase64(file: File): Promise<string> {\n return new Promise((resolve, reject) => {\n const reader = new FileReader()\n reader.onload = () => resolve(reader.result as string)\n reader.onerror = reject\n reader.readAsDataURL(file)\n })\n}\n"],"mappings":"AAGO,SAAS,aAAa,QAAgB,UAAwB;AACnE,QAAM,MAAM,OAAO,MAAM,GAAG;AAC5B,QAAM,OAAO,IAAI,CAAC,EAAE,MAAM,SAAS,IAAI,CAAC,KAAK;AAC7C,QAAM,OAAO,KAAK,IAAI,CAAC,CAAC;AACxB,MAAI,IAAI,KAAK;AACb,QAAM,QAAQ,IAAI,WAAW,CAAC;AAC9B,SAAO,KAAK;AACV,UAAM,CAAC,IAAI,KAAK,WAAW,CAAC;AAAA,EAC9B;AACA,SAAO,IAAI,KAAK,CAAC,KAAK,GAAG,UAAU,EAAE,MAAM,KAAK,CAAC;AACnD;AAKO,SAAS,aAAa,MAA6B;AACxD,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,UAAM,SAAS,IAAI,WAAW;AAC9B,WAAO,SAAS,MAAM,QAAQ,OAAO,MAAgB;AACrD,WAAO,UAAU;AACjB,WAAO,cAAc,IAAI;AAAA,EAC3B,CAAC;AACH;","names":[]}
@@ -1,17 +0,0 @@
1
- import imageCompression from "browser-image-compression";
2
- async function compressImage(file, options = {}) {
3
- const { maxSizeMB = 1, maxWidthOrHeight = 1920 } = options;
4
- if (file.size <= maxSizeMB * 1024 * 1024) {
5
- return file;
6
- }
7
- return imageCompression(file, {
8
- maxSizeMB,
9
- maxWidthOrHeight,
10
- useWebWorker: true,
11
- fileType: file.type
12
- });
13
- }
14
- export {
15
- compressImage
16
- };
17
- //# sourceMappingURL=compress-image.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../../../src/modules/images/utils/compress-image.ts"],"sourcesContent":["import imageCompression from 'browser-image-compression'\nimport type { CompressImageOptions } from '../types/image.type'\n\nexport async function compressImage(\n file: File,\n options: CompressImageOptions = {}\n): Promise<File> {\n const { maxSizeMB = 1, maxWidthOrHeight = 1920 } = options\n\n if (file.size <= maxSizeMB * 1024 * 1024) {\n return file\n }\n\n return imageCompression(file, {\n maxSizeMB,\n maxWidthOrHeight,\n useWebWorker: true,\n fileType: file.type as 'image/jpeg' | 'image/png' | 'image/webp',\n })\n}\n"],"mappings":"AAAA,OAAO,sBAAsB;AAG7B,eAAsB,cACpB,MACA,UAAgC,CAAC,GAClB;AACf,QAAM,EAAE,YAAY,GAAG,mBAAmB,KAAK,IAAI;AAEnD,MAAI,KAAK,QAAQ,YAAY,OAAO,MAAM;AACxC,WAAO;AAAA,EACT;AAEA,SAAO,iBAAiB,MAAM;AAAA,IAC5B;AAAA,IACA;AAAA,IACA,cAAc;AAAA,IACd,UAAU,KAAK;AAAA,EACjB,CAAC;AACH;","names":[]}
@@ -1,31 +0,0 @@
1
- async function cropImageToCanvas(image, crop, targetWidth, targetHeight) {
2
- const canvas = document.createElement("canvas");
3
- const ctx = canvas.getContext("2d");
4
- if (!ctx) throw new Error("Canvas n\xE3o suportado");
5
- const scaleX = image.naturalWidth / image.width;
6
- const scaleY = image.naturalHeight / image.height;
7
- const pixelCrop = {
8
- x: crop.unit === "%" ? crop.x / 100 * image.naturalWidth : crop.x * scaleX,
9
- y: crop.unit === "%" ? crop.y / 100 * image.naturalHeight : crop.y * scaleY,
10
- width: crop.unit === "%" ? crop.width / 100 * image.naturalWidth : crop.width * scaleX,
11
- height: crop.unit === "%" ? crop.height / 100 * image.naturalHeight : crop.height * scaleY
12
- };
13
- canvas.width = targetWidth;
14
- canvas.height = targetHeight;
15
- ctx.drawImage(
16
- image,
17
- pixelCrop.x,
18
- pixelCrop.y,
19
- pixelCrop.width,
20
- pixelCrop.height,
21
- 0,
22
- 0,
23
- targetWidth,
24
- targetHeight
25
- );
26
- return canvas.toDataURL("image/jpeg", 0.92);
27
- }
28
- export {
29
- cropImageToCanvas
30
- };
31
- //# sourceMappingURL=crop-image.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../../../src/modules/images/utils/crop-image.ts"],"sourcesContent":["import type { Crop } from 'react-image-crop'\n\nexport async function cropImageToCanvas(\n image: HTMLImageElement,\n crop: Crop,\n targetWidth: number,\n targetHeight: number\n): Promise<string> {\n const canvas = document.createElement('canvas')\n const ctx = canvas.getContext('2d')\n\n if (!ctx) throw new Error('Canvas não suportado')\n\n // Escala entre tamanho renderizado e natural (imagem pode estar reduzida com CSS)\n const scaleX = image.naturalWidth / image.width\n const scaleY = image.naturalHeight / image.height\n\n // Converte coordenadas do crop para pixels naturais da imagem\n const pixelCrop = {\n x: crop.unit === '%'\n ? (crop.x / 100) * image.naturalWidth\n : crop.x * scaleX,\n y: crop.unit === '%'\n ? (crop.y / 100) * image.naturalHeight\n : crop.y * scaleY,\n width: crop.unit === '%'\n ? (crop.width / 100) * image.naturalWidth\n : crop.width * scaleX,\n height: crop.unit === '%'\n ? (crop.height / 100) * image.naturalHeight\n : crop.height * scaleY,\n }\n\n canvas.width = targetWidth\n canvas.height = targetHeight\n\n ctx.drawImage(\n image,\n pixelCrop.x,\n pixelCrop.y,\n pixelCrop.width,\n pixelCrop.height,\n 0,\n 0,\n targetWidth,\n targetHeight\n )\n\n // Usa JPEG para compatibilidade universal (Safari tem problemas com WebP)\n return canvas.toDataURL('image/jpeg', 0.92)\n}\n"],"mappings":"AAEA,eAAsB,kBACpB,OACA,MACA,aACA,cACiB;AACjB,QAAM,SAAS,SAAS,cAAc,QAAQ;AAC9C,QAAM,MAAM,OAAO,WAAW,IAAI;AAElC,MAAI,CAAC,IAAK,OAAM,IAAI,MAAM,yBAAsB;AAGhD,QAAM,SAAS,MAAM,eAAe,MAAM;AAC1C,QAAM,SAAS,MAAM,gBAAgB,MAAM;AAG3C,QAAM,YAAY;AAAA,IAChB,GAAG,KAAK,SAAS,MACZ,KAAK,IAAI,MAAO,MAAM,eACvB,KAAK,IAAI;AAAA,IACb,GAAG,KAAK,SAAS,MACZ,KAAK,IAAI,MAAO,MAAM,gBACvB,KAAK,IAAI;AAAA,IACb,OAAO,KAAK,SAAS,MAChB,KAAK,QAAQ,MAAO,MAAM,eAC3B,KAAK,QAAQ;AAAA,IACjB,QAAQ,KAAK,SAAS,MACjB,KAAK,SAAS,MAAO,MAAM,gBAC5B,KAAK,SAAS;AAAA,EACpB;AAEA,SAAO,QAAQ;AACf,SAAO,SAAS;AAEhB,MAAI;AAAA,IACF;AAAA,IACA,UAAU;AAAA,IACV,UAAU;AAAA,IACV,UAAU;AAAA,IACV,UAAU;AAAA,IACV;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAGA,SAAO,OAAO,UAAU,cAAc,IAAI;AAC5C;","names":[]}
@@ -1,58 +0,0 @@
1
- import {
2
- ACCEPTED_IMAGE_FORMATS,
3
- MAX_FILE_SIZE_MB
4
- } from "../constants/image.constants";
5
- function validateImageFormat(file) {
6
- if (file.type === "image/svg+xml" || file.name.toLowerCase().endsWith(".svg")) {
7
- return {
8
- valid: false,
9
- error: "Formato SVG n\xE3o \xE9 suportado. Use PNG, JPEG, WebP ou GIF."
10
- };
11
- }
12
- if (!ACCEPTED_IMAGE_FORMATS.includes(
13
- file.type
14
- )) {
15
- return {
16
- valid: false,
17
- error: "Formato n\xE3o suportado. Use PNG, JPEG, WebP ou GIF."
18
- };
19
- }
20
- return { valid: true };
21
- }
22
- function validateImageSize(file, maxSizeMB = MAX_FILE_SIZE_MB) {
23
- if (file.size > maxSizeMB * 1024 * 1024) {
24
- return {
25
- valid: false,
26
- error: `Arquivo muito grande. M\xE1ximo ${maxSizeMB}MB.`
27
- };
28
- }
29
- return { valid: true };
30
- }
31
- function validateImage(file) {
32
- const formatValidation = validateImageFormat(file);
33
- if (!formatValidation.valid) return formatValidation;
34
- const sizeValidation = validateImageSize(file);
35
- if (!sizeValidation.valid) return sizeValidation;
36
- return { valid: true };
37
- }
38
- async function getImageDimensions(file) {
39
- return new Promise((resolve, reject) => {
40
- const img = new Image();
41
- img.onload = () => {
42
- resolve({ width: img.naturalWidth, height: img.naturalHeight });
43
- URL.revokeObjectURL(img.src);
44
- };
45
- img.onerror = () => {
46
- reject(new Error("Falha ao carregar imagem"));
47
- URL.revokeObjectURL(img.src);
48
- };
49
- img.src = URL.createObjectURL(file);
50
- });
51
- }
52
- export {
53
- getImageDimensions,
54
- validateImage,
55
- validateImageFormat,
56
- validateImageSize
57
- };
58
- //# sourceMappingURL=validate-image.mjs.map