@greatapps/common 1.1.475 → 1.1.477

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 (87) hide show
  1. package/dist/components/account/sections/MyProfileSection.mjs +2 -1
  2. package/dist/components/account/sections/MyProfileSection.mjs.map +1 -1
  3. package/dist/components/embeds/CrispEmbed.mjs +60 -24
  4. package/dist/components/embeds/CrispEmbed.mjs.map +1 -1
  5. package/dist/components/embeds/EmbedWidgets.mjs +45 -0
  6. package/dist/components/embeds/EmbedWidgets.mjs.map +1 -0
  7. package/dist/components/embeds/FrillEmbed.mjs +10 -3
  8. package/dist/components/embeds/FrillEmbed.mjs.map +1 -1
  9. package/dist/components/layouts/ProfilePopover.mjs +2 -1
  10. package/dist/components/layouts/ProfilePopover.mjs.map +1 -1
  11. package/dist/components/modals/cards/AddCardModal.mjs +10 -6
  12. package/dist/components/modals/cards/AddCardModal.mjs.map +1 -1
  13. package/dist/components/modals/cards/CardFormFields.mjs +47 -15
  14. package/dist/components/modals/cards/CardFormFields.mjs.map +1 -1
  15. package/dist/components/navigation/CancelledSubscriptionBanner.mjs +1 -1
  16. package/dist/components/navigation/CancelledSubscriptionBanner.mjs.map +1 -1
  17. package/dist/components/navigation/ProjectSelectorPopover.mjs +1 -1
  18. package/dist/components/navigation/ProjectSelectorPopover.mjs.map +1 -1
  19. package/dist/components/navigation/subcomponents/BottomLinks.mjs +2 -2
  20. package/dist/components/navigation/subcomponents/BottomLinks.mjs.map +1 -1
  21. package/dist/components/navigation/subcomponents/ProjectSelector.mjs +1 -1
  22. package/dist/components/navigation/subcomponents/ProjectSelector.mjs.map +1 -1
  23. package/dist/components/pages/notifications/Notifications.mjs +27 -17
  24. package/dist/components/pages/notifications/Notifications.mjs.map +1 -1
  25. package/dist/components/ui/form/Select.mjs +1 -1
  26. package/dist/components/ui/form/Select.mjs.map +1 -1
  27. package/dist/components/ui/overlay/Dialog.mjs +2 -1
  28. package/dist/components/ui/overlay/Dialog.mjs.map +1 -1
  29. package/dist/components/ui/overlay/Popover.mjs +1 -1
  30. package/dist/components/ui/overlay/Popover.mjs.map +1 -1
  31. package/dist/components/ui/overlay/Sheet.mjs +8 -6
  32. package/dist/components/ui/overlay/Sheet.mjs.map +1 -1
  33. package/dist/components/ui/overlay/Tooltip.mjs +1 -1
  34. package/dist/components/ui/overlay/Tooltip.mjs.map +1 -1
  35. package/dist/components/widgets/ImageUpload/ImageCropModal.mjs +212 -0
  36. package/dist/components/widgets/ImageUpload/ImageCropModal.mjs.map +1 -0
  37. package/dist/components/widgets/ImageUpload/ImageTooSmallModal.mjs +51 -0
  38. package/dist/components/widgets/ImageUpload/ImageTooSmallModal.mjs.map +1 -0
  39. package/dist/components/widgets/ImageUpload/ImageUpload.mjs +122 -0
  40. package/dist/components/widgets/ImageUpload/ImageUpload.mjs.map +1 -0
  41. package/dist/components/widgets/ImageUpload/index.mjs +9 -0
  42. package/dist/components/widgets/ImageUpload/index.mjs.map +1 -0
  43. package/dist/index.mjs +50 -2
  44. package/dist/index.mjs.map +1 -1
  45. package/dist/infra/utils/date.mjs +11 -0
  46. package/dist/infra/utils/date.mjs.map +1 -1
  47. package/dist/modules/auth/services/auth.service.mjs +2 -1
  48. package/dist/modules/auth/services/auth.service.mjs.map +1 -1
  49. package/dist/modules/images/actions/process-image.action.mjs +31 -0
  50. package/dist/modules/images/actions/process-image.action.mjs.map +1 -0
  51. package/dist/modules/images/constants/image.constants.mjs +14 -0
  52. package/dist/modules/images/constants/image.constants.mjs.map +1 -0
  53. package/dist/modules/images/hooks/use-image-upload.hook.mjs +132 -0
  54. package/dist/modules/images/hooks/use-image-upload.hook.mjs.map +1 -0
  55. package/dist/modules/images/services/image-processing.service.mjs +65 -0
  56. package/dist/modules/images/services/image-processing.service.mjs.map +1 -0
  57. package/dist/modules/images/types/image.type.mjs +1 -0
  58. package/dist/modules/images/types/image.type.mjs.map +1 -0
  59. package/dist/modules/images/utils/base64.mjs +24 -0
  60. package/dist/modules/images/utils/base64.mjs.map +1 -0
  61. package/dist/modules/images/utils/compress-image.mjs +17 -0
  62. package/dist/modules/images/utils/compress-image.mjs.map +1 -0
  63. package/dist/modules/images/utils/crop-image.mjs +31 -0
  64. package/dist/modules/images/utils/crop-image.mjs.map +1 -0
  65. package/dist/modules/images/utils/validate-image.mjs +58 -0
  66. package/dist/modules/images/utils/validate-image.mjs.map +1 -0
  67. package/dist/modules/plans/actions/list-plans.action.mjs +17 -0
  68. package/dist/modules/plans/actions/list-plans.action.mjs.map +1 -0
  69. package/dist/modules/plans/hooks/list-plans.hook.mjs +22 -0
  70. package/dist/modules/plans/hooks/list-plans.hook.mjs.map +1 -0
  71. package/dist/modules/plans/hooks/use-plan-by-id.hook.mjs +21 -2
  72. package/dist/modules/plans/hooks/use-plan-by-id.hook.mjs.map +1 -1
  73. package/dist/modules/plans/services/plans.service.mjs +71 -10
  74. package/dist/modules/plans/services/plans.service.mjs.map +1 -1
  75. package/dist/modules/plans/types/plan.type.mjs +1 -0
  76. package/dist/modules/plans/types/plan.type.mjs.map +1 -1
  77. package/dist/modules/plans/utils/map-api-plan-to-ui.mjs +58 -0
  78. package/dist/modules/plans/utils/map-api-plan-to-ui.mjs.map +1 -0
  79. package/dist/modules/subscriptions/types/subscription.type.mjs +31 -1
  80. package/dist/modules/subscriptions/types/subscription.type.mjs.map +1 -1
  81. package/dist/server.mjs +6 -0
  82. package/dist/server.mjs.map +1 -1
  83. package/dist/utils/format/currency.mjs +13 -0
  84. package/dist/utils/format/currency.mjs.map +1 -0
  85. package/package.json +1 -1
  86. package/src/components/navigation/CancelledSubscriptionBanner.tsx +1 -1
  87. package/src/components/ui/overlay/Sheet.tsx +13 -9
