@greatapps/common 1.1.532 → 1.1.534
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.
- package/dist/infra/utils/date.mjs +3 -0
- package/dist/infra/utils/date.mjs.map +1 -1
- package/dist/modules/images/hooks/use-image-upload.hook.mjs +2 -31
- package/dist/modules/images/hooks/use-image-upload.hook.mjs.map +1 -1
- package/dist/modules/projects/hooks/find-project.hook.mjs +1 -1
- package/dist/modules/projects/hooks/find-project.hook.mjs.map +1 -1
- package/dist/modules/projects/hooks/list-infinite-projects.hook.mjs +1 -1
- package/dist/modules/projects/hooks/list-infinite-projects.hook.mjs.map +1 -1
- package/dist/modules/projects/hooks/list-projects.hook.mjs +1 -1
- package/dist/modules/projects/hooks/list-projects.hook.mjs.map +1 -1
- package/package.json +1 -1
- package/src/infra/utils/date.ts +3 -0
- package/src/modules/images/hooks/use-image-upload.hook.ts +3 -39
- package/src/modules/projects/hooks/find-project.hook.ts +1 -1
- package/src/modules/projects/hooks/list-infinite-projects.hook.ts +1 -1
- package/src/modules/projects/hooks/list-projects.hook.ts +1 -1
|
@@ -3,6 +3,9 @@ function formatShortDate(date) {
|
|
|
3
3
|
const d = new Date(date);
|
|
4
4
|
const day = String(d.getDate()).padStart(2, "0");
|
|
5
5
|
const month = String(d.getMonth() + 1).padStart(2, "0");
|
|
6
|
+
if (d.getFullYear() !== (/* @__PURE__ */ new Date()).getFullYear()) {
|
|
7
|
+
return `${day}/${month}/${d.getFullYear()}`;
|
|
8
|
+
}
|
|
6
9
|
return `${day}/${month}`;
|
|
7
10
|
}
|
|
8
11
|
function formatDateTime(date) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/infra/utils/date.ts"],"sourcesContent":["export function formatShortDate(date: Date | string | null | undefined): string {\n if (!date) return '--';\n const d = new Date(date);\n const day = String(d.getDate()).padStart(2, '0');\n const month = String(d.getMonth() + 1).padStart(2, '0');\n return `${day}/${month}`;\n}\n\nexport function formatDateTime(date: Date | string | null | undefined): string | null {\n if (!date) return null;\n return new Date(date).toLocaleString('pt-BR', {\n day: '2-digit',\n month: '2-digit',\n year: 'numeric',\n hour: '2-digit',\n minute: '2-digit',\n });\n}\n"],"mappings":"AAAO,SAAS,gBAAgB,MAAgD;AAC9E,MAAI,CAAC,KAAM,QAAO;AAClB,QAAM,IAAI,IAAI,KAAK,IAAI;AACvB,QAAM,MAAM,OAAO,EAAE,QAAQ,CAAC,EAAE,SAAS,GAAG,GAAG;AAC/C,QAAM,QAAQ,OAAO,EAAE,SAAS,IAAI,CAAC,EAAE,SAAS,GAAG,GAAG;AACtD,SAAO,GAAG,GAAG,IAAI,KAAK;AACxB;AAEO,SAAS,eAAe,MAAuD;AACpF,MAAI,CAAC,KAAM,QAAO;AAClB,SAAO,IAAI,KAAK,IAAI,EAAE,eAAe,SAAS;AAAA,IAC5C,KAAK;AAAA,IACL,OAAO;AAAA,IACP,MAAM;AAAA,IACN,MAAM;AAAA,IACN,QAAQ;AAAA,EACV,CAAC;AACH;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/infra/utils/date.ts"],"sourcesContent":["export function formatShortDate(date: Date | string | null | undefined): string {\n if (!date) return '--';\n const d = new Date(date);\n const day = String(d.getDate()).padStart(2, '0');\n const month = String(d.getMonth() + 1).padStart(2, '0');\n if (d.getFullYear() !== new Date().getFullYear()) {\n return `${day}/${month}/${d.getFullYear()}`;\n }\n return `${day}/${month}`;\n}\n\nexport function formatDateTime(date: Date | string | null | undefined): string | null {\n if (!date) return null;\n return new Date(date).toLocaleString('pt-BR', {\n day: '2-digit',\n month: '2-digit',\n year: 'numeric',\n hour: '2-digit',\n minute: '2-digit',\n });\n}\n"],"mappings":"AAAO,SAAS,gBAAgB,MAAgD;AAC9E,MAAI,CAAC,KAAM,QAAO;AAClB,QAAM,IAAI,IAAI,KAAK,IAAI;AACvB,QAAM,MAAM,OAAO,EAAE,QAAQ,CAAC,EAAE,SAAS,GAAG,GAAG;AAC/C,QAAM,QAAQ,OAAO,EAAE,SAAS,IAAI,CAAC,EAAE,SAAS,GAAG,GAAG;AACtD,MAAI,EAAE,YAAY,OAAM,oBAAI,KAAK,GAAE,YAAY,GAAG;AAChD,WAAO,GAAG,GAAG,IAAI,KAAK,IAAI,EAAE,YAAY,CAAC;AAAA,EAC3C;AACA,SAAO,GAAG,GAAG,IAAI,KAAK;AACxB;AAEO,SAAS,eAAe,MAAuD;AACpF,MAAI,CAAC,KAAM,QAAO;AAClB,SAAO,IAAI,KAAK,IAAI,EAAE,eAAe,SAAS;AAAA,IAC5C,KAAK;AAAA,IACL,OAAO;AAAA,IACP,MAAM;AAAA,IACN,MAAM;AAAA,IACN,QAAQ;AAAA,EACV,CAAC;AACH;","names":[]}
|
|
@@ -18,22 +18,6 @@ function useImageUpload(options) {
|
|
|
18
18
|
const [isProcessing, setIsProcessing] = useState(false);
|
|
19
19
|
const fileInputRef = useRef(null);
|
|
20
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
21
|
const handleFileSelect = useCallback(
|
|
38
22
|
(file) => {
|
|
39
23
|
const validation = validateImage(file);
|
|
@@ -46,20 +30,7 @@ function useImageUpload(options) {
|
|
|
46
30
|
setOriginalImage(objectUrl);
|
|
47
31
|
const img = new Image();
|
|
48
32
|
img.onload = () => {
|
|
49
|
-
|
|
50
|
-
if (checkMinimumDimensions(naturalWidth, naturalHeight)) {
|
|
51
|
-
setShowCropModal(true);
|
|
52
|
-
} else {
|
|
53
|
-
setTooSmallError({
|
|
54
|
-
fileName: currentFileName.current,
|
|
55
|
-
minWidth: config.width,
|
|
56
|
-
minHeight: config.height
|
|
57
|
-
});
|
|
58
|
-
setShowTooSmallModal(true);
|
|
59
|
-
onErrorRef.current?.(`Imagem muito pequena. Tamanho m\xEDnimo: ${config.width}x${config.height}px.`);
|
|
60
|
-
URL.revokeObjectURL(objectUrl);
|
|
61
|
-
setOriginalImage(null);
|
|
62
|
-
}
|
|
33
|
+
setShowCropModal(true);
|
|
63
34
|
};
|
|
64
35
|
img.onerror = () => {
|
|
65
36
|
URL.revokeObjectURL(objectUrl);
|
|
@@ -68,7 +39,7 @@ function useImageUpload(options) {
|
|
|
68
39
|
};
|
|
69
40
|
img.src = objectUrl;
|
|
70
41
|
},
|
|
71
|
-
[
|
|
42
|
+
[]
|
|
72
43
|
);
|
|
73
44
|
const handleImageLoadInModal = useCallback(
|
|
74
45
|
(_naturalWidth, _naturalHeight) => {
|
|
@@ -1 +1 @@
|
|
|
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
|
|
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 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 // Usa object URL em vez de base64 — mais eficiente para imagens grandes\n const objectUrl = URL.createObjectURL(file)\n setOriginalImage(objectUrl)\n\n // Carrega imagem em memória para garantir que é válida antes de abrir modal\n const img = new Image()\n img.onload = () => {\n setShowCropModal(true)\n }\n img.onerror = () => {\n URL.revokeObjectURL(objectUrl)\n setOriginalImage(null)\n onErrorRef.current?.('Erro ao carregar a imagem. Tente uma imagem menor ou em outro formato.')\n }\n img.src = objectUrl\n },\n []\n )\n\n const handleImageLoadInModal = useCallback(\n (_naturalWidth: number, _naturalHeight: number) => {\n // Validação agora é feita antes de abrir a modal\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 if (originalImage) URL.revokeObjectURL(originalImage)\n setOriginalImage(null)\n }, [originalImage])\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 if (originalImage) URL.revokeObjectURL(originalImage)\n setOriginalImage(null)\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 if (originalImage) URL.revokeObjectURL(originalImage)\n setOriginalImage(null)\n setCroppedPreview(null)\n }, [originalImage])\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 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/modules/projects/hooks/find-project.hook.ts"],"sourcesContent":["'use client';\n\nimport { useQuery } from '@tanstack/react-query';\nimport { findProjectAction } from '../actions/find-project.action';\nimport { withAction } from '../../../utils/withAction';\nimport { useAuthQueryKey } from '../../../hooks/useAuthQueryKey';\nimport { PROJECTS_BASE_KEY } from './list-projects.hook';\n\nexport function useProject(projectId: number | null) {\n const queryKey = useAuthQueryKey([...PROJECTS_BASE_KEY, projectId]);\n\n return useQuery({\n queryKey,\n queryFn: () => withAction(() => findProjectAction(projectId!))(),\n enabled: projectId != null && projectId > 0,\n staleTime:
|
|
1
|
+
{"version":3,"sources":["../../../../src/modules/projects/hooks/find-project.hook.ts"],"sourcesContent":["'use client';\n\nimport { useQuery } from '@tanstack/react-query';\nimport { findProjectAction } from '../actions/find-project.action';\nimport { withAction } from '../../../utils/withAction';\nimport { useAuthQueryKey } from '../../../hooks/useAuthQueryKey';\nimport { PROJECTS_BASE_KEY } from './list-projects.hook';\n\nexport function useProject(projectId: number | null) {\n const queryKey = useAuthQueryKey([...PROJECTS_BASE_KEY, projectId]);\n\n return useQuery({\n queryKey,\n queryFn: () => withAction(() => findProjectAction(projectId!))(),\n enabled: projectId != null && projectId > 0,\n staleTime: 10_000,\n });\n}\n"],"mappings":";AAEA,SAAS,gBAAgB;AACzB,SAAS,yBAAyB;AAClC,SAAS,kBAAkB;AAC3B,SAAS,uBAAuB;AAChC,SAAS,yBAAyB;AAE3B,SAAS,WAAW,WAA0B;AACnD,QAAM,WAAW,gBAAgB,CAAC,GAAG,mBAAmB,SAAS,CAAC;AAElE,SAAO,SAAS;AAAA,IACd;AAAA,IACA,SAAS,MAAM,WAAW,MAAM,kBAAkB,SAAU,CAAC,EAAE;AAAA,IAC/D,SAAS,aAAa,QAAQ,YAAY;AAAA,IAC1C,WAAW;AAAA,EACb,CAAC;AACH;","names":[]}
|
|
@@ -26,7 +26,7 @@ function useInfiniteProjects({
|
|
|
26
26
|
return loaded < lastPage.total ? allPages.length + 1 : void 0;
|
|
27
27
|
},
|
|
28
28
|
placeholderData: (prev) => prev,
|
|
29
|
-
staleTime:
|
|
29
|
+
staleTime: 1e4,
|
|
30
30
|
refetchOnMount: true,
|
|
31
31
|
refetchOnWindowFocus: true,
|
|
32
32
|
refetchOnReconnect: true
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/modules/projects/hooks/list-infinite-projects.hook.ts"],"sourcesContent":["\"use client\";\n\nimport { useInfiniteQuery } from \"@tanstack/react-query\";\nimport { listProjectsAction } from \"../actions/list-projects.action\";\nimport type { ListProjectsActionParams } from \"../actions/list-projects.action\";\nimport { withAction } from \"../../../utils/withAction\";\nimport { useAuthQueryKey } from \"../../../hooks/useAuthQueryKey\";\nimport { PROJECTS_BASE_KEY } from \"./list-projects.hook\";\n\nconst PAGE_SIZE = 20;\n\nexport const INFINITE_PROJECTS_QUERY_KEY = (\n params?: Omit<ListProjectsActionParams, \"page\">,\n) => [...PROJECTS_BASE_KEY, \"infinite\", params] as const;\n\nexport function useInfiniteProjects({\n limit = PAGE_SIZE,\n ...params\n}: Omit<ListProjectsActionParams, \"page\">) {\n const queryKey = useAuthQueryKey([...INFINITE_PROJECTS_QUERY_KEY(params)]);\n\n return useInfiniteQuery({\n queryKey,\n queryFn: ({ pageParam }) =>\n withAction(() =>\n listProjectsAction({\n ...params,\n page: pageParam as number,\n limit,\n }),\n )(),\n initialPageParam: 1,\n getNextPageParam: (lastPage, allPages) => {\n const loaded = allPages.reduce((sum, p) => sum + p.data.length, 0);\n return loaded < lastPage.total ? allPages.length + 1 : undefined;\n },\n placeholderData: (prev) => prev,\n staleTime:
|
|
1
|
+
{"version":3,"sources":["../../../../src/modules/projects/hooks/list-infinite-projects.hook.ts"],"sourcesContent":["\"use client\";\n\nimport { useInfiniteQuery } from \"@tanstack/react-query\";\nimport { listProjectsAction } from \"../actions/list-projects.action\";\nimport type { ListProjectsActionParams } from \"../actions/list-projects.action\";\nimport { withAction } from \"../../../utils/withAction\";\nimport { useAuthQueryKey } from \"../../../hooks/useAuthQueryKey\";\nimport { PROJECTS_BASE_KEY } from \"./list-projects.hook\";\n\nconst PAGE_SIZE = 20;\n\nexport const INFINITE_PROJECTS_QUERY_KEY = (\n params?: Omit<ListProjectsActionParams, \"page\">,\n) => [...PROJECTS_BASE_KEY, \"infinite\", params] as const;\n\nexport function useInfiniteProjects({\n limit = PAGE_SIZE,\n ...params\n}: Omit<ListProjectsActionParams, \"page\">) {\n const queryKey = useAuthQueryKey([...INFINITE_PROJECTS_QUERY_KEY(params)]);\n\n return useInfiniteQuery({\n queryKey,\n queryFn: ({ pageParam }) =>\n withAction(() =>\n listProjectsAction({\n ...params,\n page: pageParam as number,\n limit,\n }),\n )(),\n initialPageParam: 1,\n getNextPageParam: (lastPage, allPages) => {\n const loaded = allPages.reduce((sum, p) => sum + p.data.length, 0);\n return loaded < lastPage.total ? allPages.length + 1 : undefined;\n },\n placeholderData: (prev) => prev,\n staleTime: 10_000,\n refetchOnMount: true,\n refetchOnWindowFocus: true,\n refetchOnReconnect: true,\n });\n}\n"],"mappings":";AAEA,SAAS,wBAAwB;AACjC,SAAS,0BAA0B;AAEnC,SAAS,kBAAkB;AAC3B,SAAS,uBAAuB;AAChC,SAAS,yBAAyB;AAElC,MAAM,YAAY;AAEX,MAAM,8BAA8B,CACzC,WACG,CAAC,GAAG,mBAAmB,YAAY,MAAM;AAEvC,SAAS,oBAAoB;AAAA,EAClC,QAAQ;AAAA,EACR,GAAG;AACL,GAA2C;AACzC,QAAM,WAAW,gBAAgB,CAAC,GAAG,4BAA4B,MAAM,CAAC,CAAC;AAEzE,SAAO,iBAAiB;AAAA,IACtB;AAAA,IACA,SAAS,CAAC,EAAE,UAAU,MACpB;AAAA,MAAW,MACT,mBAAmB;AAAA,QACjB,GAAG;AAAA,QACH,MAAM;AAAA,QACN;AAAA,MACF,CAAC;AAAA,IACH,EAAE;AAAA,IACJ,kBAAkB;AAAA,IAClB,kBAAkB,CAAC,UAAU,aAAa;AACxC,YAAM,SAAS,SAAS,OAAO,CAAC,KAAK,MAAM,MAAM,EAAE,KAAK,QAAQ,CAAC;AACjE,aAAO,SAAS,SAAS,QAAQ,SAAS,SAAS,IAAI;AAAA,IACzD;AAAA,IACA,iBAAiB,CAAC,SAAS;AAAA,IAC3B,WAAW;AAAA,IACX,gBAAgB;AAAA,IAChB,sBAAsB;AAAA,IACtB,oBAAoB;AAAA,EACtB,CAAC;AACH;","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/modules/projects/hooks/list-projects.hook.ts"],"sourcesContent":["'use client';\n\nimport { useQuery, keepPreviousData } from '@tanstack/react-query';\nimport { listProjectsAction } from '../actions/list-projects.action';\nimport type { ListProjectsActionParams } from '../actions/list-projects.action';\nimport { withAction } from '../../../utils/withAction';\nimport { useAuthQueryKey } from '../../../hooks/useAuthQueryKey';\n\nexport const PROJECTS_BASE_KEY = ['projects'] as const;\n\nexport const PROJECTS_QUERY_KEY = (params?: ListProjectsActionParams) =>\n [...PROJECTS_BASE_KEY, params] as const;\n\nexport function useProjects(params?: ListProjectsActionParams) {\n const queryKey = useAuthQueryKey([...PROJECTS_QUERY_KEY(params)]);\n\n return useQuery({\n queryKey,\n queryFn: withAction(() => listProjectsAction(params)),\n staleTime:
|
|
1
|
+
{"version":3,"sources":["../../../../src/modules/projects/hooks/list-projects.hook.ts"],"sourcesContent":["'use client';\n\nimport { useQuery, keepPreviousData } from '@tanstack/react-query';\nimport { listProjectsAction } from '../actions/list-projects.action';\nimport type { ListProjectsActionParams } from '../actions/list-projects.action';\nimport { withAction } from '../../../utils/withAction';\nimport { useAuthQueryKey } from '../../../hooks/useAuthQueryKey';\n\nexport const PROJECTS_BASE_KEY = ['projects'] as const;\n\nexport const PROJECTS_QUERY_KEY = (params?: ListProjectsActionParams) =>\n [...PROJECTS_BASE_KEY, params] as const;\n\nexport function useProjects(params?: ListProjectsActionParams) {\n const queryKey = useAuthQueryKey([...PROJECTS_QUERY_KEY(params)]);\n\n return useQuery({\n queryKey,\n queryFn: withAction(() => listProjectsAction(params)),\n staleTime: 10_000,\n placeholderData: keepPreviousData,\n });\n}\n"],"mappings":";AAEA,SAAS,UAAU,wBAAwB;AAC3C,SAAS,0BAA0B;AAEnC,SAAS,kBAAkB;AAC3B,SAAS,uBAAuB;AAEzB,MAAM,oBAAoB,CAAC,UAAU;AAErC,MAAM,qBAAqB,CAAC,WACjC,CAAC,GAAG,mBAAmB,MAAM;AAExB,SAAS,YAAY,QAAmC;AAC7D,QAAM,WAAW,gBAAgB,CAAC,GAAG,mBAAmB,MAAM,CAAC,CAAC;AAEhE,SAAO,SAAS;AAAA,IACd;AAAA,IACA,SAAS,WAAW,MAAM,mBAAmB,MAAM,CAAC;AAAA,IACpD,WAAW;AAAA,IACX,iBAAiB;AAAA,EACnB,CAAC;AACH;","names":[]}
|
package/package.json
CHANGED
package/src/infra/utils/date.ts
CHANGED
|
@@ -3,6 +3,9 @@ export function formatShortDate(date: Date | string | null | undefined): string
|
|
|
3
3
|
const d = new Date(date);
|
|
4
4
|
const day = String(d.getDate()).padStart(2, '0');
|
|
5
5
|
const month = String(d.getMonth() + 1).padStart(2, '0');
|
|
6
|
+
if (d.getFullYear() !== new Date().getFullYear()) {
|
|
7
|
+
return `${day}/${month}/${d.getFullYear()}`;
|
|
8
|
+
}
|
|
6
9
|
return `${day}/${month}`;
|
|
7
10
|
}
|
|
8
11
|
|
|
@@ -38,26 +38,6 @@ export function useImageUpload(options: UseImageUploadOptions) {
|
|
|
38
38
|
const fileInputRef = useRef<HTMLInputElement>(null)
|
|
39
39
|
const currentFileName = useRef<string>('')
|
|
40
40
|
|
|
41
|
-
// Verifica se a imagem cabe o crop mínimo
|
|
42
|
-
const checkMinimumDimensions = useCallback(
|
|
43
|
-
(naturalWidth: number, naturalHeight: number): boolean => {
|
|
44
|
-
const { width: minW, height: minH, aspectRatio } = config
|
|
45
|
-
const imgAspect = naturalWidth / naturalHeight
|
|
46
|
-
|
|
47
|
-
if (imgAspect >= aspectRatio) {
|
|
48
|
-
const cropHeight = naturalHeight
|
|
49
|
-
const cropWidth = cropHeight * aspectRatio
|
|
50
|
-
return cropWidth >= minW && cropHeight >= minH
|
|
51
|
-
} else {
|
|
52
|
-
const cropWidth = naturalWidth
|
|
53
|
-
const cropHeight = cropWidth / aspectRatio
|
|
54
|
-
return cropWidth >= minW && cropHeight >= minH
|
|
55
|
-
}
|
|
56
|
-
},
|
|
57
|
-
[config]
|
|
58
|
-
)
|
|
59
|
-
|
|
60
|
-
// Valida dimensões ANTES de abrir qualquer modal
|
|
61
41
|
const handleFileSelect = useCallback(
|
|
62
42
|
(file: File) => {
|
|
63
43
|
const validation = validateImage(file)
|
|
@@ -72,24 +52,10 @@ export function useImageUpload(options: UseImageUploadOptions) {
|
|
|
72
52
|
const objectUrl = URL.createObjectURL(file)
|
|
73
53
|
setOriginalImage(objectUrl)
|
|
74
54
|
|
|
75
|
-
// Carrega imagem em memória para
|
|
55
|
+
// Carrega imagem em memória para garantir que é válida antes de abrir modal
|
|
76
56
|
const img = new Image()
|
|
77
57
|
img.onload = () => {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
if (checkMinimumDimensions(naturalWidth, naturalHeight)) {
|
|
81
|
-
setShowCropModal(true)
|
|
82
|
-
} else {
|
|
83
|
-
setTooSmallError({
|
|
84
|
-
fileName: currentFileName.current,
|
|
85
|
-
minWidth: config.width,
|
|
86
|
-
minHeight: config.height,
|
|
87
|
-
})
|
|
88
|
-
setShowTooSmallModal(true)
|
|
89
|
-
onErrorRef.current?.(`Imagem muito pequena. Tamanho mínimo: ${config.width}x${config.height}px.`)
|
|
90
|
-
URL.revokeObjectURL(objectUrl)
|
|
91
|
-
setOriginalImage(null)
|
|
92
|
-
}
|
|
58
|
+
setShowCropModal(true)
|
|
93
59
|
}
|
|
94
60
|
img.onerror = () => {
|
|
95
61
|
URL.revokeObjectURL(objectUrl)
|
|
@@ -98,14 +64,12 @@ export function useImageUpload(options: UseImageUploadOptions) {
|
|
|
98
64
|
}
|
|
99
65
|
img.src = objectUrl
|
|
100
66
|
},
|
|
101
|
-
[
|
|
67
|
+
[]
|
|
102
68
|
)
|
|
103
69
|
|
|
104
|
-
// Mantido para compatibilidade, mas não mais necessário para validação
|
|
105
70
|
const handleImageLoadInModal = useCallback(
|
|
106
71
|
(_naturalWidth: number, _naturalHeight: number) => {
|
|
107
72
|
// Validação agora é feita antes de abrir a modal
|
|
108
|
-
// Este callback pode ser usado para outros propósitos se necessário
|
|
109
73
|
},
|
|
110
74
|
[]
|
|
111
75
|
)
|
|
@@ -35,7 +35,7 @@ export function useInfiniteProjects({
|
|
|
35
35
|
return loaded < lastPage.total ? allPages.length + 1 : undefined;
|
|
36
36
|
},
|
|
37
37
|
placeholderData: (prev) => prev,
|
|
38
|
-
staleTime:
|
|
38
|
+
staleTime: 10_000,
|
|
39
39
|
refetchOnMount: true,
|
|
40
40
|
refetchOnWindowFocus: true,
|
|
41
41
|
refetchOnReconnect: true,
|