mirror of
https://github.com/felipegcoutinho/openmonetis.git
synced 2026-05-09 11:01:45 +00:00
Compare commits
6 Commits
7dd480284e
...
60a52b9873
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
60a52b9873 | ||
|
|
c9205f2be9 | ||
|
|
1d36b12109 | ||
|
|
19a1b1e943 | ||
|
|
d3fc81db73 | ||
|
|
80de9501f6 |
10
CHANGELOG.md
10
CHANGELOG.md
@@ -5,6 +5,16 @@ Todas as mudanças notáveis deste projeto serão documentadas neste arquivo.
|
||||
O formato é baseado em [Keep a Changelog](https://keepachangelog.com/pt-BR/1.1.0/),
|
||||
e este projeto adere ao [Versionamento Semântico](https://semver.org/lang/pt-BR/).
|
||||
|
||||
## [2.0.1] - 2026-03-21
|
||||
|
||||
### Corrigido
|
||||
|
||||
- Inbox: filtro por app em `/inbox` agora monta a lista completa de apps da aba a partir de todos os itens do status atual, sem depender apenas da página carregada, e o SSR deixa de quebrar quando `sourceApps` vier inconsistente
|
||||
- Inbox: notificações de cartões/apps sem logo cadastrado agora exibem `default_icon.png` como fallback visual nos cards
|
||||
- Inbox: select de apps em `/inbox` agora exibe os logos dos apps/cartões, com fallback para `default_icon.png` quando não houver logo mapeado
|
||||
- Inbox: cabeçalhos de data entre grupos de cards agora exibem ícone e tipografia um pouco maior para melhorar a leitura
|
||||
- Versionamento: `/api/health` passa a reportar a versão atual do `package.json`, evitando divergência entre healthcheck, UI e release publicada
|
||||
|
||||
## [2.0.0] - 2026-03-21
|
||||
|
||||
### Adicionado
|
||||
|
||||
@@ -93,12 +93,8 @@
|
||||
"name": "account_userId_user_id_fk",
|
||||
"tableFrom": "account",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"userId"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["userId"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -213,12 +209,8 @@
|
||||
"name": "tokens_api_user_id_user_id_fk",
|
||||
"tableFrom": "tokens_api",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["user_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -327,12 +319,8 @@
|
||||
"name": "orcamentos_user_id_user_id_fk",
|
||||
"tableFrom": "orcamentos",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["user_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -340,12 +328,8 @@
|
||||
"name": "orcamentos_categoria_id_categorias_id_fk",
|
||||
"tableFrom": "orcamentos",
|
||||
"tableTo": "categorias",
|
||||
"columnsFrom": [
|
||||
"categoria_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["categoria_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "cascade"
|
||||
}
|
||||
@@ -463,12 +447,8 @@
|
||||
"name": "cartoes_user_id_user_id_fk",
|
||||
"tableFrom": "cartoes",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["user_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -476,12 +456,8 @@
|
||||
"name": "cartoes_conta_id_contas_id_fk",
|
||||
"tableFrom": "cartoes",
|
||||
"tableTo": "contas",
|
||||
"columnsFrom": [
|
||||
"conta_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["conta_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "cascade"
|
||||
}
|
||||
@@ -563,12 +539,8 @@
|
||||
"name": "categorias_user_id_user_id_fk",
|
||||
"tableFrom": "categorias",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["user_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -683,12 +655,8 @@
|
||||
"name": "contas_user_id_user_id_fk",
|
||||
"tableFrom": "contas",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["user_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -847,12 +815,8 @@
|
||||
"name": "pre_lancamentos_user_id_user_id_fk",
|
||||
"tableFrom": "pre_lancamentos",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["user_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -860,12 +824,8 @@
|
||||
"name": "pre_lancamentos_lancamento_id_lancamentos_id_fk",
|
||||
"tableFrom": "pre_lancamentos",
|
||||
"tableTo": "lancamentos",
|
||||
"columnsFrom": [
|
||||
"lancamento_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["lancamento_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1005,12 +965,8 @@
|
||||
"name": "antecipacoes_parcelas_lancamento_id_lancamentos_id_fk",
|
||||
"tableFrom": "antecipacoes_parcelas",
|
||||
"tableTo": "lancamentos",
|
||||
"columnsFrom": [
|
||||
"lancamento_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["lancamento_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -1018,12 +974,8 @@
|
||||
"name": "antecipacoes_parcelas_pagador_id_pagadores_id_fk",
|
||||
"tableFrom": "antecipacoes_parcelas",
|
||||
"tableTo": "pagadores",
|
||||
"columnsFrom": [
|
||||
"pagador_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["pagador_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -1031,12 +983,8 @@
|
||||
"name": "antecipacoes_parcelas_categoria_id_categorias_id_fk",
|
||||
"tableFrom": "antecipacoes_parcelas",
|
||||
"tableTo": "categorias",
|
||||
"columnsFrom": [
|
||||
"categoria_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["categoria_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -1044,12 +992,8 @@
|
||||
"name": "antecipacoes_parcelas_user_id_user_id_fk",
|
||||
"tableFrom": "antecipacoes_parcelas",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["user_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1179,12 +1123,8 @@
|
||||
"name": "faturas_user_id_user_id_fk",
|
||||
"tableFrom": "faturas",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["user_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -1192,12 +1132,8 @@
|
||||
"name": "faturas_cartao_id_cartoes_id_fk",
|
||||
"tableFrom": "faturas",
|
||||
"tableTo": "cartoes",
|
||||
"columnsFrom": [
|
||||
"cartao_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["cartao_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "cascade"
|
||||
}
|
||||
@@ -1271,12 +1207,8 @@
|
||||
"name": "anotacoes_user_id_user_id_fk",
|
||||
"tableFrom": "anotacoes",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["user_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1364,12 +1296,8 @@
|
||||
"name": "passkey_userId_user_id_fk",
|
||||
"tableFrom": "passkey",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"userId"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["userId"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1452,12 +1380,8 @@
|
||||
"name": "compartilhamentos_pagador_pagador_id_pagadores_id_fk",
|
||||
"tableFrom": "compartilhamentos_pagador",
|
||||
"tableTo": "pagadores",
|
||||
"columnsFrom": [
|
||||
"pagador_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["pagador_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -1465,12 +1389,8 @@
|
||||
"name": "compartilhamentos_pagador_shared_with_user_id_user_id_fk",
|
||||
"tableFrom": "compartilhamentos_pagador",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"shared_with_user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["shared_with_user_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -1478,12 +1398,8 @@
|
||||
"name": "compartilhamentos_pagador_created_by_user_id_user_id_fk",
|
||||
"tableFrom": "compartilhamentos_pagador",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"created_by_user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["created_by_user_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1639,12 +1555,8 @@
|
||||
"name": "pagadores_user_id_user_id_fk",
|
||||
"tableFrom": "pagadores",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["user_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1733,12 +1645,8 @@
|
||||
"name": "insights_salvos_user_id_user_id_fk",
|
||||
"tableFrom": "insights_salvos",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["user_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1808,12 +1716,8 @@
|
||||
"name": "session_userId_user_id_fk",
|
||||
"tableFrom": "session",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"userId"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["userId"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1823,9 +1727,7 @@
|
||||
"session_token_unique": {
|
||||
"name": "session_token_unique",
|
||||
"nullsNotDistinct": false,
|
||||
"columns": [
|
||||
"token"
|
||||
]
|
||||
"columns": ["token"]
|
||||
}
|
||||
},
|
||||
"policies": {},
|
||||
@@ -2228,12 +2130,8 @@
|
||||
"name": "lancamentos_antecipacao_id_antecipacoes_parcelas_id_fk",
|
||||
"tableFrom": "lancamentos",
|
||||
"tableTo": "antecipacoes_parcelas",
|
||||
"columnsFrom": [
|
||||
"antecipacao_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["antecipacao_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -2241,12 +2139,8 @@
|
||||
"name": "lancamentos_user_id_user_id_fk",
|
||||
"tableFrom": "lancamentos",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["user_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -2254,12 +2148,8 @@
|
||||
"name": "lancamentos_cartao_id_cartoes_id_fk",
|
||||
"tableFrom": "lancamentos",
|
||||
"tableTo": "cartoes",
|
||||
"columnsFrom": [
|
||||
"cartao_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["cartao_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "cascade"
|
||||
},
|
||||
@@ -2267,12 +2157,8 @@
|
||||
"name": "lancamentos_conta_id_contas_id_fk",
|
||||
"tableFrom": "lancamentos",
|
||||
"tableTo": "contas",
|
||||
"columnsFrom": [
|
||||
"conta_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["conta_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "cascade"
|
||||
},
|
||||
@@ -2280,12 +2166,8 @@
|
||||
"name": "lancamentos_categoria_id_categorias_id_fk",
|
||||
"tableFrom": "lancamentos",
|
||||
"tableTo": "categorias",
|
||||
"columnsFrom": [
|
||||
"categoria_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["categoria_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "cascade"
|
||||
},
|
||||
@@ -2293,12 +2175,8 @@
|
||||
"name": "lancamentos_pagador_id_pagadores_id_fk",
|
||||
"tableFrom": "lancamentos",
|
||||
"tableTo": "pagadores",
|
||||
"columnsFrom": [
|
||||
"pagador_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["pagador_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "cascade"
|
||||
}
|
||||
@@ -2363,9 +2241,7 @@
|
||||
"user_email_unique": {
|
||||
"name": "user_email_unique",
|
||||
"nullsNotDistinct": false,
|
||||
"columns": [
|
||||
"email"
|
||||
]
|
||||
"columns": ["email"]
|
||||
}
|
||||
},
|
||||
"policies": {},
|
||||
@@ -2443,12 +2319,8 @@
|
||||
"name": "preferencias_usuario_user_id_user_id_fk",
|
||||
"tableFrom": "preferencias_usuario",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["user_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -2458,9 +2330,7 @@
|
||||
"preferencias_usuario_user_id_unique": {
|
||||
"name": "preferencias_usuario_user_id_unique",
|
||||
"nullsNotDistinct": false,
|
||||
"columns": [
|
||||
"user_id"
|
||||
]
|
||||
"columns": ["user_id"]
|
||||
}
|
||||
},
|
||||
"policies": {},
|
||||
|
||||
@@ -93,12 +93,8 @@
|
||||
"name": "account_userId_user_id_fk",
|
||||
"tableFrom": "account",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"userId"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["userId"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -213,12 +209,8 @@
|
||||
"name": "tokens_api_user_id_user_id_fk",
|
||||
"tableFrom": "tokens_api",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["user_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -327,12 +319,8 @@
|
||||
"name": "orcamentos_user_id_user_id_fk",
|
||||
"tableFrom": "orcamentos",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["user_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -340,12 +328,8 @@
|
||||
"name": "orcamentos_categoria_id_categorias_id_fk",
|
||||
"tableFrom": "orcamentos",
|
||||
"tableTo": "categorias",
|
||||
"columnsFrom": [
|
||||
"categoria_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["categoria_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "cascade"
|
||||
}
|
||||
@@ -463,12 +447,8 @@
|
||||
"name": "cartoes_user_id_user_id_fk",
|
||||
"tableFrom": "cartoes",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["user_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -476,12 +456,8 @@
|
||||
"name": "cartoes_conta_id_contas_id_fk",
|
||||
"tableFrom": "cartoes",
|
||||
"tableTo": "contas",
|
||||
"columnsFrom": [
|
||||
"conta_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["conta_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "cascade"
|
||||
}
|
||||
@@ -563,12 +539,8 @@
|
||||
"name": "categorias_user_id_user_id_fk",
|
||||
"tableFrom": "categorias",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["user_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -683,12 +655,8 @@
|
||||
"name": "contas_user_id_user_id_fk",
|
||||
"tableFrom": "contas",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["user_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -847,12 +815,8 @@
|
||||
"name": "pre_lancamentos_user_id_user_id_fk",
|
||||
"tableFrom": "pre_lancamentos",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["user_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -860,12 +824,8 @@
|
||||
"name": "pre_lancamentos_lancamento_id_lancamentos_id_fk",
|
||||
"tableFrom": "pre_lancamentos",
|
||||
"tableTo": "lancamentos",
|
||||
"columnsFrom": [
|
||||
"lancamento_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["lancamento_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1005,12 +965,8 @@
|
||||
"name": "antecipacoes_parcelas_lancamento_id_lancamentos_id_fk",
|
||||
"tableFrom": "antecipacoes_parcelas",
|
||||
"tableTo": "lancamentos",
|
||||
"columnsFrom": [
|
||||
"lancamento_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["lancamento_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -1018,12 +974,8 @@
|
||||
"name": "antecipacoes_parcelas_pagador_id_pagadores_id_fk",
|
||||
"tableFrom": "antecipacoes_parcelas",
|
||||
"tableTo": "pagadores",
|
||||
"columnsFrom": [
|
||||
"pagador_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["pagador_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -1031,12 +983,8 @@
|
||||
"name": "antecipacoes_parcelas_categoria_id_categorias_id_fk",
|
||||
"tableFrom": "antecipacoes_parcelas",
|
||||
"tableTo": "categorias",
|
||||
"columnsFrom": [
|
||||
"categoria_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["categoria_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -1044,12 +992,8 @@
|
||||
"name": "antecipacoes_parcelas_user_id_user_id_fk",
|
||||
"tableFrom": "antecipacoes_parcelas",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["user_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1179,12 +1123,8 @@
|
||||
"name": "faturas_user_id_user_id_fk",
|
||||
"tableFrom": "faturas",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["user_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -1192,12 +1132,8 @@
|
||||
"name": "faturas_cartao_id_cartoes_id_fk",
|
||||
"tableFrom": "faturas",
|
||||
"tableTo": "cartoes",
|
||||
"columnsFrom": [
|
||||
"cartao_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["cartao_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "cascade"
|
||||
}
|
||||
@@ -1271,12 +1207,8 @@
|
||||
"name": "anotacoes_user_id_user_id_fk",
|
||||
"tableFrom": "anotacoes",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["user_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1364,12 +1296,8 @@
|
||||
"name": "passkey_userId_user_id_fk",
|
||||
"tableFrom": "passkey",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"userId"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["userId"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1452,12 +1380,8 @@
|
||||
"name": "compartilhamentos_pagador_pagador_id_pagadores_id_fk",
|
||||
"tableFrom": "compartilhamentos_pagador",
|
||||
"tableTo": "pagadores",
|
||||
"columnsFrom": [
|
||||
"pagador_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["pagador_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -1465,12 +1389,8 @@
|
||||
"name": "compartilhamentos_pagador_shared_with_user_id_user_id_fk",
|
||||
"tableFrom": "compartilhamentos_pagador",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"shared_with_user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["shared_with_user_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -1478,12 +1398,8 @@
|
||||
"name": "compartilhamentos_pagador_created_by_user_id_user_id_fk",
|
||||
"tableFrom": "compartilhamentos_pagador",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"created_by_user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["created_by_user_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1639,12 +1555,8 @@
|
||||
"name": "pagadores_user_id_user_id_fk",
|
||||
"tableFrom": "pagadores",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["user_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1733,12 +1645,8 @@
|
||||
"name": "insights_salvos_user_id_user_id_fk",
|
||||
"tableFrom": "insights_salvos",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["user_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1808,12 +1716,8 @@
|
||||
"name": "session_userId_user_id_fk",
|
||||
"tableFrom": "session",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"userId"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["userId"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -1823,9 +1727,7 @@
|
||||
"session_token_unique": {
|
||||
"name": "session_token_unique",
|
||||
"nullsNotDistinct": false,
|
||||
"columns": [
|
||||
"token"
|
||||
]
|
||||
"columns": ["token"]
|
||||
}
|
||||
},
|
||||
"policies": {},
|
||||
@@ -2228,12 +2130,8 @@
|
||||
"name": "lancamentos_antecipacao_id_antecipacoes_parcelas_id_fk",
|
||||
"tableFrom": "lancamentos",
|
||||
"tableTo": "antecipacoes_parcelas",
|
||||
"columnsFrom": [
|
||||
"antecipacao_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["antecipacao_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -2241,12 +2139,8 @@
|
||||
"name": "lancamentos_user_id_user_id_fk",
|
||||
"tableFrom": "lancamentos",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["user_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -2254,12 +2148,8 @@
|
||||
"name": "lancamentos_cartao_id_cartoes_id_fk",
|
||||
"tableFrom": "lancamentos",
|
||||
"tableTo": "cartoes",
|
||||
"columnsFrom": [
|
||||
"cartao_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["cartao_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "cascade"
|
||||
},
|
||||
@@ -2267,12 +2157,8 @@
|
||||
"name": "lancamentos_conta_id_contas_id_fk",
|
||||
"tableFrom": "lancamentos",
|
||||
"tableTo": "contas",
|
||||
"columnsFrom": [
|
||||
"conta_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["conta_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "cascade"
|
||||
},
|
||||
@@ -2280,12 +2166,8 @@
|
||||
"name": "lancamentos_categoria_id_categorias_id_fk",
|
||||
"tableFrom": "lancamentos",
|
||||
"tableTo": "categorias",
|
||||
"columnsFrom": [
|
||||
"categoria_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["categoria_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "cascade"
|
||||
},
|
||||
@@ -2293,12 +2175,8 @@
|
||||
"name": "lancamentos_pagador_id_pagadores_id_fk",
|
||||
"tableFrom": "lancamentos",
|
||||
"tableTo": "pagadores",
|
||||
"columnsFrom": [
|
||||
"pagador_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["pagador_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "cascade"
|
||||
}
|
||||
@@ -2363,9 +2241,7 @@
|
||||
"user_email_unique": {
|
||||
"name": "user_email_unique",
|
||||
"nullsNotDistinct": false,
|
||||
"columns": [
|
||||
"email"
|
||||
]
|
||||
"columns": ["email"]
|
||||
}
|
||||
},
|
||||
"policies": {},
|
||||
@@ -2443,12 +2319,8 @@
|
||||
"name": "preferencias_usuario_user_id_user_id_fk",
|
||||
"tableFrom": "preferencias_usuario",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["user_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -2458,9 +2330,7 @@
|
||||
"preferencias_usuario_user_id_unique": {
|
||||
"name": "preferencias_usuario_user_id_unique",
|
||||
"nullsNotDistinct": false,
|
||||
"columns": [
|
||||
"user_id"
|
||||
]
|
||||
"columns": ["user_id"]
|
||||
}
|
||||
},
|
||||
"policies": {},
|
||||
@@ -2552,12 +2422,8 @@
|
||||
"name": "import_category_mappings_user_id_user_id_fk",
|
||||
"tableFrom": "import_category_mappings",
|
||||
"tableTo": "user",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["user_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
@@ -2565,12 +2431,8 @@
|
||||
"name": "import_category_mappings_category_id_categorias_id_fk",
|
||||
"tableFrom": "import_category_mappings",
|
||||
"tableTo": "categorias",
|
||||
"columnsFrom": [
|
||||
"category_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsFrom": ["category_id"],
|
||||
"columnsTo": ["id"],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
@@ -2578,10 +2440,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"import_category_mappings_user_id_description_key_pk": {
|
||||
"name": "import_category_mappings_user_id_description_key_pk",
|
||||
"columns": [
|
||||
"user_id",
|
||||
"description_key"
|
||||
]
|
||||
"columns": ["user_id", "description_key"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
|
||||
14
package.json
14
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "openmonetis",
|
||||
"version": "2.0.0",
|
||||
"version": "2.0.1",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev --turbopack",
|
||||
@@ -28,9 +28,9 @@
|
||||
"backup": "bash scripts/backup.sh"
|
||||
},
|
||||
"dependencies": {
|
||||
"@ai-sdk/anthropic": "^3.0.62",
|
||||
"@ai-sdk/google": "^3.0.51",
|
||||
"@ai-sdk/openai": "^3.0.46",
|
||||
"@ai-sdk/anthropic": "^3.0.63",
|
||||
"@ai-sdk/google": "^3.0.52",
|
||||
"@ai-sdk/openai": "^3.0.47",
|
||||
"@better-auth/passkey": "^1.5.5",
|
||||
"@dnd-kit/core": "^6.3.1",
|
||||
"@dnd-kit/sortable": "^10.0.0",
|
||||
@@ -60,7 +60,7 @@
|
||||
"@tanstack/react-virtual": "^3.13.23",
|
||||
"@vercel/analytics": "^2.0.1",
|
||||
"@vercel/speed-insights": "^2.0.0",
|
||||
"ai": "^6.0.127",
|
||||
"ai": "^6.0.134",
|
||||
"better-auth": "1.5.5",
|
||||
"canvas-confetti": "^1.9.4",
|
||||
"class-variance-authority": "0.7.1",
|
||||
@@ -90,12 +90,12 @@
|
||||
"@tailwindcss/postcss": "4.2.2",
|
||||
"@types/canvas-confetti": "^1.9.0",
|
||||
"@types/node": "25.5.0",
|
||||
"@types/pg": "^8.18.0",
|
||||
"@types/pg": "^8.20.0",
|
||||
"@types/react": "19.2.14",
|
||||
"@types/react-dom": "19.2.3",
|
||||
"dotenv": "^17.3.1",
|
||||
"drizzle-kit": "0.31.10",
|
||||
"tailwindcss": "4.2.1",
|
||||
"tailwindcss": "4.2.2",
|
||||
"tsx": "4.21.0",
|
||||
"typescript": "5.9.3"
|
||||
}
|
||||
|
||||
113
pnpm-lock.yaml
generated
113
pnpm-lock.yaml
generated
@@ -9,17 +9,17 @@ importers:
|
||||
.:
|
||||
dependencies:
|
||||
'@ai-sdk/anthropic':
|
||||
specifier: ^3.0.62
|
||||
version: 3.0.62(zod@4.3.6)
|
||||
specifier: ^3.0.63
|
||||
version: 3.0.63(zod@4.3.6)
|
||||
'@ai-sdk/google':
|
||||
specifier: ^3.0.51
|
||||
version: 3.0.51(zod@4.3.6)
|
||||
specifier: ^3.0.52
|
||||
version: 3.0.52(zod@4.3.6)
|
||||
'@ai-sdk/openai':
|
||||
specifier: ^3.0.46
|
||||
version: 3.0.46(zod@4.3.6)
|
||||
specifier: ^3.0.47
|
||||
version: 3.0.47(zod@4.3.6)
|
||||
'@better-auth/passkey':
|
||||
specifier: ^1.5.5
|
||||
version: 1.5.5(933ec2e58dee4f4ee115209e94e4bc6e)
|
||||
version: 1.5.5(67982ffe784494dfa72893bff94217f8)
|
||||
'@dnd-kit/core':
|
||||
specifier: ^6.3.1
|
||||
version: 6.3.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
|
||||
@@ -31,7 +31,7 @@ importers:
|
||||
version: 3.2.2(react@19.2.4)
|
||||
'@openrouter/ai-sdk-provider':
|
||||
specifier: ^2.3.3
|
||||
version: 2.3.3(ai@6.0.129(zod@4.3.6))(zod@4.3.6)
|
||||
version: 2.3.3(ai@6.0.134(zod@4.3.6))(zod@4.3.6)
|
||||
'@radix-ui/react-alert-dialog':
|
||||
specifier: 1.1.15
|
||||
version: 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
|
||||
@@ -105,11 +105,11 @@ importers:
|
||||
specifier: ^2.0.0
|
||||
version: 2.0.0(next@16.1.7(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)
|
||||
ai:
|
||||
specifier: ^6.0.127
|
||||
version: 6.0.129(zod@4.3.6)
|
||||
specifier: ^6.0.134
|
||||
version: 6.0.134(zod@4.3.6)
|
||||
better-auth:
|
||||
specifier: 1.5.5
|
||||
version: 1.5.5(@prisma/client@7.4.2(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3))(drizzle-kit@0.31.10)(drizzle-orm@0.45.1(@electric-sql/pglite@0.3.15)(@opentelemetry/api@1.9.0)(@prisma/client@7.4.2(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3))(@types/pg@8.18.0)(kysely@0.28.11)(mysql2@3.15.3)(pg@8.20.0)(postgres@3.4.7)(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)))(mongodb@7.1.0)(mysql2@3.15.3)(next@16.1.7(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(pg@8.20.0)(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
|
||||
version: 1.5.5(@prisma/client@7.4.2(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3))(drizzle-kit@0.31.10)(drizzle-orm@0.45.1(@electric-sql/pglite@0.3.15)(@opentelemetry/api@1.9.0)(@prisma/client@7.4.2(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3))(@types/pg@8.20.0)(kysely@0.28.11)(mysql2@3.15.3)(pg@8.20.0)(postgres@3.4.7)(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)))(mongodb@7.1.0)(mysql2@3.15.3)(next@16.1.7(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(pg@8.20.0)(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
|
||||
canvas-confetti:
|
||||
specifier: ^1.9.4
|
||||
version: 1.9.4
|
||||
@@ -127,7 +127,7 @@ importers:
|
||||
version: 4.1.0
|
||||
drizzle-orm:
|
||||
specifier: 0.45.1
|
||||
version: 0.45.1(@electric-sql/pglite@0.3.15)(@opentelemetry/api@1.9.0)(@prisma/client@7.4.2(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3))(@types/pg@8.18.0)(kysely@0.28.11)(mysql2@3.15.3)(pg@8.20.0)(postgres@3.4.7)(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))
|
||||
version: 0.45.1(@electric-sql/pglite@0.3.15)(@opentelemetry/api@1.9.0)(@prisma/client@7.4.2(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3))(@types/pg@8.20.0)(kysely@0.28.11)(mysql2@3.15.3)(pg@8.20.0)(postgres@3.4.7)(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))
|
||||
jspdf:
|
||||
specifier: ^4.2.1
|
||||
version: 4.2.1
|
||||
@@ -190,8 +190,8 @@ importers:
|
||||
specifier: 25.5.0
|
||||
version: 25.5.0
|
||||
'@types/pg':
|
||||
specifier: ^8.18.0
|
||||
version: 8.18.0
|
||||
specifier: ^8.20.0
|
||||
version: 8.20.0
|
||||
'@types/react':
|
||||
specifier: 19.2.14
|
||||
version: 19.2.14
|
||||
@@ -205,8 +205,8 @@ importers:
|
||||
specifier: 0.31.10
|
||||
version: 0.31.10
|
||||
tailwindcss:
|
||||
specifier: 4.2.1
|
||||
version: 4.2.1
|
||||
specifier: 4.2.2
|
||||
version: 4.2.2
|
||||
tsx:
|
||||
specifier: 4.21.0
|
||||
version: 4.21.0
|
||||
@@ -216,32 +216,32 @@ importers:
|
||||
|
||||
packages:
|
||||
|
||||
'@ai-sdk/anthropic@3.0.62':
|
||||
resolution: {integrity: sha512-CkShXR8tmNO7QQnvpKbSMe2Vr1zUUcpqlp69iR+DYrbHm+tDJO9u6zZsjEHjcoRU9/e9z++p0W6NiuLC3aZ4Bg==}
|
||||
'@ai-sdk/anthropic@3.0.63':
|
||||
resolution: {integrity: sha512-SiLosFr0FfKfrNpAAj8mD/i3S5YBB/z5orb1DH3pN1yATuBNjjPMLnRE4P3Dn7Y5cQsro0uzw5g5117hkShWoQ==}
|
||||
engines: {node: '>=18'}
|
||||
peerDependencies:
|
||||
zod: ^3.25.76 || ^4.1.8
|
||||
|
||||
'@ai-sdk/gateway@3.0.75':
|
||||
resolution: {integrity: sha512-7Hwa0VdH+l85NFS7zqZhRRaiwZMStDxEwUoTPxPNEH6V0Vgw9wi9OGopIsYdywmfSOPfSAsPL8XXPAuaSLGchw==}
|
||||
'@ai-sdk/gateway@3.0.77':
|
||||
resolution: {integrity: sha512-UdwIG2H2YMuntJQ5L+EmED5XiwnlvDT3HOmKfVFxR4Nq/RSLFA/HcchhwfNXHZ5UJjyuL2VO0huLbWSZ9ijemQ==}
|
||||
engines: {node: '>=18'}
|
||||
peerDependencies:
|
||||
zod: ^3.25.76 || ^4.1.8
|
||||
|
||||
'@ai-sdk/google@3.0.51':
|
||||
resolution: {integrity: sha512-S5pG/iRt+E12a4TSnquBFnkHkbS+rcAJ2lRzds59vdnVqTsZGGIncaLefpGmq/MZNfbSo6JIO60duoZIpZXOqg==}
|
||||
'@ai-sdk/google@3.0.52':
|
||||
resolution: {integrity: sha512-HiFB4VlHnv55k9xIbgQW9tHw5OsLXzbAghnDUqrnk/S94QpQuyrDwLSDsk/tUkxJeT00B+wvhL1y6/SARdLeXw==}
|
||||
engines: {node: '>=18'}
|
||||
peerDependencies:
|
||||
zod: ^3.25.76 || ^4.1.8
|
||||
|
||||
'@ai-sdk/openai@3.0.46':
|
||||
resolution: {integrity: sha512-8grBb4sAMU0MAC6uOOD/wP/+SyX/3MMS/Lf+ToGgeUzoF9oWU9dWBLkvgjXpn7Ro81bPDeycW2GCCT63V/Vnvg==}
|
||||
'@ai-sdk/openai@3.0.47':
|
||||
resolution: {integrity: sha512-bRsb2sDN5u+pKO3Kdr0flpxtL+cPwQ2uCo/pVyzIbj2I4AkKAokJHhw5JWLVOeEwdlYzWfmv+hzaiGarzUcTFQ==}
|
||||
engines: {node: '>=18'}
|
||||
peerDependencies:
|
||||
zod: ^3.25.76 || ^4.1.8
|
||||
|
||||
'@ai-sdk/provider-utils@4.0.20':
|
||||
resolution: {integrity: sha512-gpUIj9uDhIGbuo9afKEgQ074BWmhvK4THJAAeBjRnroTy2yQYo6rbtGD7pQDMZM8ouXPYmT/SCdkWVJ0KcpX8A==}
|
||||
'@ai-sdk/provider-utils@4.0.21':
|
||||
resolution: {integrity: sha512-MtFUYI1/8mgDvRmaBDjbLJPFFrMG777AvSgyIFQtZHIMzm88R/12vYBBpnk7pfiWLFE1DSZzY4WDYzGbKAcmiw==}
|
||||
engines: {node: '>=18'}
|
||||
peerDependencies:
|
||||
zod: ^3.25.76 || ^4.1.8
|
||||
@@ -2240,8 +2240,8 @@ packages:
|
||||
'@types/pako@2.0.4':
|
||||
resolution: {integrity: sha512-VWDCbrLeVXJM9fihYodcLiIv0ku+AlOa/TQ1SvYOaBuyrSKgEcro95LJyIsJ4vSo6BXIxOKxiJAat04CmST9Fw==}
|
||||
|
||||
'@types/pg@8.18.0':
|
||||
resolution: {integrity: sha512-gT+oueVQkqnj6ajGJXblFR4iavIXWsGAFCk3dP4Kki5+a9R4NMt0JARdk6s8cUKcfUoqP5dAtDSLU8xYUTFV+Q==}
|
||||
'@types/pg@8.20.0':
|
||||
resolution: {integrity: sha512-bEPFOaMAHTEP1EzpvHTbmwR8UsFyHSKsRisLIHVMXnpNefSbGA1bD6CVy+qKjGSqmZqNqBDV2azOBo8TgkcVow==}
|
||||
|
||||
'@types/raf@3.4.3':
|
||||
resolution: {integrity: sha512-c4YAvMedbPZ5tEyxzQdMoOhhJ4RD3rngZIdwC2/qDN3d7JpEhB6fiBRKVY1lg5B7Wk+uPBjn5f39j1/2MY1oOw==}
|
||||
@@ -2329,8 +2329,8 @@ packages:
|
||||
resolution: {integrity: sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==}
|
||||
engines: {node: '>=0.8'}
|
||||
|
||||
ai@6.0.129:
|
||||
resolution: {integrity: sha512-5nGckqbzwUBZD7wV9jsA8qaoYRwGpU9LVMtXD+ZrxSi2H6QNjpbrhsuuEBKS9xcMYevCviVNoFzpmSUWzn45Hw==}
|
||||
ai@6.0.134:
|
||||
resolution: {integrity: sha512-YalNEaavld/kE444gOcsMKXdVVRGEe0SK77fAFcWYcqLg+a7xKnEet8bdfrEAJTfnMjj01rhgrIL10903w1a5Q==}
|
||||
engines: {node: '>=18'}
|
||||
peerDependencies:
|
||||
zod: ^3.25.76 || ^4.1.8
|
||||
@@ -3380,9 +3380,6 @@ packages:
|
||||
tailwind-merge@3.5.0:
|
||||
resolution: {integrity: sha512-I8K9wewnVDkL1NTGoqWmVEIlUcB9gFriAEkXkfCjX5ib8ezGxtR3xD7iZIxrfArjEsH7F1CHD4RFUtxefdqV/A==}
|
||||
|
||||
tailwindcss@4.2.1:
|
||||
resolution: {integrity: sha512-/tBrSQ36vCleJkAOsy9kbNTgaxvGbyOamC30PRePTQe/o1MFwEKHQk4Cn7BNGaPtjp+PuUrByJehM1hgxfq4sw==}
|
||||
|
||||
tailwindcss@4.2.2:
|
||||
resolution: {integrity: sha512-KWBIxs1Xb6NoLdMVqhbhgwZf2PGBpPEiwOqgI4pFIYbNTfBXiKYyWoTsXgBQ9WFg/OlhnvHaY+AEpW7wSmFo2Q==}
|
||||
|
||||
@@ -3514,32 +3511,32 @@ packages:
|
||||
|
||||
snapshots:
|
||||
|
||||
'@ai-sdk/anthropic@3.0.62(zod@4.3.6)':
|
||||
'@ai-sdk/anthropic@3.0.63(zod@4.3.6)':
|
||||
dependencies:
|
||||
'@ai-sdk/provider': 3.0.8
|
||||
'@ai-sdk/provider-utils': 4.0.20(zod@4.3.6)
|
||||
'@ai-sdk/provider-utils': 4.0.21(zod@4.3.6)
|
||||
zod: 4.3.6
|
||||
|
||||
'@ai-sdk/gateway@3.0.75(zod@4.3.6)':
|
||||
'@ai-sdk/gateway@3.0.77(zod@4.3.6)':
|
||||
dependencies:
|
||||
'@ai-sdk/provider': 3.0.8
|
||||
'@ai-sdk/provider-utils': 4.0.20(zod@4.3.6)
|
||||
'@ai-sdk/provider-utils': 4.0.21(zod@4.3.6)
|
||||
'@vercel/oidc': 3.1.0
|
||||
zod: 4.3.6
|
||||
|
||||
'@ai-sdk/google@3.0.51(zod@4.3.6)':
|
||||
'@ai-sdk/google@3.0.52(zod@4.3.6)':
|
||||
dependencies:
|
||||
'@ai-sdk/provider': 3.0.8
|
||||
'@ai-sdk/provider-utils': 4.0.20(zod@4.3.6)
|
||||
'@ai-sdk/provider-utils': 4.0.21(zod@4.3.6)
|
||||
zod: 4.3.6
|
||||
|
||||
'@ai-sdk/openai@3.0.46(zod@4.3.6)':
|
||||
'@ai-sdk/openai@3.0.47(zod@4.3.6)':
|
||||
dependencies:
|
||||
'@ai-sdk/provider': 3.0.8
|
||||
'@ai-sdk/provider-utils': 4.0.20(zod@4.3.6)
|
||||
'@ai-sdk/provider-utils': 4.0.21(zod@4.3.6)
|
||||
zod: 4.3.6
|
||||
|
||||
'@ai-sdk/provider-utils@4.0.20(zod@4.3.6)':
|
||||
'@ai-sdk/provider-utils@4.0.21(zod@4.3.6)':
|
||||
dependencies:
|
||||
'@ai-sdk/provider': 3.0.8
|
||||
'@standard-schema/spec': 1.1.0
|
||||
@@ -3577,12 +3574,12 @@ snapshots:
|
||||
nanostores: 1.1.1
|
||||
zod: 4.3.6
|
||||
|
||||
'@better-auth/drizzle-adapter@1.5.5(@better-auth/core@1.5.5(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.1)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(drizzle-orm@0.45.1(@electric-sql/pglite@0.3.15)(@opentelemetry/api@1.9.0)(@prisma/client@7.4.2(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3))(@types/pg@8.18.0)(kysely@0.28.11)(mysql2@3.15.3)(pg@8.20.0)(postgres@3.4.7)(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)))':
|
||||
'@better-auth/drizzle-adapter@1.5.5(@better-auth/core@1.5.5(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.1)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(drizzle-orm@0.45.1(@electric-sql/pglite@0.3.15)(@opentelemetry/api@1.9.0)(@prisma/client@7.4.2(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3))(@types/pg@8.20.0)(kysely@0.28.11)(mysql2@3.15.3)(pg@8.20.0)(postgres@3.4.7)(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)))':
|
||||
dependencies:
|
||||
'@better-auth/core': 1.5.5(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.1)(kysely@0.28.11)(nanostores@1.1.1)
|
||||
'@better-auth/utils': 0.3.1
|
||||
optionalDependencies:
|
||||
drizzle-orm: 0.45.1(@electric-sql/pglite@0.3.15)(@opentelemetry/api@1.9.0)(@prisma/client@7.4.2(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3))(@types/pg@8.18.0)(kysely@0.28.11)(mysql2@3.15.3)(pg@8.20.0)(postgres@3.4.7)(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))
|
||||
drizzle-orm: 0.45.1(@electric-sql/pglite@0.3.15)(@opentelemetry/api@1.9.0)(@prisma/client@7.4.2(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3))(@types/pg@8.20.0)(kysely@0.28.11)(mysql2@3.15.3)(pg@8.20.0)(postgres@3.4.7)(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))
|
||||
|
||||
'@better-auth/kysely-adapter@1.5.5(@better-auth/core@1.5.5(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.1)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(kysely@0.28.11)':
|
||||
dependencies:
|
||||
@@ -3601,14 +3598,14 @@ snapshots:
|
||||
'@better-auth/utils': 0.3.1
|
||||
mongodb: 7.1.0
|
||||
|
||||
'@better-auth/passkey@1.5.5(933ec2e58dee4f4ee115209e94e4bc6e)':
|
||||
'@better-auth/passkey@1.5.5(67982ffe784494dfa72893bff94217f8)':
|
||||
dependencies:
|
||||
'@better-auth/core': 1.5.5(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.1)(kysely@0.28.11)(nanostores@1.1.1)
|
||||
'@better-auth/utils': 0.3.1
|
||||
'@better-fetch/fetch': 1.1.21
|
||||
'@simplewebauthn/browser': 13.2.2
|
||||
'@simplewebauthn/server': 13.2.3
|
||||
better-auth: 1.5.5(@prisma/client@7.4.2(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3))(drizzle-kit@0.31.10)(drizzle-orm@0.45.1(@electric-sql/pglite@0.3.15)(@opentelemetry/api@1.9.0)(@prisma/client@7.4.2(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3))(@types/pg@8.18.0)(kysely@0.28.11)(mysql2@3.15.3)(pg@8.20.0)(postgres@3.4.7)(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)))(mongodb@7.1.0)(mysql2@3.15.3)(next@16.1.7(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(pg@8.20.0)(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
|
||||
better-auth: 1.5.5(@prisma/client@7.4.2(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3))(drizzle-kit@0.31.10)(drizzle-orm@0.45.1(@electric-sql/pglite@0.3.15)(@opentelemetry/api@1.9.0)(@prisma/client@7.4.2(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3))(@types/pg@8.20.0)(kysely@0.28.11)(mysql2@3.15.3)(pg@8.20.0)(postgres@3.4.7)(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)))(mongodb@7.1.0)(mysql2@3.15.3)(next@16.1.7(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(pg@8.20.0)(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
|
||||
better-call: 1.3.2(zod@4.3.6)
|
||||
nanostores: 1.1.1
|
||||
zod: 4.3.6
|
||||
@@ -4146,9 +4143,9 @@ snapshots:
|
||||
|
||||
'@noble/hashes@2.0.1': {}
|
||||
|
||||
'@openrouter/ai-sdk-provider@2.3.3(ai@6.0.129(zod@4.3.6))(zod@4.3.6)':
|
||||
'@openrouter/ai-sdk-provider@2.3.3(ai@6.0.134(zod@4.3.6))(zod@4.3.6)':
|
||||
dependencies:
|
||||
ai: 6.0.129(zod@4.3.6)
|
||||
ai: 6.0.134(zod@4.3.6)
|
||||
zod: 4.3.6
|
||||
|
||||
'@opentelemetry/api@1.9.0': {}
|
||||
@@ -5305,7 +5302,7 @@ snapshots:
|
||||
|
||||
'@types/pako@2.0.4': {}
|
||||
|
||||
'@types/pg@8.18.0':
|
||||
'@types/pg@8.20.0':
|
||||
dependencies:
|
||||
'@types/node': 25.5.0
|
||||
pg-protocol: 1.13.0
|
||||
@@ -5347,11 +5344,11 @@ snapshots:
|
||||
|
||||
adler-32@1.3.1: {}
|
||||
|
||||
ai@6.0.129(zod@4.3.6):
|
||||
ai@6.0.134(zod@4.3.6):
|
||||
dependencies:
|
||||
'@ai-sdk/gateway': 3.0.75(zod@4.3.6)
|
||||
'@ai-sdk/gateway': 3.0.77(zod@4.3.6)
|
||||
'@ai-sdk/provider': 3.0.8
|
||||
'@ai-sdk/provider-utils': 4.0.20(zod@4.3.6)
|
||||
'@ai-sdk/provider-utils': 4.0.21(zod@4.3.6)
|
||||
'@opentelemetry/api': 1.9.0
|
||||
zod: 4.3.6
|
||||
|
||||
@@ -5378,10 +5375,10 @@ snapshots:
|
||||
|
||||
baseline-browser-mapping@2.10.0: {}
|
||||
|
||||
better-auth@1.5.5(@prisma/client@7.4.2(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3))(drizzle-kit@0.31.10)(drizzle-orm@0.45.1(@electric-sql/pglite@0.3.15)(@opentelemetry/api@1.9.0)(@prisma/client@7.4.2(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3))(@types/pg@8.18.0)(kysely@0.28.11)(mysql2@3.15.3)(pg@8.20.0)(postgres@3.4.7)(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)))(mongodb@7.1.0)(mysql2@3.15.3)(next@16.1.7(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(pg@8.20.0)(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4):
|
||||
better-auth@1.5.5(@prisma/client@7.4.2(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3))(drizzle-kit@0.31.10)(drizzle-orm@0.45.1(@electric-sql/pglite@0.3.15)(@opentelemetry/api@1.9.0)(@prisma/client@7.4.2(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3))(@types/pg@8.20.0)(kysely@0.28.11)(mysql2@3.15.3)(pg@8.20.0)(postgres@3.4.7)(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)))(mongodb@7.1.0)(mysql2@3.15.3)(next@16.1.7(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(pg@8.20.0)(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4):
|
||||
dependencies:
|
||||
'@better-auth/core': 1.5.5(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.1)(kysely@0.28.11)(nanostores@1.1.1)
|
||||
'@better-auth/drizzle-adapter': 1.5.5(@better-auth/core@1.5.5(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.1)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(drizzle-orm@0.45.1(@electric-sql/pglite@0.3.15)(@opentelemetry/api@1.9.0)(@prisma/client@7.4.2(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3))(@types/pg@8.18.0)(kysely@0.28.11)(mysql2@3.15.3)(pg@8.20.0)(postgres@3.4.7)(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)))
|
||||
'@better-auth/drizzle-adapter': 1.5.5(@better-auth/core@1.5.5(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.1)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(drizzle-orm@0.45.1(@electric-sql/pglite@0.3.15)(@opentelemetry/api@1.9.0)(@prisma/client@7.4.2(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3))(@types/pg@8.20.0)(kysely@0.28.11)(mysql2@3.15.3)(pg@8.20.0)(postgres@3.4.7)(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)))
|
||||
'@better-auth/kysely-adapter': 1.5.5(@better-auth/core@1.5.5(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.1)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(kysely@0.28.11)
|
||||
'@better-auth/memory-adapter': 1.5.5(@better-auth/core@1.5.5(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.1)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)
|
||||
'@better-auth/mongo-adapter': 1.5.5(@better-auth/core@1.5.5(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.2(zod@4.3.6))(jose@6.2.1)(kysely@0.28.11)(nanostores@1.1.1))(@better-auth/utils@0.3.1)(mongodb@7.1.0)
|
||||
@@ -5400,7 +5397,7 @@ snapshots:
|
||||
optionalDependencies:
|
||||
'@prisma/client': 7.4.2(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3)
|
||||
drizzle-kit: 0.31.10
|
||||
drizzle-orm: 0.45.1(@electric-sql/pglite@0.3.15)(@opentelemetry/api@1.9.0)(@prisma/client@7.4.2(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3))(@types/pg@8.18.0)(kysely@0.28.11)(mysql2@3.15.3)(pg@8.20.0)(postgres@3.4.7)(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))
|
||||
drizzle-orm: 0.45.1(@electric-sql/pglite@0.3.15)(@opentelemetry/api@1.9.0)(@prisma/client@7.4.2(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3))(@types/pg@8.20.0)(kysely@0.28.11)(mysql2@3.15.3)(pg@8.20.0)(postgres@3.4.7)(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))
|
||||
mongodb: 7.1.0
|
||||
mysql2: 3.15.3
|
||||
next: 16.1.7(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
|
||||
@@ -5607,12 +5604,12 @@ snapshots:
|
||||
esbuild: 0.25.12
|
||||
tsx: 4.21.0
|
||||
|
||||
drizzle-orm@0.45.1(@electric-sql/pglite@0.3.15)(@opentelemetry/api@1.9.0)(@prisma/client@7.4.2(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3))(@types/pg@8.18.0)(kysely@0.28.11)(mysql2@3.15.3)(pg@8.20.0)(postgres@3.4.7)(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)):
|
||||
drizzle-orm@0.45.1(@electric-sql/pglite@0.3.15)(@opentelemetry/api@1.9.0)(@prisma/client@7.4.2(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3))(@types/pg@8.20.0)(kysely@0.28.11)(mysql2@3.15.3)(pg@8.20.0)(postgres@3.4.7)(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)):
|
||||
optionalDependencies:
|
||||
'@electric-sql/pglite': 0.3.15
|
||||
'@opentelemetry/api': 1.9.0
|
||||
'@prisma/client': 7.4.2(prisma@7.4.2(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3)
|
||||
'@types/pg': 8.18.0
|
||||
'@types/pg': 8.20.0
|
||||
kysely: 0.28.11
|
||||
mysql2: 3.15.3
|
||||
pg: 8.20.0
|
||||
@@ -6397,8 +6394,6 @@ snapshots:
|
||||
|
||||
tailwind-merge@3.5.0: {}
|
||||
|
||||
tailwindcss@4.2.1: {}
|
||||
|
||||
tailwindcss@4.2.2: {}
|
||||
|
||||
tapable@2.3.0: {}
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 5.4 KiB |
@@ -1,6 +1,7 @@
|
||||
import { InboxPage } from "@/features/inbox/components/inbox-page";
|
||||
import {
|
||||
type ResolvedInboxSearchParams,
|
||||
resolveInboxApp,
|
||||
resolveInboxPagination,
|
||||
resolveInboxStatus,
|
||||
} from "@/features/inbox/page-helpers";
|
||||
@@ -8,6 +9,7 @@ import {
|
||||
fetchAppLogoMap,
|
||||
fetchInboxDialogData,
|
||||
fetchInboxItemsPage,
|
||||
fetchInboxSourceApps,
|
||||
fetchInboxStatusCounts,
|
||||
} from "@/features/inbox/queries";
|
||||
import { getUserId } from "@/shared/lib/auth/server";
|
||||
@@ -32,21 +34,31 @@ export default async function Page({ searchParams }: PageProps) {
|
||||
const userId = await getUserId();
|
||||
const resolvedSearchParams = searchParams ? await searchParams : undefined;
|
||||
const activeStatus = resolveInboxStatus(resolvedSearchParams);
|
||||
const activeApp = resolveInboxApp(resolvedSearchParams);
|
||||
const paginationInput = resolveInboxPagination(resolvedSearchParams);
|
||||
|
||||
const [itemsPage, counts, dialogData, appLogoMap] = await Promise.all([
|
||||
fetchInboxItemsPage(userId, activeStatus, paginationInput),
|
||||
const [itemsPage, counts, sourceApps, dialogData, appLogoMap] =
|
||||
await Promise.all([
|
||||
fetchInboxItemsPage(userId, activeStatus, {
|
||||
...paginationInput,
|
||||
sourceApp: activeApp,
|
||||
}),
|
||||
fetchInboxStatusCounts(userId),
|
||||
fetchInboxSourceApps(userId, activeStatus).catch(() => [] as string[]),
|
||||
activeStatus === "pending"
|
||||
? fetchInboxDialogData(userId)
|
||||
: Promise.resolve(EMPTY_DIALOG_DATA),
|
||||
fetchAppLogoMap(userId),
|
||||
]);
|
||||
|
||||
const normalizedSourceApps = Array.isArray(sourceApps) ? sourceApps : [];
|
||||
|
||||
return (
|
||||
<main className="flex flex-col items-start gap-6">
|
||||
<InboxPage
|
||||
activeStatus={activeStatus}
|
||||
activeApp={activeApp}
|
||||
sourceApps={normalizedSourceApps}
|
||||
items={itemsPage.items}
|
||||
counts={counts}
|
||||
pagination={itemsPage.pagination}
|
||||
|
||||
@@ -1,14 +1,25 @@
|
||||
import { ImportPage } from "@/features/transactions/components/import/import-page";
|
||||
import {
|
||||
buildOptionSets,
|
||||
buildSluggedFilters,
|
||||
} from "@/features/transactions/page-helpers";
|
||||
import { fetchTransactionFilterSources } from "@/features/transactions/queries";
|
||||
import { buildOptionSets, buildSluggedFilters } from "@/features/transactions/page-helpers";
|
||||
import { getUserId } from "@/shared/lib/auth/server";
|
||||
|
||||
export default async function Page() {
|
||||
const userId = await getUserId();
|
||||
const filterSources = await fetchTransactionFilterSources(userId);
|
||||
const sluggedFilters = buildSluggedFilters(filterSources);
|
||||
const { payerOptions, accountOptions, cardOptions, categoryOptions, defaultPayerId } =
|
||||
buildOptionSets({ ...sluggedFilters, payerRows: filterSources.payerRows });
|
||||
const {
|
||||
payerOptions,
|
||||
accountOptions,
|
||||
cardOptions,
|
||||
categoryOptions,
|
||||
defaultPayerId,
|
||||
} = buildOptionSets({
|
||||
...sluggedFilters,
|
||||
payerRows: filterSources.payerRows,
|
||||
});
|
||||
|
||||
return (
|
||||
<main className="flex flex-col gap-6">
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import { version as APP_VERSION } from "@/package.json";
|
||||
import { db } from "@/shared/lib/db";
|
||||
|
||||
const APP_VERSION = "1.0.0";
|
||||
|
||||
/**
|
||||
* Health check endpoint para Docker, monitoring e OpenMonetis Companion
|
||||
* GET /api/health
|
||||
|
||||
@@ -48,8 +48,7 @@ const accountBaseSchema = z.object({
|
||||
.string({ message: "Selecione um logo." })
|
||||
.trim()
|
||||
.min(1, "Selecione um logo."),
|
||||
initialBalance: z
|
||||
.union([
|
||||
initialBalance: z.union([
|
||||
z.number(),
|
||||
z
|
||||
.string()
|
||||
|
||||
@@ -20,16 +20,15 @@ import {
|
||||
CardTitle,
|
||||
} from "@/shared/components/ui/card";
|
||||
import { Checkbox } from "@/shared/components/ui/checkbox";
|
||||
import {
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
TooltipTrigger,
|
||||
} from "@/shared/components/ui/tooltip";
|
||||
import { resolveLogoSrc } from "@/shared/lib/logo";
|
||||
import type { InboxItem } from "./types";
|
||||
|
||||
// O timestamp vem do app Android em horário local mas salvo como UTC.
|
||||
// Adicionamos o offset de Brasília para corrigir o cálculo de "há X tempo".
|
||||
const BRASILIA_OFFSET_MS = 3 * 60 * 60 * 1000;
|
||||
|
||||
function adjustToBrasilia(date: Date): Date {
|
||||
return new Date(date.getTime() + BRASILIA_OFFSET_MS);
|
||||
}
|
||||
const DEFAULT_INBOX_APP_LOGO = "/avatars/default_icon.png";
|
||||
|
||||
function findMatchingLogo(
|
||||
sourceAppName: string | null,
|
||||
@@ -78,17 +77,19 @@ export function InboxCard({
|
||||
const matchedLogo = appLogoMap
|
||||
? findMatchingLogo(item.sourceAppName, appLogoMap)
|
||||
: null;
|
||||
const displayLogo = matchedLogo ?? DEFAULT_INBOX_APP_LOGO;
|
||||
|
||||
const amount = item.parsedAmount ? parseFloat(item.parsedAmount) : null;
|
||||
|
||||
const rawDate = new Date(item.notificationTimestamp);
|
||||
const notificationDate = adjustToBrasilia(rawDate);
|
||||
const createdAtDate = new Date(item.createdAt);
|
||||
|
||||
const timeAgo = formatDistanceToNow(notificationDate, {
|
||||
const timeAgo = formatDistanceToNow(createdAtDate, {
|
||||
addSuffix: true,
|
||||
locale: ptBR,
|
||||
});
|
||||
|
||||
const fullDate = format(createdAtDate, "PPpp", { locale: ptBR });
|
||||
|
||||
const statusDate =
|
||||
item.status === "processed"
|
||||
? item.processedAt
|
||||
@@ -107,21 +108,32 @@ export function InboxCard({
|
||||
<CardHeader className="pt-4">
|
||||
<div className="flex items-center justify-between gap-2">
|
||||
<CardTitle className="flex min-w-0 items-center gap-1.5 text-sm">
|
||||
{matchedLogo && (
|
||||
<Image
|
||||
src={matchedLogo}
|
||||
alt=""
|
||||
width={24}
|
||||
height={24}
|
||||
className="shrink-0 rounded-full"
|
||||
{onSelectToggle && (
|
||||
<Checkbox
|
||||
checked={!!selected}
|
||||
onCheckedChange={() => onSelectToggle(item.id)}
|
||||
aria-label="Selecionar item"
|
||||
className="shrink-0"
|
||||
/>
|
||||
)}
|
||||
<Image
|
||||
src={displayLogo}
|
||||
alt=""
|
||||
width={32}
|
||||
height={32}
|
||||
className="shrink-0 rounded-full"
|
||||
/>
|
||||
<span className="truncate">
|
||||
{item.sourceAppName || item.sourceApp}
|
||||
</span>
|
||||
<span className="shrink-0 text-xs font-normal text-muted-foreground">
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<span className="shrink-0 cursor-default text-xs font-normal text-muted-foreground underline decoration-dotted underline-offset-2">
|
||||
{timeAgo}
|
||||
</span>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>{fullDate}</TooltipContent>
|
||||
</Tooltip>
|
||||
</CardTitle>
|
||||
{amount !== null && (
|
||||
<MoneyValues amount={amount} className="shrink-0 text-sm" />
|
||||
@@ -174,13 +186,6 @@ export function InboxCard({
|
||||
<RiDeleteBinLine className="size-4" />
|
||||
</Button>
|
||||
)}
|
||||
{onSelectToggle && (
|
||||
<Checkbox
|
||||
checked={!!selected}
|
||||
onCheckedChange={() => onSelectToggle(item.id)}
|
||||
aria-label="Selecionar item"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</CardFooter>
|
||||
) : (
|
||||
@@ -213,13 +218,6 @@ export function InboxCard({
|
||||
>
|
||||
<RiDeleteBinLine className="size-4" />
|
||||
</Button>
|
||||
{onSelectToggle && (
|
||||
<Checkbox
|
||||
checked={!!selected}
|
||||
onCheckedChange={() => onSelectToggle(item.id)}
|
||||
aria-label="Selecionar item"
|
||||
/>
|
||||
)}
|
||||
</CardFooter>
|
||||
)}
|
||||
</Card>
|
||||
|
||||
@@ -52,7 +52,14 @@ export function InboxDetailsDialog({
|
||||
<div className="grid gap-2 text-sm">
|
||||
<div className="flex justify-between">
|
||||
<span className="text-muted-foreground">App</span>
|
||||
<div className="flex flex-col items-end gap-0.5">
|
||||
<span>{item.sourceAppName || item.sourceApp}</span>
|
||||
{item.sourceAppName && (
|
||||
<span className="font-mono text-xs text-muted-foreground">
|
||||
{item.sourceApp}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -109,6 +116,11 @@ export function InboxDetailsDialog({
|
||||
</div>
|
||||
|
||||
<DialogFooter>
|
||||
<DialogClose asChild>
|
||||
<Button type="button" variant="outline">
|
||||
Fechar
|
||||
</Button>
|
||||
</DialogClose>
|
||||
{isPending && onProcess && (
|
||||
<Button
|
||||
type="button"
|
||||
@@ -120,11 +132,6 @@ export function InboxDetailsDialog({
|
||||
Processar
|
||||
</Button>
|
||||
)}
|
||||
<DialogClose asChild>
|
||||
<Button type="button" variant="outline">
|
||||
Fechar
|
||||
</Button>
|
||||
</DialogClose>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
|
||||
@@ -6,8 +6,12 @@ import {
|
||||
RiArrowRightDoubleLine,
|
||||
RiArrowRightSLine,
|
||||
RiAtLine,
|
||||
RiCalendarEventLine,
|
||||
RiDeleteBinLine,
|
||||
} from "@remixicon/react";
|
||||
import { format } from "date-fns";
|
||||
import { ptBR } from "date-fns/locale";
|
||||
import Image from "next/image";
|
||||
import { usePathname, useRouter, useSearchParams } from "next/navigation";
|
||||
import { useEffect, useMemo, useState, useTransition } from "react";
|
||||
import { toast } from "sonner";
|
||||
@@ -42,6 +46,7 @@ import {
|
||||
TabsList,
|
||||
TabsTrigger,
|
||||
} from "@/shared/components/ui/tabs";
|
||||
import { resolveLogoSrc } from "@/shared/lib/logo";
|
||||
import { InboxCard } from "./inbox-card";
|
||||
import { InboxDetailsDialog } from "./inbox-details-dialog";
|
||||
import type {
|
||||
@@ -52,8 +57,71 @@ import type {
|
||||
SelectOption,
|
||||
} from "./types";
|
||||
|
||||
const BRASILIA_OFFSET_MS = 3 * 60 * 60 * 1000;
|
||||
const DEFAULT_INBOX_APP_LOGO = "/avatars/default_icon.png";
|
||||
|
||||
function getDateKey(date: Date): string {
|
||||
const adjusted = new Date(date.getTime() + BRASILIA_OFFSET_MS);
|
||||
return adjusted.toISOString().slice(0, 10);
|
||||
}
|
||||
|
||||
function getGroupLabel(dateKey: string): string {
|
||||
const now = new Date();
|
||||
const todayKey = getDateKey(now);
|
||||
const yesterdayKey = getDateKey(
|
||||
new Date(now.getTime() - 24 * 60 * 60 * 1000),
|
||||
);
|
||||
if (dateKey === todayKey) return "Hoje";
|
||||
if (dateKey === yesterdayKey) return "Ontem";
|
||||
const [year, month, day] = dateKey.split("-").map(Number);
|
||||
return format(new Date(year, month - 1, day), "d 'de' MMMM", {
|
||||
locale: ptBR,
|
||||
});
|
||||
}
|
||||
|
||||
function groupItemsByDay(
|
||||
items: InboxItem[],
|
||||
): { label: string; items: InboxItem[] }[] {
|
||||
const groups = new Map<string, InboxItem[]>();
|
||||
for (const item of items) {
|
||||
const key = getDateKey(new Date(item.notificationTimestamp));
|
||||
const group = groups.get(key);
|
||||
if (group) {
|
||||
group.push(item);
|
||||
} else {
|
||||
groups.set(key, [item]);
|
||||
}
|
||||
}
|
||||
const sortedKeys = [...groups.keys()].sort((a, b) => b.localeCompare(a));
|
||||
return sortedKeys.map((key) => ({
|
||||
label: getGroupLabel(key),
|
||||
items: groups.get(key) ?? [],
|
||||
}));
|
||||
}
|
||||
|
||||
function findMatchingLogo(
|
||||
sourceAppName: string | null,
|
||||
appLogoMap: Record<string, string>,
|
||||
): string | null {
|
||||
if (!sourceAppName) return null;
|
||||
|
||||
const appName = sourceAppName.toLowerCase();
|
||||
|
||||
if (appLogoMap[appName]) return resolveLogoSrc(appLogoMap[appName]);
|
||||
|
||||
for (const [name, logo] of Object.entries(appLogoMap)) {
|
||||
if (name.includes(appName) || appName.includes(name)) {
|
||||
return resolveLogoSrc(logo);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
interface InboxPageProps {
|
||||
activeStatus: InboxStatus;
|
||||
activeApp: string | null;
|
||||
sourceApps: string[];
|
||||
items: InboxItem[];
|
||||
counts: InboxStatusCounts;
|
||||
pagination: InboxPaginationState;
|
||||
@@ -69,6 +137,8 @@ interface InboxPageProps {
|
||||
|
||||
export function InboxPage({
|
||||
activeStatus,
|
||||
activeApp,
|
||||
sourceApps = [],
|
||||
items,
|
||||
counts,
|
||||
pagination,
|
||||
@@ -111,6 +181,38 @@ export function InboxPage({
|
||||
const [selectionBulkStatus, setSelectionBulkStatus] =
|
||||
useState<InboxStatus>("pending");
|
||||
|
||||
const normalizedSourceApps = useMemo(() => {
|
||||
if (!Array.isArray(sourceApps)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const uniqueApps = new Set<string>();
|
||||
for (const app of sourceApps) {
|
||||
if (typeof app !== "string") {
|
||||
continue;
|
||||
}
|
||||
|
||||
const trimmedApp = app.trim();
|
||||
if (!trimmedApp) {
|
||||
continue;
|
||||
}
|
||||
|
||||
uniqueApps.add(trimmedApp);
|
||||
}
|
||||
|
||||
return [...uniqueApps].sort((left, right) =>
|
||||
left.localeCompare(right, "pt-BR"),
|
||||
);
|
||||
}, [sourceApps]);
|
||||
|
||||
const appFilterOptions =
|
||||
activeApp && !normalizedSourceApps.includes(activeApp)
|
||||
? [activeApp, ...normalizedSourceApps]
|
||||
: normalizedSourceApps;
|
||||
|
||||
const getAppLogo = (appName: string | null) =>
|
||||
findMatchingLogo(appName, appLogoMap) ?? DEFAULT_INBOX_APP_LOGO;
|
||||
|
||||
const handleProcessOpenChange = (open: boolean) => {
|
||||
setProcessOpen(open);
|
||||
if (!open) {
|
||||
@@ -239,7 +341,6 @@ export function InboxPage({
|
||||
setSelectedIds([]);
|
||||
return;
|
||||
}
|
||||
|
||||
setSelectedIds(items.map((item) => item.id));
|
||||
};
|
||||
|
||||
@@ -276,8 +377,42 @@ export function InboxPage({
|
||||
});
|
||||
};
|
||||
|
||||
const handleAppChange = (nextApp: string) => {
|
||||
const nextParams = new URLSearchParams(searchParams.toString());
|
||||
if (nextApp === "all") {
|
||||
nextParams.delete("app");
|
||||
} else {
|
||||
nextParams.set("app", nextApp);
|
||||
}
|
||||
nextParams.delete("page");
|
||||
startTransition(() => {
|
||||
const target = nextParams.toString()
|
||||
? `${pathname}?${nextParams.toString()}`
|
||||
: pathname;
|
||||
router.replace(target, { scroll: false });
|
||||
});
|
||||
};
|
||||
|
||||
const handleTabChange = (nextStatus: string) => {
|
||||
updateUrl(nextStatus as InboxStatus, 1, pagination.pageSize);
|
||||
const nextParams = new URLSearchParams(searchParams.toString());
|
||||
nextParams.delete("app");
|
||||
if (nextStatus === "pending") {
|
||||
nextParams.delete("status");
|
||||
} else {
|
||||
nextParams.set("status", nextStatus);
|
||||
}
|
||||
nextParams.delete("page");
|
||||
if (pagination.pageSize === INBOX_DEFAULT_PAGE_SIZE) {
|
||||
nextParams.delete("pageSize");
|
||||
} else {
|
||||
nextParams.set("pageSize", pagination.pageSize.toString());
|
||||
}
|
||||
startTransition(() => {
|
||||
const target = nextParams.toString()
|
||||
? `${pathname}?${nextParams.toString()}`
|
||||
: pathname;
|
||||
router.replace(target, { scroll: false });
|
||||
});
|
||||
};
|
||||
|
||||
const handleSelectionBulkRequest = (status: InboxStatus) => {
|
||||
@@ -401,16 +536,30 @@ export function InboxPage({
|
||||
</Card>
|
||||
);
|
||||
|
||||
const renderGrid = (list: InboxItem[], readonly?: boolean) =>
|
||||
list.length === 0 ? (
|
||||
renderEmptyState(
|
||||
const renderGroupedGrid = (list: InboxItem[], readonly?: boolean) => {
|
||||
if (list.length === 0) {
|
||||
if (activeApp) {
|
||||
return renderEmptyState("Nenhuma notificação deste app");
|
||||
}
|
||||
return renderEmptyState(
|
||||
readonly
|
||||
? "Nenhuma notificação nesta aba"
|
||||
: "Nenhum pré-lançamento pendente",
|
||||
)
|
||||
) : (
|
||||
);
|
||||
}
|
||||
|
||||
const groups = groupItemsByDay(list);
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
{groups.map((group) => (
|
||||
<div key={group.label}>
|
||||
<div className="mb-3 flex items-center gap-1 text-muted-foreground">
|
||||
<RiCalendarEventLine className="size-3.5 shrink-0" />
|
||||
<p className="text-sm font-medium">{group.label}</p>
|
||||
</div>
|
||||
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-3">
|
||||
{list.map((item) => (
|
||||
{group.items.map((item) => (
|
||||
<InboxCard
|
||||
key={item.id}
|
||||
item={item}
|
||||
@@ -420,13 +569,72 @@ export function InboxPage({
|
||||
onDiscard={readonly ? undefined : handleDiscardRequest}
|
||||
onViewDetails={readonly ? undefined : handleDetailsRequest}
|
||||
onDelete={readonly ? handleDeleteRequest : undefined}
|
||||
onRestoreToPending={readonly ? handleRestoreRequest : undefined}
|
||||
onRestoreToPending={
|
||||
readonly ? handleRestoreRequest : undefined
|
||||
}
|
||||
selected={selectedIds.includes(item.id)}
|
||||
onSelectToggle={toggleSelection}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const renderAppFilter = () => {
|
||||
if (appFilterOptions.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Select value={activeApp ?? "all"} onValueChange={handleAppChange}>
|
||||
<SelectTrigger className="w-[190px]">
|
||||
<SelectValue>
|
||||
<span className="flex min-w-0 items-center gap-2">
|
||||
<Image
|
||||
src={activeApp ? getAppLogo(activeApp) : DEFAULT_INBOX_APP_LOGO}
|
||||
alt=""
|
||||
width={20}
|
||||
height={20}
|
||||
className="shrink-0 rounded-full"
|
||||
/>
|
||||
<span className="truncate">{activeApp ?? "Todos"}</span>
|
||||
</span>
|
||||
</SelectValue>
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="all">
|
||||
<span className="flex items-center gap-2">
|
||||
<Image
|
||||
src={DEFAULT_INBOX_APP_LOGO}
|
||||
alt=""
|
||||
width={20}
|
||||
height={20}
|
||||
className="shrink-0 rounded-full"
|
||||
/>
|
||||
<span>Todos</span>
|
||||
</span>
|
||||
</SelectItem>
|
||||
{appFilterOptions.map((app) => (
|
||||
<SelectItem key={app} value={app}>
|
||||
<span className="flex min-w-0 items-center gap-2">
|
||||
<Image
|
||||
src={getAppLogo(app)}
|
||||
alt=""
|
||||
width={20}
|
||||
height={20}
|
||||
className="shrink-0 rounded-full"
|
||||
/>
|
||||
<span className="truncate">{app}</span>
|
||||
</span>
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -463,9 +671,17 @@ export function InboxPage({
|
||||
</TabsList>
|
||||
|
||||
<TabsContent value="pending" className="mt-4">
|
||||
{activeStatus === "pending" && items.length > 0 && (
|
||||
<div className="mb-4 flex items-center justify-end gap-2">
|
||||
<Button variant="outline" size="sm" onClick={toggleSelectAll}>
|
||||
{activeStatus === "pending" &&
|
||||
(appFilterOptions.length > 0 || items.length > 0) && (
|
||||
<div className="mb-4 flex flex-wrap items-center gap-2">
|
||||
{renderAppFilter()}
|
||||
{items.length > 0 ? (
|
||||
<div className="ml-auto flex items-center gap-2">
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={toggleSelectAll}
|
||||
>
|
||||
{allSelected ? "Cancelar seleção" : "Selecionar página"}
|
||||
</Button>
|
||||
{selectedIds.length > 0 && (
|
||||
@@ -479,13 +695,23 @@ export function InboxPage({
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
)}
|
||||
{activeStatus === "pending" ? renderGrid(items, false) : null}
|
||||
{activeStatus === "pending" ? renderGroupedGrid(items, false) : null}
|
||||
</TabsContent>
|
||||
<TabsContent value="processed" className="mt-4">
|
||||
{activeStatus === "processed" && items.length > 0 && (
|
||||
<div className="mb-4 flex items-center justify-end gap-2">
|
||||
<Button variant="outline" size="sm" onClick={toggleSelectAll}>
|
||||
{activeStatus === "processed" &&
|
||||
(appFilterOptions.length > 0 || items.length > 0) && (
|
||||
<div className="mb-4 flex flex-wrap items-center gap-2">
|
||||
{renderAppFilter()}
|
||||
{items.length > 0 ? (
|
||||
<div className="ml-auto flex items-center gap-2">
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={toggleSelectAll}
|
||||
>
|
||||
{allSelected ? "Cancelar seleção" : "Selecionar página"}
|
||||
</Button>
|
||||
{selectedIds.length > 0 && (
|
||||
@@ -507,13 +733,23 @@ export function InboxPage({
|
||||
Limpar processados
|
||||
</Button>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
)}
|
||||
{activeStatus === "processed" ? renderGrid(items, true) : null}
|
||||
{activeStatus === "processed" ? renderGroupedGrid(items, true) : null}
|
||||
</TabsContent>
|
||||
<TabsContent value="discarded" className="mt-4">
|
||||
{activeStatus === "discarded" && items.length > 0 && (
|
||||
<div className="mb-4 flex items-center justify-end gap-2">
|
||||
<Button variant="outline" size="sm" onClick={toggleSelectAll}>
|
||||
{activeStatus === "discarded" &&
|
||||
(appFilterOptions.length > 0 || items.length > 0) && (
|
||||
<div className="mb-4 flex flex-wrap items-center gap-2">
|
||||
{renderAppFilter()}
|
||||
{items.length > 0 ? (
|
||||
<div className="ml-auto flex items-center gap-2">
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={toggleSelectAll}
|
||||
>
|
||||
{allSelected ? "Cancelar seleção" : "Selecionar página"}
|
||||
</Button>
|
||||
{selectedIds.length > 0 && (
|
||||
@@ -535,8 +771,10 @@ export function InboxPage({
|
||||
Limpar descartados
|
||||
</Button>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
)}
|
||||
{activeStatus === "discarded" ? renderGrid(items, true) : null}
|
||||
{activeStatus === "discarded" ? renderGroupedGrid(items, true) : null}
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
|
||||
|
||||
@@ -31,6 +31,10 @@ export const resolveInboxStatus = (
|
||||
: "pending";
|
||||
};
|
||||
|
||||
export const resolveInboxApp = (
|
||||
params: ResolvedInboxSearchParams,
|
||||
): string | null => getSingleParam(params, "app");
|
||||
|
||||
export const resolveInboxPagination = (
|
||||
params: ResolvedInboxSearchParams,
|
||||
): Pick<InboxPaginationState, "page" | "pageSize"> => {
|
||||
|
||||
@@ -39,18 +39,26 @@ export async function fetchInboxItemsPage(
|
||||
{
|
||||
page,
|
||||
pageSize,
|
||||
sourceApp,
|
||||
}: {
|
||||
page: number;
|
||||
pageSize: number;
|
||||
sourceApp?: string | null;
|
||||
},
|
||||
): Promise<{
|
||||
items: InboxItem[];
|
||||
pagination: InboxPaginationState;
|
||||
}> {
|
||||
const where = and(
|
||||
eq(inboxItems.userId, userId),
|
||||
eq(inboxItems.status, status),
|
||||
sourceApp ? eq(inboxItems.sourceAppName, sourceApp) : undefined,
|
||||
);
|
||||
|
||||
const [countRow] = await db
|
||||
.select({ total: count() })
|
||||
.from(inboxItems)
|
||||
.where(and(eq(inboxItems.userId, userId), eq(inboxItems.status, status)));
|
||||
.where(where);
|
||||
|
||||
const totalItems = Number(countRow?.total ?? 0);
|
||||
const totalPages = Math.max(Math.ceil(totalItems / pageSize), 1);
|
||||
@@ -60,7 +68,7 @@ export async function fetchInboxItemsPage(
|
||||
const items = await db
|
||||
.select()
|
||||
.from(inboxItems)
|
||||
.where(and(eq(inboxItems.userId, userId), eq(inboxItems.status, status)))
|
||||
.where(where)
|
||||
.orderBy(desc(inboxItems.notificationTimestamp), desc(inboxItems.createdAt))
|
||||
.limit(pageSize)
|
||||
.offset(offset);
|
||||
@@ -76,6 +84,22 @@ export async function fetchInboxItemsPage(
|
||||
};
|
||||
}
|
||||
|
||||
export async function fetchInboxSourceApps(
|
||||
userId: string,
|
||||
status: InboxStatus,
|
||||
): Promise<string[]> {
|
||||
const rows = await db
|
||||
.select({ name: inboxItems.sourceAppName })
|
||||
.from(inboxItems)
|
||||
.where(and(eq(inboxItems.userId, userId), eq(inboxItems.status, status)));
|
||||
|
||||
const seen = new Set<string>();
|
||||
for (const row of rows) {
|
||||
if (row.name) seen.add(row.name);
|
||||
}
|
||||
return [...seen].sort();
|
||||
}
|
||||
|
||||
export async function fetchInboxStatusCounts(
|
||||
userId: string,
|
||||
): Promise<InboxStatusCounts> {
|
||||
|
||||
@@ -6,7 +6,6 @@ import { normalizeDescriptionKey } from "@/features/transactions/lib/import-util
|
||||
import { getUserId } from "@/shared/lib/auth/server";
|
||||
import { db } from "@/shared/lib/db";
|
||||
|
||||
|
||||
// Retorna um map de descriptionKey → categoryId para as descrições fornecidas
|
||||
export async function fetchCategoryMappings(
|
||||
descriptions: string[],
|
||||
@@ -53,7 +52,10 @@ export async function saveCategoryMappings(
|
||||
.insert(importCategoryMappings)
|
||||
.values(toUpsert)
|
||||
.onConflictDoUpdate({
|
||||
target: [importCategoryMappings.userId, importCategoryMappings.descriptionKey],
|
||||
target: [
|
||||
importCategoryMappings.userId,
|
||||
importCategoryMappings.descriptionKey,
|
||||
],
|
||||
set: {
|
||||
categoryId: sql`excluded.category_id`,
|
||||
updatedAt: sql`excluded.updated_at`,
|
||||
|
||||
@@ -29,7 +29,11 @@ const importSchema = z.object({
|
||||
accountId: uuidSchema("FinancialAccount").nullable().optional(),
|
||||
cardId: uuidSchema("Cartão").nullable().optional(),
|
||||
paymentMethod: z.string().min(1),
|
||||
invoicePeriod: z.string().regex(/^\d{4}-\d{2}$/, "Período inválido.").nullable().optional(),
|
||||
invoicePeriod: z
|
||||
.string()
|
||||
.regex(/^\d{4}-\d{2}$/, "Período inválido.")
|
||||
.nullable()
|
||||
.optional(),
|
||||
});
|
||||
|
||||
export type ImportRow = z.infer<typeof importRowSchema>;
|
||||
@@ -51,10 +55,7 @@ export async function checkDuplicateFitIds(
|
||||
.select({ ofxFitId: transactions.ofxFitId })
|
||||
.from(transactions)
|
||||
.where(
|
||||
and(
|
||||
eq(transactions.userId, userId),
|
||||
inArray(transactions.ofxFitId, ids),
|
||||
),
|
||||
and(eq(transactions.userId, userId), inArray(transactions.ofxFitId, ids)),
|
||||
);
|
||||
|
||||
return rows.map((r) => r.ofxFitId).filter((id): id is string => id !== null);
|
||||
@@ -67,10 +68,14 @@ export async function importTransactionsAction(
|
||||
const parsed = importSchema.safeParse(input);
|
||||
|
||||
if (!parsed.success) {
|
||||
return { success: false, error: parsed.error.issues[0]?.message ?? "Dados inválidos." };
|
||||
return {
|
||||
success: false,
|
||||
error: parsed.error.issues[0]?.message ?? "Dados inválidos.",
|
||||
};
|
||||
}
|
||||
|
||||
const { rows, payerId, accountId, cardId, paymentMethod, invoicePeriod } = parsed.data;
|
||||
const { rows, payerId, accountId, cardId, paymentMethod, invoicePeriod } =
|
||||
parsed.data;
|
||||
|
||||
// Valida ownership
|
||||
const [payerOk, accountOk, cardOk] = await Promise.all([
|
||||
@@ -94,14 +99,19 @@ export async function importTransactionsAction(
|
||||
|
||||
const records = rows.map((row) => {
|
||||
const purchaseDate = parseLocalDateString(row.date);
|
||||
const period = invoicePeriod ?? `${purchaseDate.getFullYear()}-${String(purchaseDate.getMonth() + 1).padStart(2, "0")}`;
|
||||
const period =
|
||||
invoicePeriod ??
|
||||
`${purchaseDate.getFullYear()}-${String(purchaseDate.getMonth() + 1).padStart(2, "0")}`;
|
||||
|
||||
return {
|
||||
name: row.description,
|
||||
transactionType: row.transactionType === "income" ? "Receita" : "Despesa",
|
||||
condition: "À vista" as const,
|
||||
paymentMethod,
|
||||
amount: (row.transactionType === "expense" ? -row.amount : row.amount).toFixed(2),
|
||||
amount: (row.transactionType === "expense"
|
||||
? -row.amount
|
||||
: row.amount
|
||||
).toFixed(2),
|
||||
purchaseDate,
|
||||
period,
|
||||
isSettled,
|
||||
@@ -143,10 +153,7 @@ export async function deleteTransactionByFitId(
|
||||
await db
|
||||
.delete(transactions)
|
||||
.where(
|
||||
and(
|
||||
eq(transactions.userId, userId),
|
||||
eq(transactions.ofxFitId, fitId),
|
||||
),
|
||||
and(eq(transactions.userId, userId), eq(transactions.ofxFitId, fitId)),
|
||||
);
|
||||
|
||||
await revalidateForEntity("transactions", userId);
|
||||
|
||||
@@ -33,7 +33,8 @@ export function decodeAccountCard(value: string): {
|
||||
id: string;
|
||||
} | null {
|
||||
if (value.startsWith("card:")) return { type: "card", id: value.slice(5) };
|
||||
if (value.startsWith("account:")) return { type: "account", id: value.slice(8) };
|
||||
if (value.startsWith("account:"))
|
||||
return { type: "account", id: value.slice(8) };
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -65,7 +66,9 @@ export function GlobalFields({
|
||||
onBulkCategoryChange,
|
||||
}: GlobalFieldsProps) {
|
||||
const isCard = accountCardValue?.startsWith("card:") ?? false;
|
||||
const expenseCategories = categoryOptions.filter((o) => o.group === "despesa");
|
||||
const expenseCategories = categoryOptions.filter(
|
||||
(o) => o.group === "despesa",
|
||||
);
|
||||
const incomeCategories = categoryOptions.filter((o) => o.group === "receita");
|
||||
|
||||
return (
|
||||
@@ -131,7 +134,10 @@ export function GlobalFields({
|
||||
<SelectContent>
|
||||
{payerOptions.map((opt) => (
|
||||
<SelectItem key={opt.value} value={opt.value}>
|
||||
<PayerSelectContent label={opt.label} avatarUrl={opt.avatarUrl} />
|
||||
<PayerSelectContent
|
||||
label={opt.label}
|
||||
avatarUrl={opt.avatarUrl}
|
||||
/>
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
@@ -150,7 +156,10 @@ export function GlobalFields({
|
||||
<SelectLabel>Despesa</SelectLabel>
|
||||
{expenseCategories.map((opt) => (
|
||||
<SelectItem key={opt.value} value={opt.value}>
|
||||
<CategorySelectContent label={opt.label} icon={opt.icon} />
|
||||
<CategorySelectContent
|
||||
label={opt.label}
|
||||
icon={opt.icon}
|
||||
/>
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectGroup>
|
||||
@@ -163,7 +172,10 @@ export function GlobalFields({
|
||||
<SelectLabel>Receita</SelectLabel>
|
||||
{incomeCategories.map((opt) => (
|
||||
<SelectItem key={opt.value} value={opt.value}>
|
||||
<CategorySelectContent label={opt.label} icon={opt.icon} />
|
||||
<CategorySelectContent
|
||||
label={opt.label}
|
||||
icon={opt.icon}
|
||||
/>
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectGroup>
|
||||
|
||||
@@ -1,13 +1,18 @@
|
||||
"use client";
|
||||
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useCallback, useEffect, useMemo, useState, useTransition } from "react";
|
||||
import {
|
||||
useCallback,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useState,
|
||||
useTransition,
|
||||
} from "react";
|
||||
import { toast } from "sonner";
|
||||
import {
|
||||
fetchCategoryMappings,
|
||||
saveCategoryMappings,
|
||||
} from "@/features/transactions/actions/category-memory-action";
|
||||
import { normalizeDescriptionKey } from "@/features/transactions/lib/import-utils";
|
||||
import {
|
||||
checkDuplicateFitIds,
|
||||
deleteTransactionByFitId,
|
||||
@@ -27,6 +32,7 @@ import {
|
||||
} from "@/features/transactions/components/import/review-table";
|
||||
import { UploadZone } from "@/features/transactions/components/import/upload-zone";
|
||||
import type { SelectOption } from "@/features/transactions/components/types";
|
||||
import { normalizeDescriptionKey } from "@/features/transactions/lib/import-utils";
|
||||
import { Button } from "@/shared/components/ui/button";
|
||||
import {
|
||||
Card,
|
||||
@@ -82,7 +88,8 @@ export function ImportPage({
|
||||
...t,
|
||||
isDuplicate: t.externalId ? duplicates.has(t.externalId) : false,
|
||||
selected: t.externalId ? !duplicates.has(t.externalId) : true,
|
||||
categoryId: categoryMappings[normalizeDescriptionKey(t.description)] ?? null,
|
||||
categoryId:
|
||||
categoryMappings[normalizeDescriptionKey(t.description)] ?? null,
|
||||
})),
|
||||
);
|
||||
} finally {
|
||||
@@ -167,7 +174,9 @@ export function ImportPage({
|
||||
const handleImport = () => {
|
||||
if (!statement || !canImport) return;
|
||||
|
||||
const decoded = decodeAccountCard(accountCardValue!);
|
||||
const decoded = accountCardValue
|
||||
? decodeAccountCard(accountCardValue)
|
||||
: null;
|
||||
const cardId = decoded?.type === "card" ? decoded.id : null;
|
||||
const accountId = decoded?.type === "account" ? decoded.id : null;
|
||||
const paymentMethod =
|
||||
@@ -197,7 +206,10 @@ export function ImportPage({
|
||||
|
||||
// Salva mapeamentos description → category (fire-and-forget)
|
||||
saveCategoryMappings(
|
||||
selectedRows.map((r) => ({ description: r.description, categoryId: r.categoryId })),
|
||||
selectedRows.map((r) => ({
|
||||
description: r.description,
|
||||
categoryId: r.categoryId,
|
||||
})),
|
||||
);
|
||||
|
||||
const { importBatchId } = result;
|
||||
@@ -236,7 +248,8 @@ export function ImportPage({
|
||||
<div>
|
||||
<CardTitle>Importar extrato</CardTitle>
|
||||
<CardDescription>
|
||||
Importe transações a partir de um arquivo .ofx ou planilha .xlsx exportado pelo seu banco.
|
||||
Importe transações a partir de um arquivo .ofx ou planilha .xlsx
|
||||
exportado pelo seu banco.
|
||||
</CardDescription>
|
||||
</div>
|
||||
<ImportSteps current={currentStep} />
|
||||
|
||||
@@ -34,7 +34,9 @@ export function ImportSteps({ current }: ImportStepsProps) {
|
||||
isCompleted &&
|
||||
"border-primary bg-primary text-primary-foreground",
|
||||
isActive && "border-primary text-primary",
|
||||
!isCompleted && !isActive && "border-muted-foreground/30 text-muted-foreground",
|
||||
!isCompleted &&
|
||||
!isActive &&
|
||||
"border-muted-foreground/30 text-muted-foreground",
|
||||
)}
|
||||
>
|
||||
{isCompleted ? (
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { useRef } from "react";
|
||||
import { useVirtualizer } from "@tanstack/react-virtual";
|
||||
import { useRef } from "react";
|
||||
import { CategorySelectContent } from "@/features/transactions/components/select-items";
|
||||
import type { SelectOption } from "@/features/transactions/components/types";
|
||||
import MoneyValues from "@/shared/components/money-values";
|
||||
@@ -91,9 +91,7 @@ export function ReviewTable({
|
||||
onCheckedChange={(v) => onToggleAll(!!v)}
|
||||
aria-label="Selecionar todas"
|
||||
data-state={
|
||||
!allSelected && someSelected
|
||||
? "indeterminate"
|
||||
: undefined
|
||||
!allSelected && someSelected ? "indeterminate" : undefined
|
||||
}
|
||||
/>
|
||||
</TableHead>
|
||||
@@ -114,7 +112,10 @@ export function ReviewTable({
|
||||
</TableRow>
|
||||
)}
|
||||
{virtualRows.map((virtualRow) => {
|
||||
const row = rows[virtualRow.index]!;
|
||||
const row = rows[virtualRow.index];
|
||||
if (!row) {
|
||||
return null;
|
||||
}
|
||||
const index = virtualRow.index;
|
||||
return (
|
||||
<TableRow
|
||||
@@ -199,9 +200,7 @@ export function ReviewTable({
|
||||
<TableCell>
|
||||
<TransactionTypeBadge
|
||||
kind={
|
||||
row.transactionType === "income"
|
||||
? "Receita"
|
||||
: "Despesa"
|
||||
row.transactionType === "income" ? "Receita" : "Despesa"
|
||||
}
|
||||
/>
|
||||
</TableCell>
|
||||
|
||||
@@ -37,7 +37,9 @@ export function UploadZone({ onParsed }: UploadZoneProps) {
|
||||
}
|
||||
onParsed(statement);
|
||||
} catch {
|
||||
setError("Não foi possível ler o arquivo. Verifique se é um OFX válido.");
|
||||
setError(
|
||||
"Não foi possível ler o arquivo. Verifique se é um OFX válido.",
|
||||
);
|
||||
}
|
||||
};
|
||||
reader.readAsText(file, "windows-1252");
|
||||
@@ -119,11 +121,7 @@ export function UploadZone({ onParsed }: UploadZoneProps) {
|
||||
/>
|
||||
|
||||
<div className="flex items-center justify-between">
|
||||
{error ? (
|
||||
<p className="text-destructive text-sm">{error}</p>
|
||||
) : (
|
||||
<span />
|
||||
)}
|
||||
{error ? <p className="text-destructive text-sm">{error}</p> : <span />}
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleDownloadTemplate}
|
||||
|
||||
@@ -13,9 +13,9 @@ import {
|
||||
RiCheckLine,
|
||||
RiDeleteBin5Line,
|
||||
RiFileCopyLine,
|
||||
RiFileExcel2Line,
|
||||
RiFileList2Line,
|
||||
RiFlashlightFill,
|
||||
RiFileExcel2Line,
|
||||
RiGroupLine,
|
||||
RiHistoryLine,
|
||||
RiMoreFill,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { ImportStatement, ImportedTransaction } from "./types";
|
||||
import type { ImportedTransaction, ImportStatement } from "./types";
|
||||
|
||||
// Extrai o valor de uma tag leaf do OFX SGML: <TAG>valor
|
||||
function getField(block: string, tag: string): string | null {
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import * as XLSX from "xlsx";
|
||||
import type { ImportStatement, ImportedTransaction } from "@/shared/lib/import/types";
|
||||
import type {
|
||||
ImportedTransaction,
|
||||
ImportStatement,
|
||||
} from "@/shared/lib/import/types";
|
||||
|
||||
function parseDateValue(value: unknown): string | null {
|
||||
if (value == null || value === "") return null;
|
||||
|
||||
Reference in New Issue
Block a user