@@ -0,0 +1,65 @@
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
@@ -0,0 +1 @@
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":[]}
@@ -0,0 +1 @@
1
+ //# sourceMappingURL=image.type.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,24 @@
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
@@ -0,0 +1 @@
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":[]}
@@ -0,0 +1,17 @@
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
@@ -0,0 +1 @@
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":[]}
@@ -0,0 +1,31 @@
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
@@ -0,0 +1 @@
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":[]}
@@ -0,0 +1,58 @@
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
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/modules/images/utils/validate-image.ts"],"sourcesContent":["import {\n ACCEPTED_IMAGE_FORMATS,\n MAX_FILE_SIZE_MB,\n} from '../constants/image.constants'\n\nexport interface ImageValidationResult {\n valid: boolean\n error?: string\n}\n\nexport function validateImageFormat(file: File): ImageValidationResult {\n // Bloqueia SVG explicitamente (segurança + não funciona com crop)\n if (file.type === 'image/svg+xml' || file.name.toLowerCase().endsWith('.svg')) {\n return {\n valid: false,\n error: 'Formato SVG não é suportado. Use PNG, JPEG, WebP ou GIF.',\n }\n }\n\n if (\n !ACCEPTED_IMAGE_FORMATS.includes(\n file.type as (typeof ACCEPTED_IMAGE_FORMATS)[number]\n )\n ) {\n return {\n valid: false,\n error: 'Formato não suportado. Use PNG, JPEG, WebP ou GIF.',\n }\n }\n return { valid: true }\n}\n\nexport function validateImageSize(\n file: File,\n maxSizeMB: number = MAX_FILE_SIZE_MB\n): ImageValidationResult {\n if (file.size > maxSizeMB * 1024 * 1024) {\n return {\n valid: false,\n error: `Arquivo muito grande. Máximo ${maxSizeMB}MB.`,\n }\n }\n return { valid: true }\n}\n\nexport function validateImage(file: File): ImageValidationResult {\n const formatValidation = validateImageFormat(file)\n if (!formatValidation.valid) return formatValidation\n\n const sizeValidation = validateImageSize(file)\n if (!sizeValidation.valid) return sizeValidation\n\n return { valid: true }\n}\n\nexport async function getImageDimensions(\n file: File\n): Promise<{ width: number; height: number }> {\n return new Promise((resolve, reject) => {\n const img = new Image()\n img.onload = () => {\n resolve({ width: img.naturalWidth, height: img.naturalHeight })\n URL.revokeObjectURL(img.src)\n }\n img.onerror = () => {\n reject(new Error('Falha ao carregar imagem'))\n URL.revokeObjectURL(img.src)\n }\n img.src = URL.createObjectURL(file)\n })\n}\n"],"mappings":"AAAA;AAAA,EACE;AAAA,EACA;AAAA,OACK;AAOA,SAAS,oBAAoB,MAAmC;AAErE,MAAI,KAAK,SAAS,mBAAmB,KAAK,KAAK,YAAY,EAAE,SAAS,MAAM,GAAG;AAC7E,WAAO;AAAA,MACL,OAAO;AAAA,MACP,OAAO;AAAA,IACT;AAAA,EACF;AAEA,MACE,CAAC,uBAAuB;AAAA,IACtB,KAAK;AAAA,EACP,GACA;AACA,WAAO;AAAA,MACL,OAAO;AAAA,MACP,OAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO,EAAE,OAAO,KAAK;AACvB;AAEO,SAAS,kBACd,MACA,YAAoB,kBACG;AACvB,MAAI,KAAK,OAAO,YAAY,OAAO,MAAM;AACvC,WAAO;AAAA,MACL,OAAO;AAAA,MACP,OAAO,mCAAgC,SAAS;AAAA,IAClD;AAAA,EACF;AACA,SAAO,EAAE,OAAO,KAAK;AACvB;AAEO,SAAS,cAAc,MAAmC;AAC/D,QAAM,mBAAmB,oBAAoB,IAAI;AACjD,MAAI,CAAC,iBAAiB,MAAO,QAAO;AAEpC,QAAM,iBAAiB,kBAAkB,IAAI;AAC7C,MAAI,CAAC,eAAe,MAAO,QAAO;AAElC,SAAO,EAAE,OAAO,KAAK;AACvB;AAEA,eAAsB,mBACpB,MAC4C;AAC5C,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,UAAM,MAAM,IAAI,MAAM;AACtB,QAAI,SAAS,MAAM;AACjB,cAAQ,EAAE,OAAO,IAAI,cAAc,QAAQ,IAAI,cAAc,CAAC;AAC9D,UAAI,gBAAgB,IAAI,GAAG;AAAA,IAC7B;AACA,QAAI,UAAU,MAAM;AAClB,aAAO,IAAI,MAAM,0BAA0B,CAAC;AAC5C,UAAI,gBAAgB,IAAI,GAAG;AAAA,IAC7B;AACA,QAAI,MAAM,IAAI,gBAAgB,IAAI;AAAA,EACpC,CAAC;AACH;","names":[]}
@@ -0,0 +1,17 @@
1
+ "use server";
2
+ import { plansService, safeServerAction } from "@greatapps/common/server";
3
+ async function listPlansAction() {
4
+ return safeServerAction(async () => {
5
+ const { data: apiPlans } = await plansService.listPlans({
6
+ active: true,
7
+ search: "client",
8
+ sort: "id:ASC"
9
+ });
10
+ if (!apiPlans?.length) return [];
11
+ return [...apiPlans].sort((a, b) => a.value - b.value);
12
+ });
13
+ }
14
+ export {
15
+ listPlansAction
16
+ };
17
+ //# sourceMappingURL=list-plans.action.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/modules/plans/actions/list-plans.action.ts"],"sourcesContent":["'use server';\n\nimport { plansService, safeServerAction } from '@greatapps/common/server';\n\nexport async function listPlansAction() {\n return safeServerAction(async () => {\n const { data: apiPlans } = await plansService.listPlans({\n active: true,\n search: 'client',\n sort: 'id:ASC',\n });\n\n if (!apiPlans?.length) return [];\n\n return [...apiPlans].sort((a, b) => a.value - b.value);\n });\n}\n"],"mappings":";AAEA,SAAS,cAAc,wBAAwB;AAE/C,eAAsB,kBAAkB;AACtC,SAAO,iBAAiB,YAAY;AAClC,UAAM,EAAE,MAAM,SAAS,IAAI,MAAM,aAAa,UAAU;AAAA,MACtD,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,MAAM;AAAA,IACR,CAAC;AAED,QAAI,CAAC,UAAU,OAAQ,QAAO,CAAC;AAE/B,WAAO,CAAC,GAAG,QAAQ,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK;AAAA,EACvD,CAAC;AACH;","names":[]}
@@ -0,0 +1,22 @@
1
+ "use client";
2
+ import { useQuery } from "@tanstack/react-query";
3
+ import { withAction } from "@greatapps/common";
4
+ import { listPlansAction } from "../actions/list-plans.action";
5
+ const PLANS_QUERY_KEY = ["plans"];
6
+ function usePlans() {
7
+ return useQuery({
8
+ queryKey: [...PLANS_QUERY_KEY],
9
+ queryFn: withAction(listPlansAction),
10
+ staleTime: Infinity,
11
+ gcTime: Infinity,
12
+ refetchOnWindowFocus: false,
13
+ refetchOnReconnect: false,
14
+ refetchOnMount: false,
15
+ retry: 1
16
+ });
17
+ }
18
+ export {
19
+ PLANS_QUERY_KEY,
20
+ usePlans
21
+ };
22
+ //# sourceMappingURL=list-plans.hook.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/modules/plans/hooks/list-plans.hook.ts"],"sourcesContent":["'use client';\n\nimport { useQuery } from '@tanstack/react-query';\nimport { withAction } from '@greatapps/common';\nimport { listPlansAction } from '../actions/list-plans.action';\nimport type { Plan } from '../types/plan.type';\n\nexport const PLANS_QUERY_KEY = ['plans'];\n\nexport function usePlans() {\n return useQuery<Plan[]>({\n queryKey: [...PLANS_QUERY_KEY],\n queryFn: withAction(listPlansAction),\n staleTime: Infinity,\n gcTime: Infinity,\n refetchOnWindowFocus: false,\n refetchOnReconnect: false,\n refetchOnMount: false,\n retry: 1,\n });\n}\n"],"mappings":";AAEA,SAAS,gBAAgB;AACzB,SAAS,kBAAkB;AAC3B,SAAS,uBAAuB;AAGzB,MAAM,kBAAkB,CAAC,OAAO;AAEhC,SAAS,WAAW;AACzB,SAAO,SAAiB;AAAA,IACtB,UAAU,CAAC,GAAG,eAAe;AAAA,IAC7B,SAAS,WAAW,eAAe;AAAA,IACnC,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,sBAAsB;AAAA,IACtB,oBAAoB;AAAA,IACpB,gBAAgB;AAAA,IAChB,OAAO;AAAA,EACT,CAAC;AACH;","names":[]}
@@ -1,11 +1,30 @@
1
1
  "use client";
2
- import { useQuery } from "@tanstack/react-query";
2
+ import { useQuery, useQueryClient } from "@tanstack/react-query";
3
3
  import { withAction } from "../../../utils/withAction";
4
4
  import { findPlanByIdAction } from "../actions/find-plan-by-id.action";
5
+ import { PLANS_QUERY_KEY } from "./list-plans.hook";
5
6
  function usePlanById(idPlan) {
7
+ const queryClient = useQueryClient();
6
8
  return useQuery({
7
- queryKey: ["plan", idPlan],
9
+ queryKey: [...PLANS_QUERY_KEY, idPlan],
8
10
  queryFn: withAction(() => findPlanByIdAction(idPlan)),
11
+ initialData: () => {
12
+ const queries = queryClient.getQueriesData({
13
+ queryKey: [...PLANS_QUERY_KEY]
14
+ });
15
+ for (const [, data] of queries) {
16
+ if (!data || !Array.isArray(data)) continue;
17
+ const numericId = Number(idPlan);
18
+ const plan = data.find(
19
+ (p) => p.id === numericId || p.id_plan === numericId
20
+ );
21
+ if (plan) {
22
+ return { success: true, data: plan };
23
+ }
24
+ }
25
+ return void 0;
26
+ },
27
+ initialDataUpdatedAt: 0,
9
28
  enabled: !!idPlan
10
29
  });
11
30
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/modules/plans/hooks/use-plan-by-id.hook.ts"],"sourcesContent":["'use client';\n\nimport { useQuery } from '@tanstack/react-query';\nimport { withAction } from '../../../utils/withAction';\nimport { findPlanByIdAction } from '../actions/find-plan-by-id.action';\n\nexport function usePlanById(idPlan: number | string | undefined) {\n return useQuery({\n queryKey: ['plan', idPlan],\n queryFn: withAction(() => findPlanByIdAction(idPlan!)),\n enabled: !!idPlan,\n });\n}\n"],"mappings":";AAEA,SAAS,gBAAgB;AACzB,SAAS,kBAAkB;AAC3B,SAAS,0BAA0B;AAE5B,SAAS,YAAY,QAAqC;AAC/D,SAAO,SAAS;AAAA,IACd,UAAU,CAAC,QAAQ,MAAM;AAAA,IACzB,SAAS,WAAW,MAAM,mBAAmB,MAAO,CAAC;AAAA,IACrD,SAAS,CAAC,CAAC;AAAA,EACb,CAAC;AACH;","names":[]}
1
+ {"version":3,"sources":["../../../../src/modules/plans/hooks/use-plan-by-id.hook.ts"],"sourcesContent":["\"use client\";\n\nimport { useQuery, useQueryClient } from \"@tanstack/react-query\";\nimport { withAction } from \"../../../utils/withAction\";\nimport { findPlanByIdAction } from \"../actions/find-plan-by-id.action\";\nimport type { Plan } from \"../types/plan.type\";\nimport { PLANS_QUERY_KEY } from \"./list-plans.hook\";\n\nexport function usePlanById(idPlan: number | string | undefined) {\n const queryClient = useQueryClient();\n\n return useQuery({\n queryKey: [...PLANS_QUERY_KEY, idPlan],\n queryFn: withAction(() => findPlanByIdAction(idPlan!)),\n initialData: () => {\n const queries = queryClient.getQueriesData<Plan[]>({\n queryKey: [...PLANS_QUERY_KEY],\n });\n\n for (const [, data] of queries) {\n if (!data || !Array.isArray(data)) continue;\n const numericId = Number(idPlan);\n const plan = data.find(\n (p) => p.id === numericId || p.id_plan === numericId\n );\n if (plan) {\n return { success: true as const, data: plan };\n }\n }\n\n return undefined;\n },\n initialDataUpdatedAt: 0,\n enabled: !!idPlan,\n });\n}\n"],"mappings":";AAEA,SAAS,UAAU,sBAAsB;AACzC,SAAS,kBAAkB;AAC3B,SAAS,0BAA0B;AAEnC,SAAS,uBAAuB;AAEzB,SAAS,YAAY,QAAqC;AAC/D,QAAM,cAAc,eAAe;AAEnC,SAAO,SAAS;AAAA,IACd,UAAU,CAAC,GAAG,iBAAiB,MAAM;AAAA,IACrC,SAAS,WAAW,MAAM,mBAAmB,MAAO,CAAC;AAAA,IACrD,aAAa,MAAM;AACjB,YAAM,UAAU,YAAY,eAAuB;AAAA,QACjD,UAAU,CAAC,GAAG,eAAe;AAAA,MAC/B,CAAC;AAED,iBAAW,CAAC,EAAE,IAAI,KAAK,SAAS;AAC9B,YAAI,CAAC,QAAQ,CAAC,MAAM,QAAQ,IAAI,EAAG;AACnC,cAAM,YAAY,OAAO,MAAM;AAC/B,cAAM,OAAO,KAAK;AAAA,UAChB,CAAC,MAAM,EAAE,OAAO,aAAa,EAAE,YAAY;AAAA,QAC7C;AACA,YAAI,MAAM;AACR,iBAAO,EAAE,SAAS,MAAe,MAAM,KAAK;AAAA,QAC9C;AAAA,MACF;AAEA,aAAO;AAAA,IACT;AAAA,IACA,sBAAsB;AAAA,IACtB,SAAS,CAAC,CAAC;AAAA,EACb,CAAC;AACH;","names":[]}
@@ -1,11 +1,74 @@
1
1
  import "server-only";
2
- import { api } from "../../../infra/api/client";
3
- import { ApiError } from "../../../infra/api/types";
4
- import { PlanSchema } from "../types/plan.type";
2
+ import { api, getUserContext } from "@greatapps/common/server";
3
+ import { ApiError, buildQueryParams, PlanSchema } from "@greatapps/common";
4
+ import greatCache from "@greatapps/cache";
5
+ const PLANS_CACHE_TTL = 604800;
5
6
  class PlansService {
7
+ cache = new greatCache({
8
+ service: "plans",
9
+ version: "1.0.2",
10
+ domain: "whitelabel-cache.greatapps.com.br",
11
+ ambient: process.env.NODE_ENV || "development"
12
+ });
13
+ buildCacheKey(key, params) {
14
+ const sort = params?.sort ?? "id:ASC";
15
+ const active = params?.active ?? "";
16
+ const search = params?.search ?? "";
17
+ return `${key}-${sort}-${active}-${search}-v2`;
18
+ }
19
+ /**
20
+ * Lista planos do whitelabel.
21
+ * Exemplo:
22
+ * GET /{id_wl}/plans?active=true&search=client&sort=id:ASC
23
+ */
24
+ async listPlans(params) {
25
+ const { id_account } = await getUserContext();
26
+ const cacheKey = this.buildCacheKey("plans", {
27
+ ...params,
28
+ id_account
29
+ });
30
+ const cachedData = await this.cache.select(cacheKey);
31
+ if (cachedData.status == 1 && "data" in cachedData && cachedData.data) {
32
+ const data2 = JSON.parse(cachedData.data);
33
+ return { data: data2, total: data2.length, success: true };
34
+ }
35
+ const query = buildQueryParams({
36
+ sort: params?.sort ?? "id:ASC",
37
+ active: params?.active,
38
+ search: params?.search,
39
+ id_account
40
+ });
41
+ const url = `/plans${query ? `?${query}` : ""}`;
42
+ const response = await api.apps.get(url);
43
+ if (response.status === 0) {
44
+ throw new ApiError(
45
+ response.message || "Erro ao listar planos",
46
+ "LIST_PLANS_FAILED",
47
+ 400
48
+ );
49
+ }
50
+ const rawData = response.data;
51
+ const data = Array.isArray(rawData) ? rawData.map((item) => PlanSchema.parse(item)) : [];
52
+ await this.cache.insert(cacheKey, JSON.stringify(data), PLANS_CACHE_TTL);
53
+ return {
54
+ data,
55
+ total: response.total,
56
+ success: true
57
+ };
58
+ }
6
59
  async findById(idPlan) {
60
+ const { id_account } = await getUserContext();
61
+ const cacheKey = this.buildCacheKey(`plan-${idPlan}`, {
62
+ id_account: String(id_account)
63
+ });
64
+ const cachedData = await this.cache.select(cacheKey);
65
+ if (cachedData.status == 1 && "data" in cachedData && cachedData.data) {
66
+ const data = JSON.parse(cachedData.data);
67
+ return { data, success: true };
68
+ }
69
+ const query = buildQueryParams({ type: "client", id_account });
7
70
  const response = await api.apps.get(
8
- `/plans/${idPlan}?type=client`
71
+ `/plans/${idPlan}?${query}`
9
72
  );
10
73
  if (response.status === 0) {
11
74
  throw new ApiError(
@@ -15,15 +78,13 @@ class PlansService {
15
78
  );
16
79
  }
17
80
  if (!response.data?.length) {
18
- throw new ApiError(
19
- "Plano n\xE3o encontrado",
20
- "PLAN_NOT_FOUND",
21
- 404
22
- );
81
+ throw new ApiError("Plano n\xE3o encontrado", "PLAN_NOT_FOUND", 404);
23
82
  }
83
+ const plan = PlanSchema.parse(response.data[0]);
84
+ await this.cache.insert(cacheKey, JSON.stringify(plan), PLANS_CACHE_TTL);
24
85
  return {
25
86
  success: true,
26
- data: PlanSchema.parse(response.data[0])
87
+ data: plan
27
88
  };
28
89
  }
29
90
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/modules/plans/services/plans.service.ts"],"sourcesContent":["import 'server-only';\n\nimport { api } from '../../../infra/api/client';\nimport { ApiError, ApiPaginatedActionResult, SuccessResult } from '../../../infra/api/types';\nimport { Plan, PlanSchema } from '../types/plan.type';\n\nclass PlansService {\n async findById(idPlan: number | string): Promise<SuccessResult<Plan>> {\n const response = await api.apps.get<ApiPaginatedActionResult<Plan>>(\n `/plans/${idPlan}?type=client`\n );\n\n if (response.status === 0) {\n throw new ApiError(\n response.message || 'Erro ao buscar plano',\n 'FIND_PLAN_FAILED',\n 400\n );\n }\n\n if (!response.data?.length) {\n throw new ApiError(\n 'Plano não encontrado',\n 'PLAN_NOT_FOUND',\n 404\n );\n }\n\n return {\n success: true,\n data: PlanSchema.parse(response.data[0]),\n };\n }\n}\n\nexport const plansService = new PlansService();\n"],"mappings":"AAAA,OAAO;AAEP,SAAS,WAAW;AACpB,SAAS,gBAAyD;AAClE,SAAe,kBAAkB;AAEjC,MAAM,aAAa;AAAA,EACjB,MAAM,SAAS,QAAuD;AACpE,UAAM,WAAW,MAAM,IAAI,KAAK;AAAA,MAC9B,UAAU,MAAM;AAAA,IAClB;AAEA,QAAI,SAAS,WAAW,GAAG;AACzB,YAAM,IAAI;AAAA,QACR,SAAS,WAAW;AAAA,QACpB;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAEA,QAAI,CAAC,SAAS,MAAM,QAAQ;AAC1B,YAAM,IAAI;AAAA,QACR;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,MACL,SAAS;AAAA,MACT,MAAM,WAAW,MAAM,SAAS,KAAK,CAAC,CAAC;AAAA,IACzC;AAAA,EACF;AACF;AAEO,MAAM,eAAe,IAAI,aAAa;","names":[]}
1
+ {"version":3,"sources":["../../../../src/modules/plans/services/plans.service.ts"],"sourcesContent":["import \"server-only\";\n\nimport { api, apiClient, getUserContext } from \"@greatapps/common/server\";\nimport { ApiError, buildQueryParams, PlanSchema } from \"@greatapps/common\";\nimport type {\n ApiPaginatedActionResult,\n PaginatedSuccessResult,\n Plan,\n SuccessResult,\n} from \"@greatapps/common\";\nimport greatCache from \"@greatapps/cache\";\n\nexport type ListPlansParams = {\n sort?: string;\n active?: boolean;\n search?: string;\n};\n\nconst PLANS_CACHE_TTL = 604800;\n\nclass PlansService {\n private cache = new greatCache({\n service: \"plans\",\n version: \"1.0.2\",\n domain: \"whitelabel-cache.greatapps.com.br\",\n ambient: process.env.NODE_ENV || \"development\",\n });\n\n private buildCacheKey(key: string, params?: Record<string, unknown>): string {\n const sort = params?.sort ?? \"id:ASC\";\n const active = params?.active ?? \"\";\n const search = params?.search ?? \"\";\n return `${key}-${sort}-${active}-${search}-v2`;\n }\n\n /**\n * Lista planos do whitelabel.\n * Exemplo:\n * GET /{id_wl}/plans?active=true&search=client&sort=id:ASC\n */\n async listPlans(\n params?: ListPlansParams,\n ): Promise<PaginatedSuccessResult<Plan>> {\n const { id_account } = await getUserContext();\n const cacheKey = this.buildCacheKey(\"plans\", {\n ...params,\n id_account,\n });\n\n const cachedData = await this.cache.select(cacheKey);\n\n if (cachedData.status == 1 && \"data\" in cachedData && cachedData.data) {\n const data = JSON.parse(cachedData.data) as Plan[];\n return { data, total: data.length, success: true };\n }\n\n const query = buildQueryParams({\n sort: params?.sort ?? \"id:ASC\",\n active: params?.active,\n search: params?.search,\n id_account: id_account,\n });\n const url = `/plans${query ? `?${query}` : \"\"}`;\n\n const response = await api.apps.get<ApiPaginatedActionResult<Plan[]>>(url);\n\n if (response.status === 0) {\n throw new ApiError(\n (response as { message?: string }).message || \"Erro ao listar planos\",\n \"LIST_PLANS_FAILED\",\n 400,\n );\n }\n\n const rawData = (response as { data?: unknown }).data;\n const data = Array.isArray(rawData)\n ? rawData.map((item) => PlanSchema.parse(item))\n : [];\n\n await this.cache.insert(cacheKey, JSON.stringify(data), PLANS_CACHE_TTL);\n\n return {\n data,\n total: response.total,\n success: true,\n } satisfies PaginatedSuccessResult<Plan>;\n }\n\n async findById(idPlan: number | string): Promise<SuccessResult<Plan>> {\n const { id_account } = await getUserContext();\n const cacheKey = this.buildCacheKey(`plan-${idPlan}`, {\n id_account: String(id_account),\n });\n\n const cachedData = await this.cache.select(cacheKey);\n\n if (cachedData.status == 1 && \"data\" in cachedData && cachedData.data) {\n const data = JSON.parse(cachedData.data) as Plan;\n return { data, success: true };\n }\n\n const query = buildQueryParams({ type: \"client\", id_account });\n\n const response = await api.apps.get<ApiPaginatedActionResult<Plan>>(\n `/plans/${idPlan}?${query}`,\n );\n\n if (response.status === 0) {\n throw new ApiError(\n response.message || \"Erro ao buscar plano\",\n \"FIND_PLAN_FAILED\",\n 400,\n );\n }\n\n if (!response.data?.length) {\n throw new ApiError(\"Plano não encontrado\", \"PLAN_NOT_FOUND\", 404);\n }\n\n const plan = PlanSchema.parse(response.data[0]);\n\n await this.cache.insert(cacheKey, JSON.stringify(plan), PLANS_CACHE_TTL);\n\n return {\n success: true,\n data: plan,\n };\n }\n}\n\nexport const plansService = new PlansService();\n"],"mappings":"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","names":["data"]}
@@ -6,6 +6,7 @@ const PlanItemSchema = z.object({
6
6
  });
7
7
  const PlanSchema = z.object({
8
8
  id: z.number(),
9
+ id_plan: z.number().optional(),
9
10
  name: z.string(),
10
11
  value: z.number().default(0),
11
12
  type: z.string().optional(),
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/modules/plans/types/plan.type.ts"],"sourcesContent":["import z from 'zod';\n\nexport const PlanItemSchema = z.object({\n id_addon: z.number(),\n quantity: z.number(),\n value: z.number(),\n});\n\nexport type PlanItem = z.infer<typeof PlanItemSchema>;\n\nexport const PlanSchema = z.object({\n id: z.number(),\n name: z.string(),\n value: z.number().default(0),\n type: z.string().optional(),\n discount_semester: z.number().default(0),\n discount_annual: z.number().default(0),\n items: z.array(PlanItemSchema).optional().default([]),\n});\n\nexport type Plan = z.infer<typeof PlanSchema>;\n"],"mappings":"AAAA,OAAO,OAAO;AAEP,MAAM,iBAAiB,EAAE,OAAO;AAAA,EACrC,UAAU,EAAE,OAAO;AAAA,EACnB,UAAU,EAAE,OAAO;AAAA,EACnB,OAAO,EAAE,OAAO;AAClB,CAAC;AAIM,MAAM,aAAa,EAAE,OAAO;AAAA,EACjC,IAAI,EAAE,OAAO;AAAA,EACb,MAAM,EAAE,OAAO;AAAA,EACf,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC;AAAA,EAC3B,MAAM,EAAE,OAAO,EAAE,SAAS;AAAA,EAC1B,mBAAmB,EAAE,OAAO,EAAE,QAAQ,CAAC;AAAA,EACvC,iBAAiB,EAAE,OAAO,EAAE,QAAQ,CAAC;AAAA,EACrC,OAAO,EAAE,MAAM,cAAc,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC;AACtD,CAAC;","names":[]}
1
+ {"version":3,"sources":["../../../../src/modules/plans/types/plan.type.ts"],"sourcesContent":["import z from 'zod';\nimport type { BillingPeriod } from '../../subscriptions/types/billing-period.type';\n\nexport const PlanItemSchema = z.object({\n id_addon: z.number(),\n quantity: z.number(),\n value: z.number(),\n});\n\nexport type PlanItem = z.infer<typeof PlanItemSchema>;\n\nexport const PlanSchema = z.object({\n id: z.number(),\n id_plan: z.number().optional(),\n name: z.string(),\n value: z.number().default(0),\n type: z.string().optional(),\n discount_semester: z.number().default(0),\n discount_annual: z.number().default(0),\n items: z.array(PlanItemSchema).optional().default([]),\n});\n\nexport type Plan = z.infer<typeof PlanSchema>;\n\n// ── UI Plan types (used by list-plans action and consumers) ──\n\nexport type PlanFeature = {\n icon: 'check' | 'x';\n text: string;\n disabled?: boolean;\n tooltip?: keyof PlanTooltips;\n};\n\nexport type PlanMainFeatures = {\n pages: string;\n domains: string;\n users: string;\n};\n\n/** Preços mensais equivalentes por período de cobrança (já com desconto aplicado). */\nexport type PlanPricingByPeriod = {\n monthly: number;\n semiannual: number;\n annual: number;\n};\n\nexport type UiPlan = {\n idPlan: number;\n name: string;\n isPopular?: boolean;\n isCurrentPlan?: boolean;\n currentPeriodicity?: BillingPeriod | null;\n mainFeatures: PlanMainFeatures;\n features: PlanFeature[];\n originalPrice: string;\n price: string;\n pricingByPeriod?: PlanPricingByPeriod;\n buttonVariant?: 'brand' | 'default';\n items: PlanItem[];\n};\n\nexport type PlanTooltips = {\n domains: string;\n users: string;\n sharePages: string;\n projectManagement: string;\n};\n"],"mappings":"AAAA,OAAO,OAAO;AAGP,MAAM,iBAAiB,EAAE,OAAO;AAAA,EACrC,UAAU,EAAE,OAAO;AAAA,EACnB,UAAU,EAAE,OAAO;AAAA,EACnB,OAAO,EAAE,OAAO;AAClB,CAAC;AAIM,MAAM,aAAa,EAAE,OAAO;AAAA,EACjC,IAAI,EAAE,OAAO;AAAA,EACb,SAAS,EAAE,OAAO,EAAE,SAAS;AAAA,EAC7B,MAAM,EAAE,OAAO;AAAA,EACf,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC;AAAA,EAC3B,MAAM,EAAE,OAAO,EAAE,SAAS;AAAA,EAC1B,mBAAmB,EAAE,OAAO,EAAE,QAAQ,CAAC;AAAA,EACvC,iBAAiB,EAAE,OAAO,EAAE,QAAQ,CAAC;AAAA,EACrC,OAAO,EAAE,MAAM,cAAc,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC;AACtD,CAAC;","names":[]}
@@ -0,0 +1,58 @@
1
+ import { ADDON_IDS } from "../../subscriptions/constants/addons.constants";
2
+ import { formatCurrencyNumber } from "../../../utils/format/currency";
3
+ const BASE_FEATURES = [
4
+ { icon: "check", text: "Visitas ilimitadas" },
5
+ { icon: "check", text: "Leads ilimitadas" },
6
+ { icon: "check", text: "Compartilhar p\xE1ginas", tooltip: "sharePages" },
7
+ { icon: "check", text: "Hospedagem inclusa" },
8
+ { icon: "check", text: "SSL (HTTPS) + CDN" },
9
+ { icon: "check", text: "Templates Free" }
10
+ ];
11
+ function buildMainFeaturesFromItems(items) {
12
+ const pagesItem = items.find((i) => i.id_addon === ADDON_IDS.PAGES);
13
+ const domainsItem = items.find((i) => i.id_addon === ADDON_IDS.DOMAINS);
14
+ const pagesQty = pagesItem?.quantity ?? 0;
15
+ const domainsQty = domainsItem?.quantity ?? 1;
16
+ return {
17
+ pages: pagesQty === 0 ? "P\xE1ginas ilimitadas" : pagesQty === 1 ? "1 p\xE1gina" : `${pagesQty} p\xE1ginas`,
18
+ domains: domainsQty >= 999 ? "Dom\xEDnios ilimitados" : domainsQty === 1 ? "1 dom\xEDnio externo" : `${domainsQty} dom\xEDnios externos`,
19
+ users: "Usu\xE1rios ilimitados"
20
+ };
21
+ }
22
+ function computePricingByPeriod(apiPlan) {
23
+ const monthly = apiPlan.value;
24
+ const round2 = (n) => Math.round(n * 100) / 100;
25
+ return {
26
+ monthly,
27
+ semiannual: round2(monthly * (1 - apiPlan.discount_semester / 100)),
28
+ annual: round2(monthly * (1 - apiPlan.discount_annual / 100))
29
+ };
30
+ }
31
+ function mapApiPlanToUiPlan(apiPlan, options) {
32
+ const { planId, isPopular, buttonVariant } = options;
33
+ const pricingByPeriod = computePricingByPeriod(apiPlan);
34
+ const monthlyFinal = pricingByPeriod.monthly;
35
+ const lowerName = apiPlan.name.toLowerCase();
36
+ const hasProjectAndOnboarding = lowerName.includes("ag\xEAncia") || lowerName.includes("agencia");
37
+ const features = [
38
+ ...BASE_FEATURES,
39
+ hasProjectAndOnboarding ? { icon: "check", text: "Reuni\xE3o de Onboarding" } : { icon: "x", text: "Reuni\xE3o de Onboarding", disabled: true },
40
+ hasProjectAndOnboarding ? { icon: "check", text: "Gest\xE3o de projetos", tooltip: "projectManagement" } : { icon: "x", text: "Gest\xE3o de projetos", disabled: true, tooltip: "projectManagement" }
41
+ ];
42
+ return {
43
+ idPlan: planId,
44
+ name: apiPlan.name,
45
+ isPopular,
46
+ buttonVariant,
47
+ mainFeatures: buildMainFeaturesFromItems(apiPlan.items),
48
+ features,
49
+ originalPrice: formatCurrencyNumber(monthlyFinal),
50
+ price: formatCurrencyNumber(monthlyFinal),
51
+ pricingByPeriod,
52
+ items: apiPlan.items
53
+ };
54
+ }
55
+ export {
56
+ mapApiPlanToUiPlan
57
+ };
58
+ //# sourceMappingURL=map-api-plan-to-ui.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/modules/plans/utils/map-api-plan-to-ui.ts"],"sourcesContent":["import type { Plan, PlanFeature, PlanMainFeatures, PlanPricingByPeriod, UiPlan } from '../types/plan.type';\nimport { ADDON_IDS } from '../../subscriptions/constants/addons.constants';\nimport { formatCurrencyNumber } from '../../../utils/format/currency';\n\nexport type PlanBillingPeriod = 'monthly' | 'semiannual' | 'annual';\n\nconst BASE_FEATURES: PlanFeature[] = [\n { icon: 'check', text: 'Visitas ilimitadas' },\n { icon: 'check', text: 'Leads ilimitadas' },\n { icon: 'check', text: 'Compartilhar páginas', tooltip: 'sharePages' },\n { icon: 'check', text: 'Hospedagem inclusa' },\n { icon: 'check', text: 'SSL (HTTPS) + CDN' },\n { icon: 'check', text: 'Templates Free' },\n];\n\nfunction buildMainFeaturesFromItems(items: Plan['items']): PlanMainFeatures {\n const pagesItem = items.find((i) => i.id_addon === ADDON_IDS.PAGES);\n const domainsItem = items.find((i) => i.id_addon === ADDON_IDS.DOMAINS);\n\n const pagesQty = pagesItem?.quantity ?? 0;\n const domainsQty = domainsItem?.quantity ?? 1;\n\n return {\n pages:\n pagesQty === 0\n ? 'Páginas ilimitadas'\n : pagesQty === 1\n ? '1 página'\n : `${pagesQty} páginas`,\n domains:\n domainsQty >= 999\n ? 'Domínios ilimitados'\n : domainsQty === 1\n ? '1 domínio externo'\n : `${domainsQty} domínios externos`,\n users: 'Usuários ilimitados',\n };\n}\n\nfunction computePricingByPeriod(apiPlan: Plan): PlanPricingByPeriod {\n const monthly = apiPlan.value;\n const round2 = (n: number) => Math.round(n * 100) / 100;\n return {\n monthly,\n semiannual: round2(monthly * (1 - apiPlan.discount_semester / 100)),\n annual: round2(monthly * (1 - apiPlan.discount_annual / 100)),\n };\n}\n\nexport function mapApiPlanToUiPlan(\n apiPlan: Plan,\n options: {\n planId: number;\n isPopular?: boolean;\n buttonVariant?: 'brand' | 'default';\n }\n): UiPlan {\n const { planId, isPopular, buttonVariant } = options;\n\n const pricingByPeriod = computePricingByPeriod(apiPlan);\n const monthlyFinal = pricingByPeriod.monthly;\n\n const lowerName = apiPlan.name.toLowerCase();\n const hasProjectAndOnboarding =\n lowerName.includes('agência') || lowerName.includes('agencia');\n\n const features: PlanFeature[] = [\n ...BASE_FEATURES,\n hasProjectAndOnboarding\n ? { icon: 'check', text: 'Reunião de Onboarding' }\n : { icon: 'x', text: 'Reunião de Onboarding', disabled: true },\n hasProjectAndOnboarding\n ? { icon: 'check', text: 'Gestão de projetos', tooltip: 'projectManagement' }\n : { icon: 'x', text: 'Gestão de projetos', disabled: true, tooltip: 'projectManagement' },\n ];\n\n return {\n idPlan: planId,\n name: apiPlan.name,\n isPopular,\n buttonVariant,\n mainFeatures: buildMainFeaturesFromItems(apiPlan.items),\n features,\n originalPrice: formatCurrencyNumber(monthlyFinal),\n price: formatCurrencyNumber(monthlyFinal),\n pricingByPeriod,\n items: apiPlan.items,\n };\n}\n"],"mappings":"AACA,SAAS,iBAAiB;AAC1B,SAAS,4BAA4B;AAIrC,MAAM,gBAA+B;AAAA,EACnC,EAAE,MAAM,SAAS,MAAM,qBAAqB;AAAA,EAC5C,EAAE,MAAM,SAAS,MAAM,mBAAmB;AAAA,EAC1C,EAAE,MAAM,SAAS,MAAM,2BAAwB,SAAS,aAAa;AAAA,EACrE,EAAE,MAAM,SAAS,MAAM,qBAAqB;AAAA,EAC5C,EAAE,MAAM,SAAS,MAAM,oBAAoB;AAAA,EAC3C,EAAE,MAAM,SAAS,MAAM,iBAAiB;AAC1C;AAEA,SAAS,2BAA2B,OAAwC;AAC1E,QAAM,YAAY,MAAM,KAAK,CAAC,MAAM,EAAE,aAAa,UAAU,KAAK;AAClE,QAAM,cAAc,MAAM,KAAK,CAAC,MAAM,EAAE,aAAa,UAAU,OAAO;AAEtE,QAAM,WAAW,WAAW,YAAY;AACxC,QAAM,aAAa,aAAa,YAAY;AAE5C,SAAO;AAAA,IACL,OACE,aAAa,IACT,0BACA,aAAa,IACX,gBACA,GAAG,QAAQ;AAAA,IACnB,SACE,cAAc,MACV,2BACA,eAAe,IACb,yBACA,GAAG,UAAU;AAAA,IACrB,OAAO;AAAA,EACT;AACF;AAEA,SAAS,uBAAuB,SAAoC;AAClE,QAAM,UAAU,QAAQ;AACxB,QAAM,SAAS,CAAC,MAAc,KAAK,MAAM,IAAI,GAAG,IAAI;AACpD,SAAO;AAAA,IACL;AAAA,IACA,YAAY,OAAO,WAAW,IAAI,QAAQ,oBAAoB,IAAI;AAAA,IAClE,QAAQ,OAAO,WAAW,IAAI,QAAQ,kBAAkB,IAAI;AAAA,EAC9D;AACF;AAEO,SAAS,mBACd,SACA,SAKQ;AACR,QAAM,EAAE,QAAQ,WAAW,cAAc,IAAI;AAE7C,QAAM,kBAAkB,uBAAuB,OAAO;AACtD,QAAM,eAAe,gBAAgB;AAErC,QAAM,YAAY,QAAQ,KAAK,YAAY;AAC3C,QAAM,0BACJ,UAAU,SAAS,YAAS,KAAK,UAAU,SAAS,SAAS;AAE/D,QAAM,WAA0B;AAAA,IAC9B,GAAG;AAAA,IACH,0BACI,EAAE,MAAM,SAAS,MAAM,2BAAwB,IAC/C,EAAE,MAAM,KAAK,MAAM,4BAAyB,UAAU,KAAK;AAAA,IAC/D,0BACI,EAAE,MAAM,SAAS,MAAM,yBAAsB,SAAS,oBAAoB,IAC1E,EAAE,MAAM,KAAK,MAAM,yBAAsB,UAAU,MAAM,SAAS,oBAAoB;AAAA,EAC5F;AAEA,SAAO;AAAA,IACL,QAAQ;AAAA,IACR,MAAM,QAAQ;AAAA,IACd;AAAA,IACA;AAAA,IACA,cAAc,2BAA2B,QAAQ,KAAK;AAAA,IACtD;AAAA,IACA,eAAe,qBAAqB,YAAY;AAAA,IAChD,OAAO,qBAAqB,YAAY;AAAA,IACxC;AAAA,IACA,OAAO,QAAQ;AAAA,EACjB;AACF;","names":[]}
@@ -48,7 +48,37 @@ const SubscriptionSchema = z.object({
48
48
  card_name: z.string().nullable().optional(),
49
49
  card_brand: z.string().nullable().optional(),
50
50
  card_number: z.string().nullable().optional(),
51
- items: z.array(SubscriptionItemSchema)
51
+ items: z.array(SubscriptionItemSchema),
52
+ pending_change: z.object({
53
+ schedule_id: z.string(),
54
+ schedule_status: z.string(),
55
+ kind: z.string(),
56
+ takes_effect_at: z.number(),
57
+ takes_effect_at_iso: z.string(),
58
+ new_plan: z.object({
59
+ id: z.number(),
60
+ name: z.string(),
61
+ periodicity: z.number(),
62
+ value: z.number(),
63
+ value_gross: z.number()
64
+ }),
65
+ new_items: z.array(z.object({
66
+ price_id: z.string(),
67
+ id_addon: z.number().nullable(),
68
+ addon_name: z.string(),
69
+ quantity: z.number(),
70
+ unit_value: z.number(),
71
+ value: z.number(),
72
+ is_plan_base: z.boolean(),
73
+ is_ai_credit: z.boolean()
74
+ })),
75
+ new_discounts: z.array(z.unknown()),
76
+ changes: z.array(z.object({
77
+ type: z.string(),
78
+ from: z.unknown(),
79
+ to: z.unknown()
80
+ }))
81
+ }).nullable().optional()
52
82
  });
53
83
  export {
54
84
  SubscriptionItemSchema,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/modules/subscriptions/types/subscription.type.ts"],"sourcesContent":["import z from 'zod';\r\n\r\nexport const SubscriptionItemSchema = z.object({\r\n id: z.union([z.number(), z.string()]),\r\n deleted: z.number(),\r\n datetime_alt: z.coerce.date().nullable().optional(),\r\n datetime_del: z.coerce.date().nullable().optional(),\r\n datetime_add: z.coerce.date(),\r\n id_wl: z.number(),\r\n id_subscription: z.union([z.number(), z.string()]),\r\n id_addon: z.number().nullable(),\r\n addon_name: z.string().optional(),\r\n value: z.number(),\r\n currency: z.string(),\r\n quantity: z.number(),\r\n payment_status: z.number(),\r\n id_charge: z.union([z.number(), z.string()]).nullable(),\r\n trial: z.boolean(),\r\n trial_ends_at: z.coerce.date().nullable().optional(),\r\n});\r\n\r\nexport type SubscriptionItem = z.infer<typeof SubscriptionItemSchema>;\r\n\r\nexport const SubscriptionSchema = z.object({\r\n id: z.union([z.number(), z.string()]),\r\n deleted: z.number(),\r\n datetime_alt: z.coerce.date().nullable().optional(),\r\n datetime_del: z.coerce.date().nullable().optional(),\r\n datetime_add: z.coerce.date(),\r\n id_wl: z.number(),\r\n id_account: z.union([z.number(), z.string()]),\r\n id_card: z.union([z.number(), z.string()]).nullable(),\r\n id_coupon: z.union([z.number(), z.string()]).nullable(),\r\n type: z.string(),\r\n payment_method: z.number().nullable(),\r\n periodicity: z.coerce.number().nullable(),\r\n value: z.number().nullable(),\r\n id_product: z.number(),\r\n id_plan: z.number(),\r\n plan_name: z.string().nullable().optional(),\r\n id_gateway: z.union([z.number(), z.string()]).nullable(),\r\n gateway_account: z.string().nullable(),\r\n date_hiring: z.coerce.date().nullable(),\r\n date_due: z.coerce.date(),\r\n date_cancellation: z.coerce.date().nullable(),\r\n date_verification: z.coerce.date().nullable(),\r\n cancellation_reason: z.string().nullable(),\r\n cancellation_description: z.string().nullable(),\r\n active: z.boolean(),\r\n charged: z.boolean(),\r\n datetime_last_update_periodicity: z.coerce.date().nullable().optional(),\r\n card_name: z.string().nullable().optional(),\r\n card_brand: z.string().nullable().optional(),\r\n card_number: z.string().nullable().optional(),\r\n items: z.array(SubscriptionItemSchema),\r\n});\r\n\r\nexport type Subscription = z.infer<typeof SubscriptionSchema>;\r\n\r\nexport interface FindSubscriptionsParams {\r\n active?: boolean;\r\n trial?: boolean;\r\n date_start?: string;\r\n date_end?: string;\r\n date_hiring_start?: string;\r\n date_hiring_end?: string;\r\n limit?: number;\r\n}\r\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../../src/modules/subscriptions/types/subscription.type.ts"],"sourcesContent":["import z from 'zod';\r\n\r\nexport const SubscriptionItemSchema = z.object({\r\n id: z.union([z.number(), z.string()]),\r\n deleted: z.number(),\r\n datetime_alt: z.coerce.date().nullable().optional(),\r\n datetime_del: z.coerce.date().nullable().optional(),\r\n datetime_add: z.coerce.date(),\r\n id_wl: z.number(),\r\n id_subscription: z.union([z.number(), z.string()]),\r\n id_addon: z.number().nullable(),\r\n addon_name: z.string().optional(),\r\n value: z.number(),\r\n currency: z.string(),\r\n quantity: z.number(),\r\n payment_status: z.number(),\r\n id_charge: z.union([z.number(), z.string()]).nullable(),\r\n trial: z.boolean(),\r\n trial_ends_at: z.coerce.date().nullable().optional(),\r\n});\r\n\r\nexport type SubscriptionItem = z.infer<typeof SubscriptionItemSchema>;\r\n\r\nexport const SubscriptionSchema = z.object({\r\n id: z.union([z.number(), z.string()]),\r\n deleted: z.number(),\r\n datetime_alt: z.coerce.date().nullable().optional(),\r\n datetime_del: z.coerce.date().nullable().optional(),\r\n datetime_add: z.coerce.date(),\r\n id_wl: z.number(),\r\n id_account: z.union([z.number(), z.string()]),\r\n id_card: z.union([z.number(), z.string()]).nullable(),\r\n id_coupon: z.union([z.number(), z.string()]).nullable(),\r\n type: z.string(),\r\n payment_method: z.number().nullable(),\r\n periodicity: z.coerce.number().nullable(),\r\n value: z.number().nullable(),\r\n id_product: z.number(),\r\n id_plan: z.number(),\r\n plan_name: z.string().nullable().optional(),\r\n id_gateway: z.union([z.number(), z.string()]).nullable(),\r\n gateway_account: z.string().nullable(),\r\n date_hiring: z.coerce.date().nullable(),\r\n date_due: z.coerce.date(),\r\n date_cancellation: z.coerce.date().nullable(),\r\n date_verification: z.coerce.date().nullable(),\r\n cancellation_reason: z.string().nullable(),\r\n cancellation_description: z.string().nullable(),\r\n active: z.boolean(),\r\n charged: z.boolean(),\r\n datetime_last_update_periodicity: z.coerce.date().nullable().optional(),\r\n card_name: z.string().nullable().optional(),\r\n card_brand: z.string().nullable().optional(),\r\n card_number: z.string().nullable().optional(),\r\n items: z.array(SubscriptionItemSchema),\r\n pending_change: z.object({\r\n schedule_id: z.string(),\r\n schedule_status: z.string(),\r\n kind: z.string(),\r\n takes_effect_at: z.number(),\r\n takes_effect_at_iso: z.string(),\r\n new_plan: z.object({\r\n id: z.number(),\r\n name: z.string(),\r\n periodicity: z.number(),\r\n value: z.number(),\r\n value_gross: z.number(),\r\n }),\r\n new_items: z.array(z.object({\r\n price_id: z.string(),\r\n id_addon: z.number().nullable(),\r\n addon_name: z.string(),\r\n quantity: z.number(),\r\n unit_value: z.number(),\r\n value: z.number(),\r\n is_plan_base: z.boolean(),\r\n is_ai_credit: z.boolean(),\r\n })),\r\n new_discounts: z.array(z.unknown()),\r\n changes: z.array(z.object({\r\n type: z.string(),\r\n from: z.unknown(),\r\n to: z.unknown(),\r\n })),\r\n }).nullable().optional(),\r\n});\r\n\r\nexport type Subscription = z.infer<typeof SubscriptionSchema>;\r\n\r\nexport interface FindSubscriptionsParams {\r\n active?: boolean;\r\n trial?: boolean;\r\n date_start?: string;\r\n date_end?: string;\r\n date_hiring_start?: string;\r\n date_hiring_end?: string;\r\n limit?: number;\r\n}\r\n"],"mappings":"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","names":[]}