feat: adicionar filtro 'Sem Categoria' nas transações
- Backend: suporte para category_id=uncategorized nos endpoints index e byWeek - Frontend: opção 'Sem Categoria' no CategorySelector com prop showUncategorized - Permite filtrar 525 transações importadas que ainda não foram categorizadas
This commit is contained in:
parent
54cccdd095
commit
f2e032f002
@ -25,8 +25,12 @@ public function index(Request $request): JsonResponse
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($request->has('category_id')) {
|
if ($request->has('category_id')) {
|
||||||
|
if ($request->category_id === 'uncategorized') {
|
||||||
|
$query->whereNull('category_id');
|
||||||
|
} else {
|
||||||
$query->ofCategory($request->category_id);
|
$query->ofCategory($request->category_id);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ($request->has('cost_center_id')) {
|
if ($request->has('cost_center_id')) {
|
||||||
$query->ofCostCenter($request->cost_center_id);
|
$query->ofCostCenter($request->cost_center_id);
|
||||||
@ -409,8 +413,12 @@ public function byWeek(Request $request): JsonResponse
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($request->has('category_id')) {
|
if ($request->has('category_id')) {
|
||||||
|
if ($request->category_id === 'uncategorized') {
|
||||||
|
$query->whereNull('category_id');
|
||||||
|
} else {
|
||||||
$query->ofCategory($request->category_id);
|
$query->ofCategory($request->category_id);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ($request->has('cost_center_id')) {
|
if ($request->has('cost_center_id')) {
|
||||||
$query->ofCostCenter($request->cost_center_id);
|
$query->ofCostCenter($request->cost_center_id);
|
||||||
|
|||||||
12
frontend/package-lock.json
generated
12
frontend/package-lock.json
generated
@ -61,7 +61,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz",
|
||||||
"integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==",
|
"integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/code-frame": "^7.27.1",
|
"@babel/code-frame": "^7.27.1",
|
||||||
"@babel/generator": "^7.28.5",
|
"@babel/generator": "^7.28.5",
|
||||||
@ -918,7 +917,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.7.tgz",
|
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.7.tgz",
|
||||||
"integrity": "sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg==",
|
"integrity": "sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"csstype": "^3.2.2"
|
"csstype": "^3.2.2"
|
||||||
}
|
}
|
||||||
@ -957,7 +955,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
|
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
|
||||||
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"peer": true,
|
|
||||||
"bin": {
|
"bin": {
|
||||||
"acorn": "bin/acorn"
|
"acorn": "bin/acorn"
|
||||||
},
|
},
|
||||||
@ -1111,7 +1108,6 @@
|
|||||||
"url": "https://github.com/sponsors/ai"
|
"url": "https://github.com/sponsors/ai"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"baseline-browser-mapping": "^2.9.0",
|
"baseline-browser-mapping": "^2.9.0",
|
||||||
"caniuse-lite": "^1.0.30001759",
|
"caniuse-lite": "^1.0.30001759",
|
||||||
@ -1187,7 +1183,6 @@
|
|||||||
"version": "4.5.1",
|
"version": "4.5.1",
|
||||||
"resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.5.1.tgz",
|
"resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.5.1.tgz",
|
||||||
"integrity": "sha512-GIjfiT9dbmHRiYi6Nl2yFCq7kkwdkp1W/lp2J99rX0yo9tgJGn3lKQATztIjb5tVtevcBtIdICNWqlq5+E8/Pw==",
|
"integrity": "sha512-GIjfiT9dbmHRiYi6Nl2yFCq7kkwdkp1W/lp2J99rX0yo9tgJGn3lKQATztIjb5tVtevcBtIdICNWqlq5+E8/Pw==",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@kurkle/color": "^0.3.0"
|
"@kurkle/color": "^0.3.0"
|
||||||
},
|
},
|
||||||
@ -1394,7 +1389,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.1.tgz",
|
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.1.tgz",
|
||||||
"integrity": "sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==",
|
"integrity": "sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/eslint-utils": "^4.8.0",
|
"@eslint-community/eslint-utils": "^4.8.0",
|
||||||
"@eslint-community/regexpp": "^4.12.1",
|
"@eslint-community/regexpp": "^4.12.1",
|
||||||
@ -1878,7 +1872,6 @@
|
|||||||
"url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project"
|
"url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.28.4"
|
"@babel/runtime": "^7.28.4"
|
||||||
},
|
},
|
||||||
@ -2502,7 +2495,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
|
||||||
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"peer": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
},
|
},
|
||||||
@ -2575,7 +2567,6 @@
|
|||||||
"version": "19.2.1",
|
"version": "19.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/react/-/react-19.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/react/-/react-19.2.1.tgz",
|
||||||
"integrity": "sha512-DGrYcCWK7tvYMnWh79yrPHt+vdx9tY+1gPZa7nJQtO/p8bLTDaHp4dzwEhQB7pZ4Xe3ok4XKuEPrVuc+wlpkmw==",
|
"integrity": "sha512-DGrYcCWK7tvYMnWh79yrPHt+vdx9tY+1gPZa7nJQtO/p8bLTDaHp4dzwEhQB7pZ4Xe3ok4XKuEPrVuc+wlpkmw==",
|
||||||
"peer": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
@ -2593,7 +2584,6 @@
|
|||||||
"version": "19.2.1",
|
"version": "19.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.1.tgz",
|
||||||
"integrity": "sha512-ibrK8llX2a4eOskq1mXKu/TGZj9qzomO+sNfO98M6d9zIPOEhlBkMkBUBLd1vgS0gQsLDBzA+8jJBVXDnfHmJg==",
|
"integrity": "sha512-ibrK8llX2a4eOskq1mXKu/TGZj9qzomO+sNfO98M6d9zIPOEhlBkMkBUBLd1vgS0gQsLDBzA+8jJBVXDnfHmJg==",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"scheduler": "^0.27.0"
|
"scheduler": "^0.27.0"
|
||||||
},
|
},
|
||||||
@ -2899,7 +2889,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/rolldown-vite/-/rolldown-vite-7.2.5.tgz",
|
"resolved": "https://registry.npmjs.org/rolldown-vite/-/rolldown-vite-7.2.5.tgz",
|
||||||
"integrity": "sha512-u09tdk/huMiN8xwoiBbig197jKdCamQTtOruSalOzbqGje3jdHiV0njQlAW0YvzoahkirFePNQ4RYlfnRQpXZA==",
|
"integrity": "sha512-u09tdk/huMiN8xwoiBbig197jKdCamQTtOruSalOzbqGje3jdHiV0njQlAW0YvzoahkirFePNQ4RYlfnRQpXZA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@oxc-project/runtime": "0.97.0",
|
"@oxc-project/runtime": "0.97.0",
|
||||||
"fdir": "^6.5.0",
|
"fdir": "^6.5.0",
|
||||||
@ -3025,7 +3014,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/zod/-/zod-4.1.13.tgz",
|
"resolved": "https://registry.npmjs.org/zod/-/zod-4.1.13.tgz",
|
||||||
"integrity": "sha512-AvvthqfqrAhNH9dnfmrfKzX5upOdjUVJYFqNSlkmGf64gRaTzlPwz99IHYnVs28qYAybvAlBV+H7pn0saFY4Ig==",
|
"integrity": "sha512-AvvthqfqrAhNH9dnfmrfKzX5upOdjUVJYFqNSlkmGf64gRaTzlPwz99IHYnVs28qYAybvAlBV+H7pn0saFY4Ig==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"peer": true,
|
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://github.com/sponsors/colinhacks"
|
"url": "https://github.com/sponsors/colinhacks"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,7 +18,8 @@ export default function CategorySelector({
|
|||||||
onChange,
|
onChange,
|
||||||
onAddNew,
|
onAddNew,
|
||||||
placeholder,
|
placeholder,
|
||||||
disabled = false
|
disabled = false,
|
||||||
|
showUncategorized = false
|
||||||
}) {
|
}) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
@ -125,6 +126,7 @@ export default function CategorySelector({
|
|||||||
|
|
||||||
// Obtener nombre completo de la categoría seleccionada
|
// Obtener nombre completo de la categoría seleccionada
|
||||||
const getSelectedCategoryName = () => {
|
const getSelectedCategoryName = () => {
|
||||||
|
if (value === 'uncategorized') return t('transactions.uncategorized');
|
||||||
const category = getCategoryById(value);
|
const category = getCategoryById(value);
|
||||||
if (!category) return placeholder || t('common.none');
|
if (!category) return placeholder || t('common.none');
|
||||||
|
|
||||||
@ -262,6 +264,21 @@ export default function CategorySelector({
|
|||||||
<span className="text-muted">{t('common.none')}</span>
|
<span className="text-muted">{t('common.none')}</span>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
{/* Opción "Sin categoría" para filtros */}
|
||||||
|
{showUncategorized && (
|
||||||
|
<>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className={`dropdown-item ${value === 'uncategorized' ? 'active' : ''}`}
|
||||||
|
onClick={(e) => handleSelect('uncategorized', e)}
|
||||||
|
>
|
||||||
|
<i className="bi bi-question-circle text-warning me-2"></i>
|
||||||
|
<span>{t('transactions.uncategorized')}</span>
|
||||||
|
</button>
|
||||||
|
<div className="dropdown-divider my-1"></div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
<div className="dropdown-divider my-1"></div>
|
<div className="dropdown-divider my-1"></div>
|
||||||
|
|
||||||
{/* Lista de categorías */}
|
{/* Lista de categorías */}
|
||||||
|
|||||||
@ -1233,6 +1233,7 @@ export default function Transactions() {
|
|||||||
value={filters.category_id}
|
value={filters.category_id}
|
||||||
onChange={handleFilterChange}
|
onChange={handleFilterChange}
|
||||||
placeholder={t('common.all')}
|
placeholder={t('common.all')}
|
||||||
|
showUncategorized={true}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="col-6 col-md-2">
|
<div className="col-6 col-md-2">
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user