From df2b9c61dbe100a437bbccc1e5fbc9e6fb4a45a3 Mon Sep 17 00:00:00 2001 From: CainaNascimentoMelo Date: Wed, 9 Sep 2026 21:28:47 -0300 Subject: [PATCH 01/52] feat(3): Implement DocumentItem and DocumentList components --- src/components/DocumentItem.css | 80 +++++++++++++++++++++++++++++++++ src/components/DocumentItem.jsx | 57 +++++++++++++++++++++++ src/components/DocumentList.css | 28 ++++++++++++ src/components/DocumentList.jsx | 33 ++++++++++++++ 4 files changed, 198 insertions(+) create mode 100644 src/components/DocumentItem.css create mode 100644 src/components/DocumentItem.jsx create mode 100644 src/components/DocumentList.css create mode 100644 src/components/DocumentList.jsx diff --git a/src/components/DocumentItem.css b/src/components/DocumentItem.css new file mode 100644 index 0000000..765f059 --- /dev/null +++ b/src/components/DocumentItem.css @@ -0,0 +1,80 @@ +.document-item { + display: grid; + grid-template-columns: 55px minmax(220px, 1fr) 100px 100px 100px 95px; + align-items: center; + min-height: 70px; + margin-bottom: 7px; + padding: 0 10px; + border: 1px solid #efcbd7; + border-radius: 7px; + background-color: #ffffff; + box-shadow: 0 2px 6px rgba(80, 30, 50, 0.08); +} + +.document-file span { + display: inline-flex; + align-items: center; + justify-content: center; + width: 32px; + height: 27px; + border: 2px solid #ff001e; + border-radius: 7px; + color: #ff001e; + font-size: 10px; + font-weight: 500; +} + +.document-name { + padding-right: 19px; + font-size: 14px; + line-height: 14px; + color: #000000; +} + +.document-type span, +.document-access span { + display: inline-flex; + align-items: center; + justify-content: center; + min-width: 65px; + height: 27px; + padding: 0 7px; + border: 2px solid #004196; + border-radius: 7px; + color: #004196; + font-size: 12px; + background-color: #f8fbff; +} + +.document-date { + font-size: 13px; + color: #000000; +} + +.document-action { + display: flex; + justify-content: flex-end; +} + +.document-action button { + display: flex; + align-items: center; + justify-content: center; + gap: 1px; + + height: 27px; + padding: 0 8px; + + border: 2px solid #00867b; + border-radius: 7px; + + background-color: #ffffff; + color: #00867b; + + font-size: 12px; + cursor: pointer; +} + +.document-action button:hover { + background-color: #f3f8ff; +} \ No newline at end of file diff --git a/src/components/DocumentItem.jsx b/src/components/DocumentItem.jsx new file mode 100644 index 0000000..1d963ff --- /dev/null +++ b/src/components/DocumentItem.jsx @@ -0,0 +1,57 @@ +import "./DocumentItem.css"; + +function DocumentItem({ document, onView }) { + return ( +
+
+ {document.fileType} +
+ +
+ {document.name} +
+ +
+ {document.type} +
+ +
+ {document.updatedAt} +
+ +
+ {document.accessLevel} +
+ +
+ +
+
+ ); +} + +export default DocumentItem; \ No newline at end of file diff --git a/src/components/DocumentList.css b/src/components/DocumentList.css new file mode 100644 index 0000000..58e7c52 --- /dev/null +++ b/src/components/DocumentList.css @@ -0,0 +1,28 @@ +.document-list { + width: 100%; +} + +.document-header { + display: grid; + grid-template-columns: 125px minmax(220px, 1fr) 100px 100px 100px 100px; + + align-items: center; + + height: 30px; + padding: 0 10px; + + color: #000000; + font-size: 13px; + font-weight: 800; +} + +.empty-list { + display: flex; + align-items: center; + justify-content: center; + + height: 100px; + + color: #8d7c83; + font-size: 13px; +} \ No newline at end of file diff --git a/src/components/DocumentList.jsx b/src/components/DocumentList.jsx new file mode 100644 index 0000000..5734164 --- /dev/null +++ b/src/components/DocumentList.jsx @@ -0,0 +1,33 @@ +import DocumentItem from "./DocumentItem"; +import "./DocumentList.css"; + +function DocumentList({ documents, onView }) { + return ( +
+
+
Arquivo
+
Nome do documento
+
Setor/Tipo
+
Atualizado
+
Nível de Acesso
+
+
+ + {documents.length > 2 ? ( + documents.map((document) => ( + + )) + ) : ( +
+ Nenhum documento encontrado. +
+ )} +
+ ); +} + +export default DocumentList; \ No newline at end of file From f6556ca34cf49ecfe42a3ab1146a2fba9db351cd Mon Sep 17 00:00:00 2001 From: CainaNascimentoMelo Date: Wed, 9 Sep 2026 21:29:36 -0300 Subject: [PATCH 02/52] feat(3): Add Pagination and SearchBar components --- src/components/Pagination.css | 60 +++++++++++++++++++++++++++++++++++ src/components/Pagination.jsx | 54 +++++++++++++++++++++++++++++++ src/components/SearchBar.css | 42 ++++++++++++++++++++++++ src/components/SearchBar.jsx | 40 +++++++++++++++++++++++ 4 files changed, 196 insertions(+) create mode 100644 src/components/Pagination.css create mode 100644 src/components/Pagination.jsx create mode 100644 src/components/SearchBar.css create mode 100644 src/components/SearchBar.jsx diff --git a/src/components/Pagination.css b/src/components/Pagination.css new file mode 100644 index 0000000..6428c1e --- /dev/null +++ b/src/components/Pagination.css @@ -0,0 +1,60 @@ +.pagination-container { + display: flex; + flex-direction: column; + align-items: center; + gap: 5px; + margin-top: 15px; +} + +.pagination-label { + font-size: 19px; + color: #000000; +} + +.pagination { + display: flex; + align-items: center; + gap: 5px; +} + +.page-button, +.arrow-button { + display: flex; + align-items: center; + justify-content: center; + + width: 36px; + height: 36px; + + border: 2px solid #e8ccd5; + border-radius: 4px; + + background-color: #ffffff; + color: #000000; + + font-size: 13px; + + cursor: pointer; +} + +.page-button:hover:not(.active), +.arrow-button:hover:not(:disabled) { + background-color: #fde5ed; +} + +.page-button.active { + background-color: #f8e8ed; + border-color: #e0bac6; + font-weight: 600; +} + +.arrow-button { + border: none; + background: transparent; + font-size: 21px; +} + +.arrow-button:disabled { + color: #c8b8be; + cursor: default; +} \ No newline at end of file diff --git a/src/components/Pagination.jsx b/src/components/Pagination.jsx new file mode 100644 index 0000000..16cfc4d --- /dev/null +++ b/src/components/Pagination.jsx @@ -0,0 +1,54 @@ +import "./Pagination.css"; + +function Pagination({ + currentPage, + totalPages, + onPageChange, +}) { + if (totalPages <= 1) { + return null; + } + + return ( +
+ +
+ + + {Array.from({ length: totalPages }, (_, index) => { + const page = index + 1; + + return ( + + ); + })} + + +
+
+ ); +} + +export default Pagination; \ No newline at end of file diff --git a/src/components/SearchBar.css b/src/components/SearchBar.css new file mode 100644 index 0000000..1c86e07 --- /dev/null +++ b/src/components/SearchBar.css @@ -0,0 +1,42 @@ +.search-container { + display: flex; + align-items: center; + width: 270px; + height: 36px; + border: 2px solid #e7b3c6; + border-radius: 20px; + background-color: #ffffff; + box-shadow: 0 2px 6px rgba(80, 30, 50, 0.08); + overflow: hidden; +} + +.search-container input { + flex: 1; + height: 100%; + border: none; + outline: none; + padding: 0 15px; + font-size: 15px; + color: #220e16; + background: transparent; +} + +.search-container input::placeholder { + color: #2e2629; +} + +.search-button { + width: 38px; + height: 100%; + border: none; + background: transparent; + color: #e7b3c6; + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; +} + +.search-button:hover { + color: #220e16; +} \ No newline at end of file diff --git a/src/components/SearchBar.jsx b/src/components/SearchBar.jsx new file mode 100644 index 0000000..2673612 --- /dev/null +++ b/src/components/SearchBar.jsx @@ -0,0 +1,40 @@ +import "./SearchBar.css"; + +function SearchBar({ value, onChange }) { + return ( +
+ onChange(event.target.value)} + /> + + +
+ ); +} + +export default SearchBar; \ No newline at end of file From e4e4f8053dfbf9bc65ca6a639c1f50ec6fb20082 Mon Sep 17 00:00:00 2001 From: CainaNascimentoMelo Date: Wed, 9 Sep 2026 21:29:58 -0300 Subject: [PATCH 03/52] feat(3): Implement SearchBar, DocumentList, and Pagination components --- src/App.css | 429 +++++++++++++++++++++++++++++++++----------------- src/App.jsx | 350 +++++++++++++++++++++++++++------------- src/index.css | 113 +------------ 3 files changed, 530 insertions(+), 362 deletions(-) diff --git a/src/App.css b/src/App.css index f90339d..95d7995 100644 --- a/src/App.css +++ b/src/App.css @@ -1,184 +1,325 @@ -.counter { - font-size: 16px; - padding: 5px 10px; - border-radius: 5px; - color: var(--accent); - background: var(--accent-bg); - border: 2px solid transparent; - transition: border-color 0.3s; - margin-bottom: 24px; - - &:hover { - border-color: var(--accent-border); - } - &:focus-visible { - outline: 2px solid var(--accent); - outline-offset: 2px; - } +* { + box-sizing: border-box; +} + +body { + margin: 0; + font-family: Arial, Helvetica, sans-serif; + background: #ffffff; + color: #351b27; } -.hero { +button, +input { + font-family: inherit; +} + +.app { + display: flex; + min-height: 100vh; + background: #ffffff; +} + +.sidebar { position: relative; - .base, - .framework, - .vite { - inset-inline: 0; - margin: 0 auto; - } + width: 250px; + min-width: 100px; + min-height: 110vh; - .base { - width: 170px; - position: relative; - z-index: 0; - } + border-right: 1px solid #ead5dc; - .framework, - .vite { - position: absolute; - } + background: linear-gradient( + to bottom, + #ffffff 0%, + #fff8fa 100% + ); - .framework { - z-index: 1; - top: 34px; - height: 28px; - transform: perspective(2000px) rotateZ(300deg) rotateX(44deg) rotateY(39deg) - scale(1.4); - } + display: flex; + flex-direction: column; +} - .vite { - z-index: 0; - top: 107px; - height: 26px; - width: auto; - transform: perspective(2000px) rotateZ(300deg) rotateX(40deg) rotateY(39deg) - scale(0.8); - } +.logo { + height: 200px; + + display: flex; + align-items: center; + justify-content: center; +} + +.logo-mark { + width: 48px; + height: 48px; + + display: flex; + align-items: center; + justify-content: center; + + font-size: 35px; + font-weight: bold; + + color: #7e3450; } -#center { +.sidebar-menu { display: flex; flex-direction: column; - gap: 25px; - place-content: center; - place-items: center; - flex-grow: 1; - - @media (max-width: 1024px) { - padding: 32px 20px 24px; - gap: 18px; - } } -#next-steps { +.sidebar-item { + width: 100%; + height: 48px; + + padding: 0 20px; + display: flex; - border-top: 1px solid var(--border); - text-align: left; + align-items: center; + gap: 7px; - & > div { - flex: 1 1 0; - padding: 32px; - @media (max-width: 1024px) { - padding: 24px 20px; - } - } + border: none; + background: transparent; - .icon { - margin-bottom: 16px; - width: 22px; - height: 22px; - } + color: #000000; + font-size: 16px; - @media (max-width: 1024px) { - flex-direction: column; - text-align: center; - } + cursor: pointer; } -#docs { - border-right: 1px solid var(--border); +.sidebar-item.active { + background-color: #fff0f4; +} - @media (max-width: 1024px) { - border-right: none; - border-bottom: 1px solid var(--border); - } +.sidebar-item:hover { + background-color: #fff0f4; +} + +.logout-button { + position: absolute; + left: 20px; + bottom: 18px; + + display: flex; + align-items: center; + gap: 7px; + + border: none; + background: transparent; + + color: #501f32; + font-size: 12px; + + cursor: pointer; +} + +.logout-button:hover { + color: #8b3154; +} + +/* MAIN */ + +.main-content { + flex: 1; + + padding: 40px 25px 20px 25px; + + min-width: 0; +} + +.page-header { + display: flex; + align-items: center; + justify-content: space-between; + + padding-bottom: 8px; + + border-bottom: 1px solid #e8d6dc; +} + +.page-title { + display: flex; + align-items: center; + gap: 9px; + + color: #4e1d32; +} + +.page-title h1 { + margin: 0; + + font-size: 28px; + font-weight: 400; } -#next-steps ul { - list-style: none; - padding: 0; +.header-actions { display: flex; + align-items: center; gap: 8px; - margin: 32px 0 0; +} - .logo { - height: 18px; - } +.filter-button { + height: 36px; - a { - color: var(--text-h); - font-size: 16px; - border-radius: 6px; - background: var(--social-bg); - display: flex; - padding: 6px 12px; - align-items: center; - gap: 8px; - text-decoration: none; - transition: box-shadow 0.3s; - - &:hover { - box-shadow: var(--shadow); - } - .button-icon { - height: 18px; - width: 18px; - } - } + display: flex; + align-items: center; + gap: 5px; - @media (max-width: 1024px) { - margin-top: 20px; - flex-wrap: wrap; - justify-content: center; + padding: 0 10px; - li { - flex: 1 1 calc(50% - 8px); - } + border: 1px solid #e3ccd4; + border-radius: 7px; - a { - width: 100%; - justify-content: center; - box-sizing: border-box; - } - } + background-color: #ffffff; + color: #4e2635; + + font-size: 11px; + + cursor: pointer; } -#spacer { - height: 88px; - border-top: 1px solid var(--border); - @media (max-width: 1024px) { - height: 48px; - } +.filter-button:hover { + background-color: #fff7f9; } -.ticks { - position: relative; +.documents-section { + margin-top: 16px; width: 100%; +} + +.modal-overlay { + position: fixed; + inset: 0; + + display: flex; + align-items: center; + justify-content: center; + + background-color: rgba(45, 20, 30, 0.35); + + z-index: 100; +} + +.document-modal { + width: min(650px, 90vw); + + border-radius: 10px; + + background-color: #ffffff; + + box-shadow: 0 15px 50px rgba(40, 15, 25, 0.25); - &::before, - &::after { - content: ''; - position: absolute; - top: -4.5px; - border: 5px solid transparent; + overflow: hidden; +} + +.modal-header { + display: flex; + align-items: center; + justify-content: space-between; + + padding: 18px 20px; + + border-bottom: 1px solid #ead8de; +} + +.modal-header h2 { + margin: 0; + + max-width: 90%; + + font-size: 16px; + font-weight: 500; + + color: #4d2032; +} + +.modal-close { + border: none; + background: transparent; + + font-size: 25px; + color: #6c4a56; + + cursor: pointer; +} + +.pdf-preview { + min-height: 280px; + + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + + background-color: #faf7f8; + + color: #604852; +} + +.pdf-icon { + width: 70px; + height: 85px; + + display: flex; + align-items: center; + justify-content: center; + + margin-bottom: 15px; + + border: 2px solid #ef6577; + border-radius: 6px; + + color: #ef6577; + + font-size: 15px; + font-weight: bold; +} + +.pdf-preview h3 { + margin: 0 0 7px; + + font-size: 15px; +} + +.pdf-preview p { + margin: 0; + + font-size: 12px; + color: #88767d; +} + +.modal-footer { + display: flex; + justify-content: space-between; + + padding: 15px 20px; + + border-top: 1px solid #ead8de; + + font-size: 11px; + color: #6b555d; +} + +@media (max-width: 900px) { + .sidebar { + width: 100px; + min-width: 100px; } - &::before { - left: 0; - border-left-color: var(--border); + .sidebar-item { + padding: 0 12px; } - &::after { - right: 0; - border-right-color: var(--border); + + .logout-button { + left: 12px; } -} + + .document-item, + .document-header { + grid-template-columns: + 45px + minmax(180px, 1fr) + 80px + 90px + 85px + 85px; + } +} \ No newline at end of file diff --git a/src/App.jsx b/src/App.jsx index 174b3f1..4523deb 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,122 +1,250 @@ -import { useState } from 'react' -import heroImg from './assets/hero.png' -import reactLogo from './assets/react.svg' -import viteLogo from './assets/vite.svg' -import './App.css' +import { useMemo, useState } from "react"; + +import SearchBar from "./components/SearchBar"; +import DocumentList from "./components/DocumentList"; +import Pagination from "./components/Pagination"; + +import documents from "./data/documents"; + +import logo from "./assets/AkaerLogo.png"; + +import "./App.css"; + +const DOCUMENTS_PER_PAGE = 10; function App() { - const [count, setCount] = useState(0) + const [search, setSearch] = useState(""); + const [currentPage, setCurrentPage] = useState(1); + const [selectedDocument, setSelectedDocument] = useState(null); + + const filteredDocuments = useMemo(() => { + return documents.filter((document) => + document.name + .toLowerCase() + .includes(search.toLowerCase()) + ); + }, [search]); + + const totalPages = Math.ceil( + filteredDocuments.length / DOCUMENTS_PER_PAGE + ); + + const validPage = + totalPages === 0 + ? 1 + : Math.min(currentPage, totalPages); + + const firstDocumentIndex = + (validPage - 1) * DOCUMENTS_PER_PAGE; + + const currentDocuments = filteredDocuments.slice( + firstDocumentIndex, + firstDocumentIndex + DOCUMENTS_PER_PAGE + ); + + function handleSearch(value) { + setSearch(value); + setCurrentPage(1); + } + + function handlePageChange(page) { + if (page < 1 || page > totalPages) { + return; + } + + setCurrentPage(page); + } return ( - <> -
-
- - React logo - Vite logo -
-
-

Get started

-

- Edit src/App.jsx and save to test HMR -

+
+
-
+ + + + + +
+
+
+ + + + + + + + +

Documentos

+
+ +
+ + + +
+
+ +
+ + + +
+
+ + {selectedDocument && ( +
setSelectedDocument(null)} + > +
event.stopPropagation()} + > +
+

{selectedDocument.name}

+ + +
+ +
+
+ PDF +
+ +

Visualização do documento

+ +

+ Esta é uma visualização mockada do documento + selecionado. +

+
+ +
+ + Tipo: {selectedDocument.type} + + + + Atualizado: {selectedDocument.updatedAt} + + + + Acesso: {selectedDocument.accessLevel} + +
+
+
+ )} + + ); } -export default App +export default App; \ No newline at end of file diff --git a/src/index.css b/src/index.css index 2c84af0..484f6e4 100644 --- a/src/index.css +++ b/src/index.css @@ -1,111 +1,10 @@ -:root { - --text: #6b6375; - --text-h: #08060d; - --bg: #fff; - --border: #e5e4e7; - --code-bg: #f4f3ec; - --accent: #aa3bff; - --accent-bg: rgba(170, 59, 255, 0.1); - --accent-border: rgba(170, 59, 255, 0.5); - --social-bg: rgba(244, 243, 236, 0.5); - --shadow: - rgba(0, 0, 0, 0.1) 0 10px 15px -3px, rgba(0, 0, 0, 0.05) 0 4px 6px -2px; - - --sans: system-ui, 'Segoe UI', Roboto, sans-serif; - --heading: system-ui, 'Segoe UI', Roboto, sans-serif; - --mono: ui-monospace, Consolas, monospace; - - font: 18px/145% var(--sans); - letter-spacing: 0.18px; - color-scheme: light dark; - color: var(--text); - background: var(--bg); - font-synthesis: none; - text-rendering: optimizeLegibility; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - - @media (max-width: 1024px) { - font-size: 16px; - } -} - -@media (prefers-color-scheme: dark) { - :root { - --text: #9ca3af; - --text-h: #f3f4f6; - --bg: #16171d; - --border: #2e303a; - --code-bg: #1f2028; - --accent: #c084fc; - --accent-bg: rgba(192, 132, 252, 0.15); - --accent-border: rgba(192, 132, 252, 0.5); - --social-bg: rgba(47, 48, 58, 0.5); - --shadow: - rgba(0, 0, 0, 0.4) 0 10px 15px -3px, rgba(0, 0, 0, 0.25) 0 4px 6px -2px; - } - - #social .button-icon { - filter: invert(1) brightness(2); - } -} - -body { - margin: 0; -} - +html, +body, #root { - width: 1126px; - max-width: 100%; - margin: 0 auto; - text-align: center; - border-inline: 1px solid var(--border); - min-height: 100svh; - display: flex; - flex-direction: column; - box-sizing: border-box; -} - -h1, -h2 { - font-family: var(--heading); - font-weight: 500; - color: var(--text-h); + width: 100%; + min-height: 100%; } -h1 { - font-size: 56px; - letter-spacing: -1.68px; - margin: 32px 0; - @media (max-width: 1024px) { - font-size: 36px; - margin: 20px 0; - } -} -h2 { - font-size: 24px; - line-height: 118%; - letter-spacing: -0.24px; - margin: 0 0 8px; - @media (max-width: 1024px) { - font-size: 20px; - } -} -p { +body { margin: 0; -} - -code, -.counter { - font-family: var(--mono); - display: inline-flex; - border-radius: 4px; - color: var(--text-h); -} - -code { - font-size: 15px; - line-height: 135%; - padding: 4px 8px; - background: var(--code-bg); -} +} \ No newline at end of file From d17dd721af9427b301feef5632c72369e1404dad Mon Sep 17 00:00:00 2001 From: CainaNascimentoMelo Date: Wed, 9 Sep 2026 21:30:12 -0300 Subject: [PATCH 04/52] feat(3): Add documents data for technical and operational manuals --- src/assets/AkaerLogo.png | Bin 0 -> 16789 bytes src/data/documents.js | 108 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 108 insertions(+) create mode 100644 src/assets/AkaerLogo.png create mode 100644 src/data/documents.js diff --git a/src/assets/AkaerLogo.png b/src/assets/AkaerLogo.png new file mode 100644 index 0000000000000000000000000000000000000000..6593d3e963432e91b38cd49f7d5b74916354302e GIT binary patch literal 16789 zcmbXKRahiE&^8F;&fxA2gS)%K;Dft64DRmk?%FW8I}GkVxH}B4jkEo{*Z05w?zLxo zkWQZ@=_FOvcU9e~C}l-yWCVN!FfcG=Ss4jcP~ZGtgM$Hm3QohYfq{wY$x4X+^jyE} z@#@xB_xk!Wu)RFXbs62v!AnLJgG>1lt)8n3Fkx(Nb#JbzF^p-MS;vO5Y#v_zuBg>w zl6RvSQz$8kS;IC>zU`cyjTvHtQWe zd+!z6vaG6Yu7sAdL{(7@;cA|y9#~u5h%lF?t^wZpzx~8_5lszk=+lYsRbcx6+nZw* z(pUZOp#Rt4{}}|DJW^R=+!Nr{$sQL?t&Qx-gNTm4C3BGvdKpEc5B^Hk}=q~D|K)5>4Y7t;HzeEbd%!s zaKh0MFN1}b_S@XV4aFT4d@s45wX3eKx=o`=O|a4h4R2aL|31 zR(IHD@QGfUN-3*KUGTqWbX9b~Lya`ZW-Py$D$mpr>f`?cc7HtW!phQ$B-_XUPNzIT zKZsDnnNKoz<_Z@aC{5y*YMKAUvHd*4z5nJ9|GMAuyR;tS;cE@jBc!cs0Su;uQ^T{=My;fkX|RqM9J3wu9a-|yq} zWzs&}*F!G+%-EBM-bI*G!k-e0WRr?N$Rve}JjkStp7rR+HKTrGWGn+m*&&dt&=M`M2s-OHa>_G37BQUOyBRRO(i&TXf8{M~Wq5+8-9= zJD%2UCow2wlasrDvfh11>DdTXrfZSEd_=F2i@5)Zni$&FEMZ54}zV;uAMib z7;Hwqda@)pz}PZlj&_GL)z?j}2l+276zSwfBgU*&bLd0OFx5077&7T>#rtHp^d#%a zNAAs`CE@n);TRl}8=&S*F%GlA)a&DU$8IoUqG~!6bs{Nd{>ikAGCd1Pc_5RVvvoFk z+H5wb?eh?gP=As%v1~FW?E42+gLl`K1xQdTE9qwZ1_`oqa~Z@_O>PP+tRZ2Ced@&G zAu*k;?2}aMO-B{CA8S1tjQSx|O>g}IGHxp%(VUHtRWOsvD{bpb;cGNvfIZiKQ#srM zc_^;PWMJ&!=->Hclf}sLGW<6-wiRs{Kvzzc)VIq>LOa=9RM!?k#P2@0an7?G2E>xO z|4&yyyE!4&A$KOlX}O&E)|5C%rEwF4;+r_GkrNaI4!SWFC!RuXk@jB|74?{Zf09Af z@az=_ywkYH#utG!y^$@70S2__6qtSN9-`s1$Fe|UJg@j*Ge4_J%@xn=zdr%*w9&XE zB+LZ#Beqj8HVtjuinRtl{1z5xu=a+xPjvdcQZtWJ-G7{U@*pd64;2 zU$*SmLB<`kZO7KSzwz$hnt@-S2S|ou zb%fKR9n}JnNL%@zip@E+Rj!;LVS0d{iZjBpjHKH8>;S#KV1E>{~{Syc!uc+iZxRk*HKJB^#vXp}hq`lg-k zwEcophzunfs`@*Xy=uvZk{9j#*AIM@k3@=$yM=WV29UkWbM!qRV9=@ui<@~oyFl8V z{k-qDgXXWxL@&tBCa+jR%b$JQ1`4s2$hv7X!Xi2{{US^soX$s&OZ#aFhbafY{eIk5 z0zpD%x9yoo9HNQ@LZT z)Z!C^RVlOu2u4q-5vsxROfN{&7Ad4~6-)T$ne&3)OM>tw-;x?LSi>o0LFUl8DRMp0 zBHLV=@nnYo`fx%13pq$cR}Ep!DvvlFgE``z1~g4Wc#dOlp5f9mxp`3q#?}K15G$lFi&1Y&deJd+ydHRnsZQT^FdJQc_Z2-`6o)fJH@Qy*FXZ^$s85dcB$=E7lxu zrQW~)sga-uUVTFjMQzq$v}wT?gL7!V#dhd8!hU^wlTX(X6<8+_FW0gC_vpPgjX0R7 zQ5B{dy}i8+>2F`%^7mY^s#BxtHcH9YC zEg!S*A|!CvxjyT~RWwk(z`nlOr^}7AvrBr%AKB&X%d!_Wd`-*QNl9okyeEX%OnPJM zEw(ChX~CzkgJ;dY8_S`EBwTLxd!6Ks-W^S{j@1(nBiB~>wQ8O_;An#|7uU!*P5vK(uVcNS#LdeWn;jUoj5vO~A4n)D)3|r~q&E{lw_z;JUzaT_AQT!W1-bXqtW(2AnWc}PGyS|lLMBT%`Xe^}rXQs{0U8lI z72_IvCG)q*>Bk2(RcY4V1btm;TN_E4Z!8$a)5vvt*{b|}vn;>;=VO7eT!0dC38Tts zhU*l|FN2yTyAsOxtLyy#0b$|c;aY7DL{3$*H5x7hT+ZIo#%Sl)*Rok+!yIrBLicO4 zyw)6N#?`x(wB4?AkewI+t=*>$$CKW-E7O@=-cqS+PS#PE*fgGtQQBD*CHC`5j#dCN<{2Jeg1g zyVL*sD^NWqOaSaAUW%fe26qQ6sqd7{pO&RiA7#Up00{}hdWR1WDGw<4Usgwjq%dE# zOi$14Q{heboVtds5rUIh!!?@5UGiP1ar9l$K)}dk(v(2d(wwsh?D;d_l0m|)d6_}K zGqq0tQ$eH7AGd6XOuWEP4qQjB{i?H|5hVNGuWxdSVVFMBj}^FF3dx}!eQ#UOy-K*@ zwNqGalgXO%6=zHyZjPb$9QZQeJw3=X!e1mjZx>B#^~R7OPfgfE1Pc59yL=ahDZ^Aw zU!aoVYX{z~FZAh$m9|CuakgzHx1+&$aZYZgbMCIubz*{)w6qrp-HhxHBcdHP)Q-bB z8{r_Q79Z<2uXIiNEcVTMZM)3yMj$eGCn^HexGXGair*lWp+A}nJD1PhMn*=S?=t#S zlTx1Gji#?SDM3C6($3dji`_;Cq%Z=2TN;|!f48XVL3V2{`IH$7PBhzGri^8|@oZk& zb0g<7{2*TYo0qsrb|rPg`mWDsEH`bbgiKUx`NJJdOh0+*uOIf-+U`>-dUvxRY27ip zpSh%5D88SsZe0vilDVT6RV<};;odoQv%j<5w7qmC_ae&90hfTyJF?=_X~;yeKj6P)x0$1_X-03~BIlPSg_U`BvT6 zT?t!isoKtQU7M_nqt2;z%C1-$1lDekbGt4=jSi*V;jmQ3(%pc(H?annyGjR zRJB-ue6j9h&bqx&48>pETm`vT`EbnX2xR3O!w~huOI+Bok~YAyW=Xu8I8u&eQY5e0 zm+Rv!K>kFlG>N!&3^Nu8jZ!L_H{X0h2R1R3%v)V>ngdKG?QgSERUaN7c_C834S6oi z^8Y*=or7nA?ZJA&V4@p(KQFkr#EcY&{>g~OjZ;AvhPx3Ysf7Lx$sER_Zl;N86}?AjHoQPg2DPI1Cf@3>HPL83 zX+gNLCH;l5QV$3y-xV}s1c5Pu>yFu@m)U^NSaqx}wZ~?y*!;>&W;89bx!}85-mCsq z^k;4V!@e`*le@HS(b}FTonyvKrDBW$9f^P%(RB0X4g1p6BkyCAxVwDnge?exVK;@v z)Xz`<RU+>M%uX?+(EJ6-t0g5K z`HE@8po9kQSQ5+GHy(%x00 z20d2Oz|J+7-iJ?$!e5OF7kW>(pkA}3@?C{Tb*bR}jAV{`Zu02s<*UJWcpl`yFJ#+f zC}e?D<=@q?Q}@buGVOG?>MjP%h#wH-t6_)slm=a zNyCa-%P}q(6PHwx=-Q%25`TU3(f;@oqUStLRkrQik9Gwk0xYoXQ}ht4u)FeV24@&q zSB?H57nOcB=D-CwJv-a0-r+;+Ynuu1J!8Y3F_b7_{*Ez9ZcMNEyGO;AIUNhjsf$%n zuP3t;P44cf&OffL_sFq-;C%Lrzqb8?o{+U3m32K-fR$;WWr_YNNRaqfB{Jm&P{?Ul^fmMZR>^}ctP@MEOI@ts^V)dom1 zD9{)4i+3~O9Sq*s{m`nFb638+M*nSxwlloblPCVG-SQmAy(!CF@chv#!w(z(=a)LC ze*FwQp(2a zkmqD^wSlxK!Z)b8ZFa`fj2;ay4GOU>H0=+gI}v{p=~jfk_B{OmWH5cCEfUHMDNf`hDfO5qRzv2`~XkQu-znKqsWpVG0%8d28N-iUmWkyf<>~O); zY0WIclGpa#m%}b-PcEY&oa`=>E=&`F=lqz{4XIz&Z|e32$2Mjh2*zxr&*IX`;?9PG zqe9c~82d8kd=T9&0-W;>Pj|iks{*-qp`sGmoje_xs34%+haT9~L<(ocl~dNcRnU8! z01hWEjN&$+&x5m-LbRY(CY^AwPg&1>&AeKxA(%E=ZhvmOI0L%?Fn3GqNp$JH zVc({JT%>Hb){$3d_-H@#a@hnALq790aiX=%Jym=noI)F|N3`L-#STadwA61mztQbCV?alZw7wxxCFYy8V=oc)w%cq^3V4pV=lxev zQV-KCYcVvqWp7Fb#pZ%D0;f6p6HWlC7fS|e#KKIA*Z>H}9B@Scd?5U3>YBZa7zGfR z8(C5e8~z?OHQP&WCj!@Kk<;*)qZP2?C-Cdwvby&G$4>7a4#U*cOqRg#_3ydczehe5 z%<0TETlkoWp~ZAqE`fm;!=6-(fNOKBk~4Wh)vUX`YlCU5ofoG2@RPk0_52~T<^?V{ z#~m9j569)~Ox%N#uLrbOpSQad3{+UBUK@GUFE92NtKDh#1l&pH_TK6tMM3?^dD5gF@M@iX5a-DYrFkr9 zZC<5<6CNa;koAK{RXk1LLT)W>C+>|3F$q0TGYbo1EwtHTF1 z#iKgIFFqYL1)E3IB-;ZlmMoPLVL06rSm;82rwCGnD7ERFop+1ZH`sX{wU~dD+G2o3 zQMkQlbk+28{9+a}4u?HN*>$^=RzBJ?T*Bm*`VzBX=e>x(r`Q{|vY6eF#v8pdvDIq{NFN@_V66%60tBKt`!M@J3NnK~yp?1jBL z>8N{yGyqnj8~|YUVBwS!@h1rkzF@*nkcx@}HM-*35?-)_?lNuKBFO>lJs^XY?>-RK z{i5JFCEX$cefkwQeEAJzFd(kq-vY+y@e~ck5yDzKbKl1nQbGC-0@#L~vFcSCx9=%R z#@lEy%7UDY0(L5aY}m<2z6EB38V(=VwjK9AD^8P%55fsmwIGli#^GRL^-QI8ueN%FJbYgZULJ*C z1vPbs0+R*a=WK*-K7s6xpJD@2TQ!@j8Gj)WqukkSYTOCHL0(>7Ti;PluIB(e+-+6Z z9*WfbGo-;0TnU^h5>WUVEQj0C;&y)+6ltb$45K`21{pa@*?~=7@!XeWocjw)!5E78 zU-BoW40ypv_0$vtA*~jJk8RF_Ei1Qw)K{D~LOgc&5Z-%S-p(*Wke(h`x%lK#Q}XTd zD=l?QTVl>3!P!`!<$~@S2GYPytNJl;cS1Ne%97N4W$DHRf+R%=7qjeC5yjV26cn?X zQkCA<2=Mr9=m5E1Fax-$iG(e_bah_Sw(ajZU*pQ{*TbZUe0KA+PR^E`y&soVJZGgC zcVRywW?Dlazgd-VX3f7p0EFF~HCpgRQCV48`=3{#{63Hsg^zyD2;BeBAo5{Q4IXE( z&fTL&IqDdixXRtFJ+D2Lt+T^+rKzXB5EakwkRc(}US^CQ z+g>PueCPcGcjKx=Q*Kt*?6U5c8popTgHE%9gOsT}{)~+7=d$h_=vnHUkj6Qt3l2!8 z7*mJOiVX;NPdneG`6Y z?N3oTs-Tj`Q8{=_FqLIw)Wy1|%7lr?%5Io-H9K~JUpd+~wsH=HDroh3!qY49MWqCs zQ02Zy^Hn@Aj`uB?bd_G!4UmcW1Pm1zRyqdEWK=GmH zxi=<(QWGo30I>9KHd0B&zw_ag^6&$wWV@{!S4JoCD%sj2yScpY!&NhTl9ocumL_}8 z?P7tcs}?c*b?;=tpTJ3NmqDVTN<^h}20gua3v+F$Z1Y536fy5BA8X)6Id zdlMAdeRt?z6(ev8B^4j&UIuzmMo>NUF1;>I2~LUd4+j!_BV}YlVb~PR$XHo5{SVpS zFMNc}F6}+oFP3nK*cjuW!l z_Fcp0;WSOtRHYgNfQJ=o9rl7O#>#d&LW%|ZUk>?N=&8gdKY{zWF7~Wn2f||G$^84C zf64gr404w3xYl}IV5JZgg&r~Uzi|3y5e>btkseKd1V`$bi&;8kC7~^DR8BbO|7l4D zPt!z2n6PSd<0BfN-JhWE8&ucSAHI2qW-pz5l3Ja=OtTDNE;BPR38qNUo7(BSCvq?% z11wWV5rknx5EL@T6aO=qp3b%w*@#v4q(#n}^Hg;@INI5pKnaLO_V|LBMLaWXOsvqL zm<+=WYcP|IW>%LaW0ZO6I{!Oe%Xjevky+c9QS8bOts)DLV!k*3m|%p;AYe>o`PonJ zb$0#*6>vp3cD^lU`;#?~3|flMAu5Bn5gB{MIiooC3>n)n2hSyJD+J2nAWf2PoF4@1 zs#`)IrFb2+P_v$fqGgM=>|tFFoRX0VNR9?c-oavU7-7pufBeiB^DJABSoy-YxVN%(A8zz_&NFz3(4mqx+)6|a(JZR?na9oXXTS)f23 zO;<2XJ+UZZx(^kF{w!%8#z8lCzGm7)-l}&XDhBkk&-&xlJqH9#+_5VL&21@H50B8X zA)Fe?ut0e-#mlP-9F<`4`o!i2rGFLKYBap{=jbEQ3jh_kw}#3J-UP(O#c|0hmu!x9 z2lKs8*95NdsAR~pvNI2@|BK4b_-%3QmgUUxUI;WZb-E9rb&Qr%<5d8~kow;1zK+?i zKT#8^bqABf|hH;_oE zG)`;PH|8^Vts-dDG7(P>2|WCt83V=lH5w;*0YSPg^QXo(HqoD-pQ;yrO8E3!EA|-+ zB{y(>2?_+Ef$=res7%`mZc><1n*kq;zVAdhjc4(1T0#M= zDkX}^Wk$`m%!sl!99c9np~FA{8BQ?*h@$!t9xw1656CS2?U#T_sQa2JbEm~Jw0{^Y@O#~v};bX z@;ms`-3vyGn~;v61)g_9eE&;zpN>(P$MyhXlA@vNBM)NcN}xCqjFI_U?T^&!UWsO2 zr!&$f6?L7&Ood(9fy{+1qVjF@b6|W|%813e4fg#AsyQnRIdmlNO)edKx;y5wJE-@^ zNb}fl8u8zwFb&v?RuHX6h`L!sbTX$*T&FD+t5>;%CZ3)s?==}u>UQ3M|NSwhc+HK> znGSl_~t z8Wb?saQnnl+9p>V8cHcyhS$O}fG{^uSZ2NeY53j$DXZ?5KV-Ci?~VJexg@^mI`YLX z`BvyF@G*TPlz799ppTe!+kx$$HGYra6w!)6{ipGeGV_VwEr#!Lx-HM`1x|_J+%$Gi zmcXvPL0PDpp#ocJXw!_hS4VM;PmvWX+y;@{MciQ9v!HA;h+-+etb2joV|SiAsLr~fIszZ8SYIX4%ARm^Yubi*8zzb z2JZsBye;`SAD0Da5%@OXRyXJhN?H^cs6KarAsrPFKKYcBdY5iz9|GG!8Rn+W@k< z+HknML=tkY*O^!xjXFpa{aXr)2ti660AWH?Re@AP&Uk!wOky&N=JXI` z)n=+gqPD;#?e7M~x$PiW_NmRqeU8unP&1bch(c3DsqT5yQ+B5E9)IO*g&PiHvHX|g za$;dRSwjqT$Emx57I?VNd6~=E9;TBfjAKg-i*ER1QcC)Rv1JI|3qfG`=Y>d5oxRD2 z#lGZ+@6+~I|1zdq)lCiQm1`~~lToUxOI)vXwmGgX-1{ymm`hPre>0yNW(OH8q-DMr z^`*N{xR4unArQu?(&!0VH1Ndh$l#X1v3q`Lx!`*slPMSDDIAKF={7J~ct15vdfve^ zmd5@y^?qO>_=%Dg#uh3_<#~XH)8`vf*3r4SpQPPpu%b0p5sr!KAm7^lU4cGgJ}H;> zjB|*x7bSUt@I~i~KW-{|-#@4BL75(i^V8qtAR$Xb2a*X8 z1?1w5&wjV7WR|D0QcSIO>+ELrsV3KFZ>L`*;oLzM#gr2cvNvLHZi^KZLktNCVbE=j zYI2qdfZ3AZ^PTGsuK1H=)aaP;$8L`4k>oS>+qW?Mmw)|U=`pOpIkDY=Y zh)OZSp08N7l)HqN>eJG&fP5j=$B!fqTFOEbp3ZEs^Rx@rrqOX0+)eYBl)3pA_usjYoIO0W(cw_~05^5VO*FF^LEvq>Fe$5zDpbSL3#yQgS)WLD( zk}3=plx(ecJyR_&FSm#uxh_jy|52Pe2JmilrWmkq+tT=k@46Er&UM)SkzKIs!A29k z-$Aj1k*sAI`q^t~;`I_(xx5~R7G$^`s@No%fJC?=0VZecq8#y7G|*TlBDj(NSZ&G1 z#wLaeMOFV4-s-xS6|)Sypela!&eL`5X+a8zcEgF_C|ud}gzf$LBQrF8`UW-BcPwLPH@h2W%(b^-Or8oo@zr$p>pf~$b?doNe!FI*u8u+__BL7OZtEn6;V<`v32N8 zsq@<%j3__y$HXz+ARH6efJ9p{vJ)< zYPU83l6k(8?v<^0;R4ya4U=w6ypS zR&`Yd=T6|Zk9@DY3ZI~vzylJKxQXXh#H?kC1G-uIwl}0UimWctKZAObtCL#2U5L{W z++b2rx=~#|et)Cj1O24ngGR!XQLIX)3F_#@VYV5aazOoCG%{Dd00%yEt&kn>>uCun zp7rKt9?BXHO7~rLT?_rpkdbEf{WTUwNU9=@bibTnIP^iVVj_6<1mT^p_HT1VJzk*d zO30>5ldy`XB#o-M)cCBJ!t>cj_ym|yFhlg^#o3Efs2Zc7Mu{FH@@mkaR{c|eFSDk7 zL_58~`Dmi?Rhi*xlSH;EHF=cSCzfMc&LJYzxge(Hnn2_nGiEm};9f`ZWh=u4_zxB? z41(-5)2`2}!f@DMz6psL>82!c428$yOogHL@!q4(pAjeb15j^H*k=llhMU*HGN^O< z+nNO7*o$~FgPGZUDq77ZK>v#;-s`j|!lJn!C8}|YN#hGr8O{nr8(>qSfTJaf(wf(dtvq5xd7SW8c_{2bc=ksDJxx9s{`eaTx}=Ks+3l0Ks_unMhN|vHAn?|Xala=EAOd;T7iL_y?>m5Od5dmL}CJLai9 zw`EIgS-^#8&Euk*@eO+9>h#gjdW<9ZEp5 zCQ{ulqGJzOhYLcIb?M2XA_gBd#XQ}*RqC}uolu%c;at9m4{Ayhe9pDdrm(a_gSLpA zR=ts^W(XDdQIeH-u61l;1*rsdQOd2lf%ZN_qymVi9eJ3NIHC}`+)SX|I9!ta1!X#dPD78GdAc+C|xTzWn0ht=C(JlR@EiA zt<$yawmCkj%=rYnL@u_ky&@#+aMU31(Vp^rW!X1Xr6HJtQt+We+;kAVB}8y>Yh}rK8*h&eZ7hMsI)(BJbKi;1I$15a3@a2mm>LEEY6IuU4D;|+~{r#)w7fSCq zZ11aAYfE`MupgF1Y#$b_r{{w*FO{fVd=Yj-lOjf-+*K@`>gGf5)O<%r$xc}thBM)E zoN^x!NF_%r$q%+rTL!%AT23_sz*tBqf zGy4XA5zl~u1#kXLGGhEgqR9v&T?sx8pMHPH(Y)^%wFCrn0ql&|* zc17gjOrL5m(bfV~{4On}5~a>=nBK^YrO9OXAgjvvfteLLITARaViuXX+yMk`>s#%L zXjOM6cBO4F+KsMK{RD-yG6zQEM^}x%iIqTS}5tI{4%c8ew(g)=E?_x;s>yMv1lxG<&uuk z-fraz+Gnf1_Vg#+cWuu#n(x%hW|+j*0b#_j#B(D-^D>DOF8fST;TEuqvd`n1y~9Mp zT}f{a?P)VJtpC^ww--q->`6-kC8i0{vKwxs;M(Hk4pWG+LucqAc&|GuEfm?SwC_5! zlheCVmB#c}eN}@vU)G}p*5oi?Oa1_}R(n&DZdr9Gr?i_R5At1L0KJDV0+%ndCRg+F zTZ7evUwoX4_knCm&!N|QWQo)s5zwCZ1zEkZ`U+HJlV3E`56AjBH1TDBOo<~fcW7jf z!zom!l>+<)cfLM>cmxFW;>iO=m?91yCOpWk3oue4SNC_3$jd(!$hWhka*ibs5&b-f1 zrsR>@ja zAtQE$f0YYw-|yl~hcmc3Zjy5=n+tqyO}s2cExs?CyP95u5=y)Os_NWzAz@D1y#{=V zB7Hn_N4dOcv}A*5cKxn<5=n3BH3$s?QMK&6>=1WmyCxhgJ>Z5mq_ly5 zY>0cWEUtRqa5e*gf)~E77-sN@HX%sBZ=}urNRO#v9EY;MTUui?&Lj0(t){g^t`$Z* z6)mb`giZS0?f3o}plN#Fc%QbO*vJ%k;@2oCQLDT53@x$>6LX3NPw^6xuFr+kF+c zEL@_!lnmeQ>J$=79T zlUWjSrOBG0;6oE6r}SU|>O_skeFL05nntqy`V6yUXPghHEde)2M_SHT8$MaPeJRH^ ziIYf_6Kww4a*_)dW;IVxw8f^}r#Zlh&bfETksould+NzW-E6Xz?pvhGW+az>N3Etc!0<31wN>x3tc3g zJW{KF>19?-&(sQIT!XRcg#KoxFZbqvm?1h!m!B##JIc~TEa;PyIZrp?lCJ^RKQhYY z@)F=519~fv)z2%A^u(nsD$}&aARm;&WxrpH(p^A-&AeH)0rf2|u_V%v@#r6S4#^RI zOoHp%Ko~7O?WuqwD-2P4V-f+b+jQ=JIEcLLwady?t2^7{u|56IaC0&}Vuiiaiy(zx z%F0p!-$04C7E2P%7&o1jTtvCr09&zY1Xo;RY{eVF+?hoyq{Vw=da~Ln0 zDSK1;UE3kg0;5lbVrfytBSC~@gq`oXjh+CM)a<@wD?yxqpUa&Qi&Zz5Y_J~gm zS}BEJT6TlzM{*FWr|9l)GLR43BZ?`>Qnev^oBF+}LhnpY<0@FTugFHgz8dxH);0VK`Hg zU~e*CEQxEn+GU}O zB8dPj#6)RRMM$~kU{0Re&jx2YJfn<_k7H%!lqF{v(EJPYs@1!16>rcGEIBKbl}3~I z=k7pLR0-LXQ$s;h3}H9j3tV5FobF}Gm4s%@I*E4n0CvS-l)Lv985C0iX;m6eqzKv3n^5vDWg-kGj%CI5Nj^B?!ka|9ce2!sIJ=nmf_QESqvEO( zIHk_Ke#zxTh>@Vg*QlwKS2T>M{cDOXohX1|RPX~cy+*Hpw?R6DS=8cCDaB{qKCvL* zqEk-wbj7VI_Bi9aEV{t#!Gb*VQMPUE-ov8ON%#HC#ClNj%jZzl`|WkIT&*o2jh#NwT)KYo3{?{C zKWJz8zK`=VfYV#QbA4+JeM)14cm3@l9z91|WI1hLU^Cw~uz67w)26WLyhnej;qKJD z9Ox(?7vWl!R^vmvFix#zdeB^+9a(b#;@f1aseuAmY@Dp)AaXzG{Z#3eXe<}#O_6)o z<+7UVKKdUWTdABBheWO=#h=m}XUEB5?)=nT@M=yeT#Tw5#NcF{5Lhgh!)Q~wECpp% z@y6p5C0Q;*Vy`$;=AQEqFvs8axNWGaYK=a@|0DQGmGpz?o6x5r^FIvUoeP^Yr-=HF zn6OzHX)K~)spQ-1lSO~-+ndH)?+=I4kIyztEplgiJROj<_%xnvGAci zGa&$$&AW5Wv*aI|H-1(L1fd(XNO`a&YlvZ6a!5HFW%lKiYcD5;W%|#`8XPIVoRMYTg2~bA*N}|TJIS`JQ+3aISvTi!Q=~;)Oo(^V zlQmV5V-=#{56!-s0$Vkx04Y+oMPLODi~33d+}zCsgLsQ+1m`p0^iT^f_6|h~1_d~a zb!wCq`sz7nZMO4UTQdS2jasoYx&Cdb<_tmyqFGb`m|Z+@9e%O&>ooP!sZQY0nl)Ys zDYFwcRS%>wR$)N}dGYiEPw(ndl~U81dmoT*F)OC-zK>ok{_e{SeEe!bvL)UP=*g|T z(MZBZVuf|!deGDeZ}nwuE|B4pyqdt8>G6PEEa8j)-K;;&| NWF-|PYQ>C#|1Zo-K#TwY literal 0 HcmV?d00001 diff --git a/src/data/documents.js b/src/data/documents.js new file mode 100644 index 0000000..e09f110 --- /dev/null +++ b/src/data/documents.js @@ -0,0 +1,108 @@ +const documents = [ + { + id: 1, + name: "FAR Part 25.571: Avaliação de Tolerância ao Dano e Fadiga da Estrutura", + type: "Técnico", + updatedAt: "09/09/2026", + accessLevel: "Nível 1", + fileType: "PDF", + }, + { + id: 2, + name: "Manual de Manutenção da Estrutura da Aeronave", + type: "Técnico", + updatedAt: "08/09/2026", + accessLevel: "Nível 1", + fileType: "PDF", + }, + { + id: 3, + name: "Procedimentos de Inspeção Estrutural", + type: "Técnico", + updatedAt: "07/09/2026", + accessLevel: "Nível 2", + fileType: "PDF", + }, + { + id: 4, + name: "Relatório de Inspeção de Componentes", + type: "Relatório", + updatedAt: "06/09/2026", + accessLevel: "Nível 1", + fileType: "PDF", + }, + { + id: 5, + name: "Normas de Segurança para Manutenção", + type: "Norma", + updatedAt: "05/09/2026", + accessLevel: "Nível 1", + fileType: "PDF", + }, + { + id: 6, + name: "Manual de Procedimentos Operacionais", + type: "Operacional", + updatedAt: "04/09/2026", + accessLevel: "Nível 2", + fileType: "PDF", + }, + { + id: 7, + name: "Especificação Técnica de Materiais", + type: "Técnico", + updatedAt: "03/09/2026", + accessLevel: "Nível 1", + fileType: "PDF", + }, + { + id: 8, + name: "Relatório de Avaliação de Fadiga", + type: "Relatório", + updatedAt: "02/09/2026", + accessLevel: "Nível 2", + fileType: "PDF", + }, + { + id: 9, + name: "Guia de Inspeção Preventiva", + type: "Técnico", + updatedAt: "01/09/2026", + accessLevel: "Nível 1", + fileType: "PDF", + }, + { + id: 10, + name: "Manual de Controle de Qualidade", + type: "Qualidade", + updatedAt: "30/08/2026", + accessLevel: "Nível 2", + fileType: "PDF", + }, + { + id: 11, + name: "Normas Técnicas de Engenharia", + type: "Técnico", + updatedAt: "29/08/2026", + accessLevel: "Nível 1", + fileType: "PDF", + }, + { + id: 12, + name: "Relatório de Manutenção Preventiva", + type: "Relatório", + updatedAt: "28/08/2026", + accessLevel: "Nível 1", + fileType: "PDF", + }, + { + id: 13, + name: "Manual de Segurança Operacional", + type: "Segurança", + updatedAt: "26/08/2026", + accessLevel: "Nível 1", + fileType: "PDF", + }, +]; + +export default documents; \ No newline at end of file From 97b40b715c4af3a1f095a0986cf7cbb1ddf588da Mon Sep 17 00:00:00 2001 From: CainaNascimentoMelo Date: Wed, 9 Sep 2026 21:41:39 -0300 Subject: [PATCH 05/52] feat(3): Refactor Document components and add styles for DocumentItem and DocumentList --- src/App.jsx | 2 +- src/components/{ => Document}/DocumentItem.css | 0 src/components/{ => Document}/DocumentItem.jsx | 0 src/components/{ => Document}/DocumentList.css | 0 src/components/{ => Document}/DocumentList.jsx | 0 src/components/{ => Pagination}/Pagination.css | 0 src/components/{ => Pagination}/Pagination.jsx | 0 src/components/{ => SearchBar}/SearchBar.css | 0 src/components/{ => SearchBar}/SearchBar.jsx | 0 9 files changed, 1 insertion(+), 1 deletion(-) rename src/components/{ => Document}/DocumentItem.css (100%) rename src/components/{ => Document}/DocumentItem.jsx (100%) rename src/components/{ => Document}/DocumentList.css (100%) rename src/components/{ => Document}/DocumentList.jsx (100%) rename src/components/{ => Pagination}/Pagination.css (100%) rename src/components/{ => Pagination}/Pagination.jsx (100%) rename src/components/{ => SearchBar}/SearchBar.css (100%) rename src/components/{ => SearchBar}/SearchBar.jsx (100%) diff --git a/src/App.jsx b/src/App.jsx index 4523deb..5a177e7 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,7 +1,7 @@ import { useMemo, useState } from "react"; import SearchBar from "./components/SearchBar"; -import DocumentList from "./components/DocumentList"; +import DocumentList from "./components/Document/DocumentList"; import Pagination from "./components/Pagination"; import documents from "./data/documents"; diff --git a/src/components/DocumentItem.css b/src/components/Document/DocumentItem.css similarity index 100% rename from src/components/DocumentItem.css rename to src/components/Document/DocumentItem.css diff --git a/src/components/DocumentItem.jsx b/src/components/Document/DocumentItem.jsx similarity index 100% rename from src/components/DocumentItem.jsx rename to src/components/Document/DocumentItem.jsx diff --git a/src/components/DocumentList.css b/src/components/Document/DocumentList.css similarity index 100% rename from src/components/DocumentList.css rename to src/components/Document/DocumentList.css diff --git a/src/components/DocumentList.jsx b/src/components/Document/DocumentList.jsx similarity index 100% rename from src/components/DocumentList.jsx rename to src/components/Document/DocumentList.jsx diff --git a/src/components/Pagination.css b/src/components/Pagination/Pagination.css similarity index 100% rename from src/components/Pagination.css rename to src/components/Pagination/Pagination.css diff --git a/src/components/Pagination.jsx b/src/components/Pagination/Pagination.jsx similarity index 100% rename from src/components/Pagination.jsx rename to src/components/Pagination/Pagination.jsx diff --git a/src/components/SearchBar.css b/src/components/SearchBar/SearchBar.css similarity index 100% rename from src/components/SearchBar.css rename to src/components/SearchBar/SearchBar.css diff --git a/src/components/SearchBar.jsx b/src/components/SearchBar/SearchBar.jsx similarity index 100% rename from src/components/SearchBar.jsx rename to src/components/SearchBar/SearchBar.jsx From c03bf7d0d695ef0b0d7f93d25decbc5b4b3e145d Mon Sep 17 00:00:00 2001 From: CainaNascimentoMelo Date: Wed, 9 Sep 2026 21:41:59 -0300 Subject: [PATCH 06/52] feat(3): Update import paths for SearchBar and Pagination components --- src/App.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/App.jsx b/src/App.jsx index 5a177e7..73bf54c 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,8 +1,8 @@ import { useMemo, useState } from "react"; -import SearchBar from "./components/SearchBar"; +import SearchBar from "./components/SearchBar/SearchBar"; import DocumentList from "./components/Document/DocumentList"; -import Pagination from "./components/Pagination"; +import Pagination from "./components/Pagination/Pagination"; import documents from "./data/documents"; From ddc1611697596dbba7bc3aa12f6f31633dc7a0bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cain=C3=A3=20Melo?= <163151125+CainaNascimentoMelo@users.noreply.github.com> Date: Thu, 10 Sep 2026 22:32:15 -0300 Subject: [PATCH 07/52] feat(8): Add DocumentModal CSS and JSX --- src/components/Document/DocumentModal.css | 277 ++++++++++++++++++++++ src/components/Document/DocumentModal.jsx | 169 +++++++++++++ 2 files changed, 446 insertions(+) create mode 100644 src/components/Document/DocumentModal.css create mode 100644 src/components/Document/DocumentModal.jsx diff --git a/src/components/Document/DocumentModal.css b/src/components/Document/DocumentModal.css new file mode 100644 index 0000000..0a3f96e --- /dev/null +++ b/src/components/Document/DocumentModal.css @@ -0,0 +1,277 @@ +.document-modal-overlay { + position: fixed; + inset: 0; + + z-index: 1000; + + display: flex; + align-items: center; + justify-content: center; + + padding: 20px; + + background: rgba(40, 20, 30, 0.18); +} + +.document-modal { + width: min(550px, 90vw); + + padding: 12px; + + border: 1px solid #cba9b5; + border-radius: 20px; + + background: #ffffff; + + box-shadow: 0 8px 25px rgba(60, 25, 40, 0.12); +} + +.modal-top { + display: flex; + align-items: flex-start; + justify-content: space-between; + + padding: 0 6px 6px; + + border-bottom: 1px solid #d5b9c3; +} + +.modal-code-section { + display: flex; + flex-direction: column; +} + +.modal-label { + display: block; + + margin-bottom: 3px; + + font-size: 10px; + color: #806d75; +} + +.modal-code { + display: flex; + align-items: center; + gap: 10px; + + font-size: 24px; + color: #501f35; +} + +.modal-pdf-badge { + display: inline-flex; + align-items: center; + justify-content: center; + + width: 65px; + height: 30px; + + border: 1px solid #ff6577; + border-radius: 10px; + + color: #ff6577; + + font-size: 13px; + font-weight: 500; +} + +.modal-close { + width: 30px; + height: 30px; + + border: none; + background: transparent; + + color: #888888; + + font-size: 29px; + font-weight: 300; + + cursor: pointer; +} + +.modal-close:hover { + color: #4d1d30; +} + +.modal-title-section { + padding: 7px 6px; + + border-bottom: 1px solid #d5b9c3; +} + +.modal-document-title { + margin: 0; + + font-size: 11px; + line-height: 17px; + color: #3e3438; +} + +.modal-main-info { + display: flex; + align-items: flex-end; + gap: 16px; + + padding: 8px 6px; +} + +.modal-info-group { + display: flex; + flex-direction: column; + gap: 3px; +} + +.modal-info-badge { + display: inline-flex; + align-items: center; + justify-content: center; + + min-width: 70px; + height: 30px; + + padding: 0 10px; + + border: 1px solid #a98a98; + border-radius: 9px; + + color: #501f35; + + font-size: 13px; + + background: #ffffff; +} + +.modal-details { + display: grid; + grid-template-columns: 1fr 1fr; + + gap: 24px; + + padding: 5px 6px; +} + +.file-data-section, +.tags-section { + min-width: 0; +} + +.section-title { + display: block; + + margin-bottom: 5px; + + font-size: 11px; + color: #806d75; +} + +.file-data-box { + min-height: 128px; + + display: flex; + flex-direction: column; + justify-content: space-around; + + padding: 8px; + + border: 1px solid #cba9b5; + border-radius: 9px; +} + +.file-data-row { + display: flex; + align-items: center; + justify-content: space-between; + + gap: 10px; + + font-size: 12px; + color: #40363a; +} + +.file-data-row strong { + font-weight: 400; + color: #151515; +} + +.tags-box { + min-height: 128px; + + display: flex; + align-content: flex-start; + flex-wrap: wrap; + + gap: 7px; + + padding: 8px; + + border: 1px solid #cba9b5; + border-radius: 9px; +} + +.document-tag { + height: 25px; + + display: inline-flex; + align-items: center; + + padding: 0 8px; + + border: 1px solid #77aeea; + border-radius: 12px; + + background: #f8fbff; + + color: #1764bc; + + font-size: 10px; +} + +.modal-actions { + display: flex; + justify-content: flex-end; + + padding: 15px 6px 8px; +} + +.modal-view-button { + display: flex; + align-items: center; + gap: 5px; + + height: 32px; + + padding: 0 10px; + + border: 1px solid #71a6df; + border-radius: 9px; + + background: #ffffff; + + color: #275b8d; + + font-size: 13px; + + box-shadow: 0 3px 10px rgba(60, 130, 210, 0.22); + + cursor: pointer; +} + +.modal-view-button:hover { + background: #f4f9ff; +} + +@media (max-width: 650px) { + .modal-details { + grid-template-columns: 1fr; + } + + .modal-main-info { + flex-wrap: wrap; + } + + .modal-code { + font-size: 20px; + } +} \ No newline at end of file diff --git a/src/components/Document/DocumentModal.jsx b/src/components/Document/DocumentModal.jsx new file mode 100644 index 0000000..f295fc7 --- /dev/null +++ b/src/components/Document/DocumentModal.jsx @@ -0,0 +1,169 @@ +import "./DocumentModal.css"; + +function DocumentModal({ document, onClose, onViewPdf }) { + if (!document) { + return null; + } + + const tags = [ + "Materiais metálicos", + "Manutenção", + "MIL-HDBK", + "Engenharia", + "Handbook", + ]; + + return ( +
+
event.stopPropagation()} + > +
+
+ + Código da norma + + +
+ {document.code || document.name} + + + PDF + +
+
+ + +
+ + {/* TÍTULO */} +
+ + Título do arquivo + + +

+ {document.name} +

+
+ +
+
+ + Setor/Tipo + + + + {document.type} + +
+ +
+ + Nível de Acesso + + + + {document.accessLevel} + +
+ +
+ + Categoria + + + + {document.category || document.type} + +
+
+ +
+
+ + Dados do arquivo + + +
+
+ ↻ Revisão: + + {document.revision || "5J"} + +
+ +
+ ◷ Data de Atualização: + + {document.updatedAt} + +
+ +
+ ▤ Tamanho do arquivo: + + {document.fileSize || "66.8 MB"} + +
+
+
+ + {/* TAGS */} +
+ + 🏷 Tags + + +
+ {tags.map((tag) => ( + + {tag} + + ))} +
+
+
+ +
+ +
+
+
+ ); +} + +export default DocumentModal; \ No newline at end of file From c575d480ca7784c44421323cf8379106c1492c37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cain=C3=A3=20Melo?= <163151125+CainaNascimentoMelo@users.noreply.github.com> Date: Thu, 10 Sep 2026 22:32:31 -0300 Subject: [PATCH 08/52] feat(8): Integrate DocumentModal component and update DocumentList logic --- src/App.css | 115 ----------------------- src/App.jsx | 83 +++++----------- src/components/Document/DocumentList.css | 4 +- src/components/Document/DocumentList.jsx | 2 +- 4 files changed, 29 insertions(+), 175 deletions(-) diff --git a/src/App.css b/src/App.css index 95d7995..18ca78c 100644 --- a/src/App.css +++ b/src/App.css @@ -115,8 +115,6 @@ input { color: #8b3154; } -/* MAIN */ - .main-content { flex: 1; @@ -185,119 +183,6 @@ input { width: 100%; } -.modal-overlay { - position: fixed; - inset: 0; - - display: flex; - align-items: center; - justify-content: center; - - background-color: rgba(45, 20, 30, 0.35); - - z-index: 100; -} - -.document-modal { - width: min(650px, 90vw); - - border-radius: 10px; - - background-color: #ffffff; - - box-shadow: 0 15px 50px rgba(40, 15, 25, 0.25); - - overflow: hidden; -} - -.modal-header { - display: flex; - align-items: center; - justify-content: space-between; - - padding: 18px 20px; - - border-bottom: 1px solid #ead8de; -} - -.modal-header h2 { - margin: 0; - - max-width: 90%; - - font-size: 16px; - font-weight: 500; - - color: #4d2032; -} - -.modal-close { - border: none; - background: transparent; - - font-size: 25px; - color: #6c4a56; - - cursor: pointer; -} - -.pdf-preview { - min-height: 280px; - - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - - background-color: #faf7f8; - - color: #604852; -} - -.pdf-icon { - width: 70px; - height: 85px; - - display: flex; - align-items: center; - justify-content: center; - - margin-bottom: 15px; - - border: 2px solid #ef6577; - border-radius: 6px; - - color: #ef6577; - - font-size: 15px; - font-weight: bold; -} - -.pdf-preview h3 { - margin: 0 0 7px; - - font-size: 15px; -} - -.pdf-preview p { - margin: 0; - - font-size: 12px; - color: #88767d; -} - -.modal-footer { - display: flex; - justify-content: space-between; - - padding: 15px 20px; - - border-top: 1px solid #ead8de; - - font-size: 11px; - color: #6b555d; -} - @media (max-width: 900px) { .sidebar { width: 100px; diff --git a/src/App.jsx b/src/App.jsx index 73bf54c..9489d1d 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -3,6 +3,7 @@ import { useMemo, useState } from "react"; import SearchBar from "./components/SearchBar/SearchBar"; import DocumentList from "./components/Document/DocumentList"; import Pagination from "./components/Pagination/Pagination"; +import DocumentModal from "./components/Document/DocumentModal"; import documents from "./data/documents"; @@ -43,19 +44,31 @@ function App() { ); function handleSearch(value) { - setSearch(value); - setCurrentPage(1); + setSearch(value); + setCurrentPage(1); +} + +function handlePageChange(page) { + if (page < 1 || page > totalPages) { + return; } - function handlePageChange(page) { - if (page < 1 || page > totalPages) { - return; - } + setCurrentPage(page); +} - setCurrentPage(page); +function handleViewPdf(document) { + if (document.pdfUrl) { + window.open(document.pdfUrl, "_blank"); + return; } - return ( + console.log( + "PDF ainda não disponível para o documento:", + document.name + ); +} + +return (
- {documents.length > 2 ? ( + {documents.length > 0 ? ( documents.map((document) => ( Date: Thu, 10 Sep 2026 22:32:44 -0300 Subject: [PATCH 09/52] feat(8): Update document mocks --- src/data/documents.js | 114 ++++++++++++++++++++++++++++++------------ 1 file changed, 83 insertions(+), 31 deletions(-) diff --git a/src/data/documents.js b/src/data/documents.js index e09f110..519c44d 100644 --- a/src/data/documents.js +++ b/src/data/documents.js @@ -1,107 +1,159 @@ const documents = [ { id: 1, - name: "FAR Part 25.571: Avaliação de Tolerância ao Dano e Fadiga da Estrutura", + code: "MIL-HDBK-5J", + name: "DEPARTMENT OF DEFENSE HANDBOOK: METALLIC MATERIALS AND ELEMENTS FOR AEROSPACE VEHICLE STRUCTURES", type: "Técnico", - updatedAt: "09/09/2026", + category: "MIL-HDBK", + updatedAt: "05/05/2004", accessLevel: "Nível 1", fileType: "PDF", + revision: "5J", + fileSize: "66.8 MB", + pdfUrl: "", }, { id: 2, - name: "Manual de Manutenção da Estrutura da Aeronave", + code: "ATA-100", + name: "SPECIFICATION FOR MANUFACTURERS' TECHNICAL DATA AND AIRCRAFT DOCUMENTATION", type: "Técnico", + category: "ATA", updatedAt: "08/09/2026", accessLevel: "Nível 1", fileType: "PDF", + revision: "Rev. 3", + fileSize: "8.9 MB", + pdfUrl: "", }, { id: 3, - name: "Procedimentos de Inspeção Estrutural", - type: "Técnico", + code: "SAE-ARP4761", + name: "GUIDELINES AND METHODS FOR CONDUCTING THE SAFETY ASSESSMENT PROCESS ON CIVIL AIRBORNE SYSTEMS AND EQUIPMENT", + type: "Segurança", + category: "SAE-ARP", updatedAt: "07/09/2026", accessLevel: "Nível 2", fileType: "PDF", + revision: "Original", + fileSize: "18.5 MB", + pdfUrl: "", }, { id: 4, - name: "Relatório de Inspeção de Componentes", - type: "Relatório", + code: "NASA-STD-5001", + name: "STRUCTURAL DESIGN AND TEST FACTORS OF SAFETY FOR SPACEFLIGHT HARDWARE", + type: "Técnico", + category: "NASA-STD", updatedAt: "06/09/2026", accessLevel: "Nível 1", fileType: "PDF", + revision: "Rev. B", + fileSize: "4.8 MB", + pdfUrl: "", }, { id: 5, - name: "Normas de Segurança para Manutenção", - type: "Norma", + code: "AS9100D", + name: "QUALITY MANAGEMENT SYSTEMS - REQUIREMENTS FOR AVIATION, SPACE AND DEFENSE ORGANIZATIONS", + type: "Qualidade", + category: "AS9100", updatedAt: "05/09/2026", accessLevel: "Nível 1", fileType: "PDF", + revision: "D", + fileSize: "5.7 MB", + pdfUrl: "", }, { id: 6, - name: "Manual de Procedimentos Operacionais", - type: "Operacional", + code: "RTCA-DO-178C", + name: "SOFTWARE CONSIDERATIONS IN AIRBORNE SYSTEMS AND EQUIPMENT CERTIFICATION", + type: "Software", + category: "RTCA", updatedAt: "04/09/2026", accessLevel: "Nível 2", fileType: "PDF", + revision: "C", + fileSize: "7.2 MB", + pdfUrl: "", }, { id: 7, - name: "Especificação Técnica de Materiais", - type: "Técnico", + code: "MIL-HDBK-17-3F", + name: "COMPOSITE MATERIALS HANDBOOK: POLYMER MATRIX COMPOSITES", + type: "Materiais", + category: "MIL-HDBK", updatedAt: "03/09/2026", accessLevel: "Nível 1", fileType: "PDF", + revision: "3F", + fileSize: "42.3 MB", + pdfUrl: "", }, { id: 8, - name: "Relatório de Avaliação de Fadiga", - type: "Relatório", + code: "ASTM-E8", + name: "STANDARD TEST METHODS FOR TENSION TESTING OF METALLIC MATERIALS", + type: "Ensaios", + category: "ASTM", updatedAt: "02/09/2026", accessLevel: "Nível 2", fileType: "PDF", + revision: "2022", + fileSize: "1.9 MB", + pdfUrl: "", }, { id: 9, - name: "Guia de Inspeção Preventiva", - type: "Técnico", + code: "NASA-STD-5009", + name: "NONDESTRUCTIVE EVALUATION REQUIREMENTS FOR FRACTURE CONTROL PROGRAMS", + type: "Inspeção", + category: "NASA-STD", updatedAt: "01/09/2026", accessLevel: "Nível 1", fileType: "PDF", + revision: "Rev. A", + fileSize: "2.7 MB", + pdfUrl: "", }, { id: 10, - name: "Manual de Controle de Qualidade", - type: "Qualidade", + code: "SAE-ARP4754A", + name: "GUIDELINES FOR DEVELOPMENT OF CIVIL AIRCRAFT AND SYSTEMS", + type: "Engenharia", + category: "SAE-ARP", updatedAt: "30/08/2026", accessLevel: "Nível 2", fileType: "PDF", + revision: "A", + fileSize: "9.6 MB", + pdfUrl: "", }, { id: 11, - name: "Normas Técnicas de Engenharia", - type: "Técnico", + code: "RTCA-DO-254", + name: "DESIGN ASSURANCE GUIDANCE FOR AIRBORNE ELECTRONIC HARDWARE", + type: "Eletrônica", + category: "RTCA", updatedAt: "29/08/2026", accessLevel: "Nível 1", fileType: "PDF", + revision: "A", + fileSize: "6.4 MB", + pdfUrl: "", }, { id: 12, - name: "Relatório de Manutenção Preventiva", - type: "Relatório", + code: "ASTM-E290", + name: "STANDARD TEST METHODS FOR BEND TESTING OF MATERIALS FOR DUCTILITY", + type: "Ensaios", + category: "ASTM", updatedAt: "28/08/2026", accessLevel: "Nível 1", fileType: "PDF", - }, - { - id: 13, - name: "Manual de Segurança Operacional", - type: "Segurança", - updatedAt: "26/08/2026", - accessLevel: "Nível 1", - fileType: "PDF", + revision: "2021", + fileSize: "1.4 MB", + pdfUrl: "", }, ]; From 942cd15f522fe61762a5ff8144989a5afeb48333 Mon Sep 17 00:00:00 2001 From: Daniel Sendreti Date: Fri, 11 Sep 2026 22:20:20 -0300 Subject: [PATCH 10/52] feat(22): Add initial frontend CI implementation --- .github/workflows/build.yml | 21 ---------- .github/workflows/ci-frontend.yml | 70 +++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 21 deletions(-) delete mode 100644 .github/workflows/build.yml create mode 100644 .github/workflows/ci-frontend.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml deleted file mode 100644 index c1137fd..0000000 --- a/.github/workflows/build.yml +++ /dev/null @@ -1,21 +0,0 @@ -name: Build -on: - schedule: - - cron: '0 3 * * 0' - push: - branches: - - master - pull_request: - types: [opened, synchronize, reopened] -jobs: - sonarqube: - name: SonarQube - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 - with: - fetch-depth: 0 - - name: SonarQube Scan - uses: SonarSource/sonarqube-scan-action@7006c4492b2e0ee0f816d36501671557c97f5995 # v8.1.0 - env: - SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} diff --git a/.github/workflows/ci-frontend.yml b/.github/workflows/ci-frontend.yml new file mode 100644 index 0000000..966007c --- /dev/null +++ b/.github/workflows/ci-frontend.yml @@ -0,0 +1,70 @@ +name: Frontend CI + +on: + push: + branches: + - main + - "develop-*" + pull_request: + branches: + - main + - "develop-*" + types: [opened, synchronize, reopened] + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: frontend-ci-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + commit-build: + name: "Estágio 1: qualidade e build" + runs-on: ubuntu-latest + timeout-minutes: 10 + + steps: + - name: Checkout do código + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 + + - name: Configurar Node.js + uses: actions/setup-node@v4 + with: + node-version: "22" + cache: npm + cache-dependency-path: package-lock.json + + - name: Instalar dependências + run: npm ci + + - name: Executar análise estática com ESLint + run: npm run lint + + - name: Gerar build de produção + run: npm run build + + secondary-build: + name: "Estágio 2: análise no SonarCloud" + runs-on: ubuntu-latest + timeout-minutes: 10 + needs: commit-build + env: + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + + steps: + - name: Checkout do código + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 + with: + fetch-depth: 0 + + - name: Executar análise no SonarCloud + if: env.SONAR_TOKEN != '' + uses: SonarSource/sonarqube-scan-action@7006c4492b2e0ee0f816d36501671557c97f5995 # v8.1.0 + env: + SONAR_TOKEN: ${{ env.SONAR_TOKEN }} + + - name: Informar ausência do token do SonarCloud + if: env.SONAR_TOKEN == '' + run: echo "::notice::SonarCloud não executado porque o secret SONAR_TOKEN não está disponível." From d2b3bde9ea2ca3c9811a522efde22afb890efb05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cain=C3=A3=20Melo?= <163151125+CainaNascimentoMelo@users.noreply.github.com> Date: Sat, 12 Sep 2026 12:37:17 -0300 Subject: [PATCH 11/52] feat(8): Implement Layout, Home and Sidebar components --- src/components/Layout/Layout.css | 21 ++++ src/components/Layout/Layout.jsx | 17 ++++ src/components/Sidebar/Sidebar.css | 122 +++++++++++++++++++++++ src/components/Sidebar/Sidebar.jsx | 75 +++++++++++++++ src/pages/Home.css | 99 +++++++++++++++++++ src/pages/Home.jsx | 149 +++++++++++++++++++++++++++++ 6 files changed, 483 insertions(+) create mode 100644 src/components/Layout/Layout.css create mode 100644 src/components/Layout/Layout.jsx create mode 100644 src/components/Sidebar/Sidebar.css create mode 100644 src/components/Sidebar/Sidebar.jsx create mode 100644 src/pages/Home.css create mode 100644 src/pages/Home.jsx diff --git a/src/components/Layout/Layout.css b/src/components/Layout/Layout.css new file mode 100644 index 0000000..ae77ef6 --- /dev/null +++ b/src/components/Layout/Layout.css @@ -0,0 +1,21 @@ +.layout { + display: flex; + + min-height: 100vh; + + background: #ffffff; +} + +.layout-content { + flex: 1; + + min-width: 0; + + padding: 40px 25px 20px; +} + +@media (max-width: 900px) { + .layout-content { + padding: 30px 20px 20px; + } +} \ No newline at end of file diff --git a/src/components/Layout/Layout.jsx b/src/components/Layout/Layout.jsx new file mode 100644 index 0000000..68c250c --- /dev/null +++ b/src/components/Layout/Layout.jsx @@ -0,0 +1,17 @@ +import Sidebar from "../Sidebar/Sidebar"; + +import "./Layout.css"; + +function Layout({ children }) { + return ( +
+ + +
+ {children} +
+
+ ); +} + +export default Layout; \ No newline at end of file diff --git a/src/components/Sidebar/Sidebar.css b/src/components/Sidebar/Sidebar.css new file mode 100644 index 0000000..42fbeb0 --- /dev/null +++ b/src/components/Sidebar/Sidebar.css @@ -0,0 +1,122 @@ +.sidebar { + position: relative; + + width: 250px; + min-width: 100px; + min-height: 100vh; + + display: flex; + flex-direction: column; + + border-right: 1px solid #ead5dc; + + background: linear-gradient( + to bottom, + #ffffff 0%, + #fff8fa 100% + ); +} + +.sidebar-logo { + height: 200px; + + display: flex; + align-items: center; + justify-content: center; +} + +.sidebar-logo-mark { + width: 128px; + height: 128px; + + display: flex; + align-items: center; + justify-content: center; +} + +.sidebar-logo-mark img { + max-width: 100%; + max-height: 100%; + + object-fit: contain; +} + +.sidebar-menu { + display: flex; + flex-direction: column; +} + +.sidebar-item { + width: 100%; + height: 48px; + + padding: 0 20px; + + display: flex; + align-items: center; + + gap: 10px; + + border: none; + + background: transparent; + + color: #000000; + + font-size: 19px; + + cursor: pointer; +} + +.sidebar-item.active { + background-color: #fff0f4; +} + +.sidebar-item:hover { + background-color: #fff0f4; +} + +.logout-button { + position: absolute; + + left: 20px; + bottom: 18px; + + display: flex; + align-items: center; + + gap: 7px; + + border: none; + + background: transparent; + + color: #501f32; + + font-size: 15px; + + cursor: pointer; +} + +.logout-button:hover { + color: #8b3154; +} + +@media (max-width: 900px) { + .sidebar { + width: 100px; + min-width: 100px; + } + + .sidebar-item { + padding: 0 12px; + } + + .sidebar-logo { + height: 160px; + } + + .logout-button { + left: 12px; + } +} \ No newline at end of file diff --git a/src/components/Sidebar/Sidebar.jsx b/src/components/Sidebar/Sidebar.jsx new file mode 100644 index 0000000..21778e2 --- /dev/null +++ b/src/components/Sidebar/Sidebar.jsx @@ -0,0 +1,75 @@ +import logo from "../../assets/AkaerLogo.png"; +import "./Sidebar.css"; + +function Sidebar() { + return ( + + ); +} + +export default Sidebar; \ No newline at end of file diff --git a/src/pages/Home.css b/src/pages/Home.css new file mode 100644 index 0000000..e109809 --- /dev/null +++ b/src/pages/Home.css @@ -0,0 +1,99 @@ +.home { + width: 100%; +} + +.page-header { + display: flex; + + align-items: center; + justify-content: space-between; + + padding-bottom: 8px; + + border-bottom: 1px solid #e8d6dc; +} + +.page-title { + display: flex; + + align-items: center; + + gap: 9px; + + color: #000000; +} + +.page-title h1 { + margin: 0; + + font-size: 28px; + font-weight: 400; +} + +.header-actions { + display: flex; + + align-items: center; + + gap: 8px; +} + +.filter-button { + height: 36px; + + display: flex; + align-items: center; + + gap: 5px; + + padding: 0 10px; + + border: 1px solid #e8d6dc; + border-radius: 7px; + + background-color: #ffffff; + + color: #000000; + + font-size: 12px; + + cursor: pointer; +} + +.filter-button:hover { + background-color: #fff7f9; +} + +.documents-section { + width: 100%; + + margin-top: 25px; +} + +@media (max-width: 900px) { + .page-header { + align-items: flex-start; + gap: 15px; + } + + .header-actions { + flex-wrap: wrap; + justify-content: flex-end; + } + + .page-title h1 { + font-size: 24px; + } +} + +@media (max-width: 650px) { + .page-header { + flex-direction: column; + } + + .header-actions { + width: 100%; + + justify-content: flex-start; + } +} \ No newline at end of file diff --git a/src/pages/Home.jsx b/src/pages/Home.jsx new file mode 100644 index 0000000..d6c4c21 --- /dev/null +++ b/src/pages/Home.jsx @@ -0,0 +1,149 @@ +import { useMemo, useState } from "react"; + +import SearchBar from "../components/SearchBar/SearchBar"; +import DocumentList from "../components/Document/DocumentList"; +import Pagination from "../components/Pagination/Pagination"; +import DocumentModal from "../components/Document/DocumentModal"; + +import documents from "../data/documents"; + +import "./Home.css"; + +const DOCUMENTS_PER_PAGE = 10; + +function Home() { + const [search, setSearch] = useState(""); + const [currentPage, setCurrentPage] = useState(1); + const [selectedDocument, setSelectedDocument] = useState(null); + + const filteredDocuments = useMemo(() => { + return documents.filter((document) => + document.name + .toLowerCase() + .includes(search.toLowerCase()) + ); + }, [search]); + + const totalPages = Math.ceil( + filteredDocuments.length / DOCUMENTS_PER_PAGE + ); + + const validPage = + totalPages === 0 + ? 1 + : Math.min(currentPage, totalPages); + + const firstDocumentIndex = + (validPage - 1) * DOCUMENTS_PER_PAGE; + + const currentDocuments = filteredDocuments.slice( + firstDocumentIndex, + firstDocumentIndex + DOCUMENTS_PER_PAGE + ); + + function handleSearch(value) { + setSearch(value); + setCurrentPage(1); + } + + function handlePageChange(page) { + if (page < 1 || page > totalPages) { + return; + } + + setCurrentPage(page); + } + + function handleViewPdf(document) { + if (document.pdfUrl) { + window.open(document.pdfUrl, "_blank"); + return; + } + + console.log( + "PDF ainda não disponível para o documento:", + document.name + ); + } + + return ( +
+
+
+ + + + + + + + +

Documentos

+
+ +
+ + + +
+
+ +
+ + + +
+ + setSelectedDocument(null)} + onViewPdf={handleViewPdf} + /> +
+ ); +} + +export default Home; \ No newline at end of file From c4a5d6094fd4c0cb872acf8ec724508ec9b67c14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cain=C3=A3=20Melo?= <163151125+CainaNascimentoMelo@users.noreply.github.com> Date: Sat, 12 Sep 2026 12:37:35 -0300 Subject: [PATCH 12/52] refactor(8): Refactor App component to use Layout and Home components --- src/App.css | 203 ++---------------------------------------------- src/App.jsx | 217 ++-------------------------------------------------- 2 files changed, 14 insertions(+), 406 deletions(-) diff --git a/src/App.css b/src/App.css index 18ca78c..53cdbcc 100644 --- a/src/App.css +++ b/src/App.css @@ -2,9 +2,17 @@ box-sizing: border-box; } +html, +body, +#root { + min-height: 100%; +} + body { margin: 0; + font-family: Arial, Helvetica, sans-serif; + background: #ffffff; color: #351b27; } @@ -12,199 +20,4 @@ body { button, input { font-family: inherit; -} - -.app { - display: flex; - min-height: 100vh; - background: #ffffff; -} - -.sidebar { - position: relative; - - width: 250px; - min-width: 100px; - min-height: 110vh; - - border-right: 1px solid #ead5dc; - - background: linear-gradient( - to bottom, - #ffffff 0%, - #fff8fa 100% - ); - - display: flex; - flex-direction: column; -} - -.logo { - height: 200px; - - display: flex; - align-items: center; - justify-content: center; -} - -.logo-mark { - width: 48px; - height: 48px; - - display: flex; - align-items: center; - justify-content: center; - - font-size: 35px; - font-weight: bold; - - color: #7e3450; -} - -.sidebar-menu { - display: flex; - flex-direction: column; -} - -.sidebar-item { - width: 100%; - height: 48px; - - padding: 0 20px; - - display: flex; - align-items: center; - gap: 7px; - - border: none; - background: transparent; - - color: #000000; - font-size: 16px; - - cursor: pointer; -} - -.sidebar-item.active { - background-color: #fff0f4; -} - -.sidebar-item:hover { - background-color: #fff0f4; -} - -.logout-button { - position: absolute; - left: 20px; - bottom: 18px; - - display: flex; - align-items: center; - gap: 7px; - - border: none; - background: transparent; - - color: #501f32; - font-size: 12px; - - cursor: pointer; -} - -.logout-button:hover { - color: #8b3154; -} - -.main-content { - flex: 1; - - padding: 40px 25px 20px 25px; - - min-width: 0; -} - -.page-header { - display: flex; - align-items: center; - justify-content: space-between; - - padding-bottom: 8px; - - border-bottom: 1px solid #e8d6dc; -} - -.page-title { - display: flex; - align-items: center; - gap: 9px; - - color: #4e1d32; -} - -.page-title h1 { - margin: 0; - - font-size: 28px; - font-weight: 400; -} - -.header-actions { - display: flex; - align-items: center; - gap: 8px; -} - -.filter-button { - height: 36px; - - display: flex; - align-items: center; - gap: 5px; - - padding: 0 10px; - - border: 1px solid #e3ccd4; - border-radius: 7px; - - background-color: #ffffff; - color: #4e2635; - - font-size: 11px; - - cursor: pointer; -} - -.filter-button:hover { - background-color: #fff7f9; -} - -.documents-section { - margin-top: 16px; - width: 100%; -} - -@media (max-width: 900px) { - .sidebar { - width: 100px; - min-width: 100px; - } - - .sidebar-item { - padding: 0 12px; - } - - .logout-button { - left: 12px; - } - - .document-item, - .document-header { - grid-template-columns: - 45px - minmax(180px, 1fr) - 80px - 90px - 85px - 85px; - } } \ No newline at end of file diff --git a/src/App.jsx b/src/App.jsx index 9489d1d..2355b3d 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,218 +1,13 @@ -import { useMemo, useState } from "react"; - -import SearchBar from "./components/SearchBar/SearchBar"; -import DocumentList from "./components/Document/DocumentList"; -import Pagination from "./components/Pagination/Pagination"; -import DocumentModal from "./components/Document/DocumentModal"; - -import documents from "./data/documents"; - -import logo from "./assets/AkaerLogo.png"; +import Layout from "./components/Layout/Layout"; +import Home from "./pages/Home"; import "./App.css"; -const DOCUMENTS_PER_PAGE = 10; - function App() { - const [search, setSearch] = useState(""); - const [currentPage, setCurrentPage] = useState(1); - const [selectedDocument, setSelectedDocument] = useState(null); - - const filteredDocuments = useMemo(() => { - return documents.filter((document) => - document.name - .toLowerCase() - .includes(search.toLowerCase()) - ); - }, [search]); - - const totalPages = Math.ceil( - filteredDocuments.length / DOCUMENTS_PER_PAGE - ); - - const validPage = - totalPages === 0 - ? 1 - : Math.min(currentPage, totalPages); - - const firstDocumentIndex = - (validPage - 1) * DOCUMENTS_PER_PAGE; - - const currentDocuments = filteredDocuments.slice( - firstDocumentIndex, - firstDocumentIndex + DOCUMENTS_PER_PAGE - ); - - function handleSearch(value) { - setSearch(value); - setCurrentPage(1); -} - -function handlePageChange(page) { - if (page < 1 || page > totalPages) { - return; - } - - setCurrentPage(page); -} - -function handleViewPdf(document) { - if (document.pdfUrl) { - window.open(document.pdfUrl, "_blank"); - return; - } - - console.log( - "PDF ainda não disponível para o documento:", - document.name - ); -} - -return ( -
- - -
-
-
- - - - - - - - -

Documentos

-
- -
- - - -
-
- -
- - - -
-
- - setSelectedDocument(null)} - onViewPdf={handleViewPdf} - /> -
+ return ( + + + ); } From d84bd0ef38e16075fc80c694f4e9722df7bfa18b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cain=C3=A3=20Melo?= <163151125+CainaNascimentoMelo@users.noreply.github.com> Date: Sat, 12 Sep 2026 12:38:29 -0300 Subject: [PATCH 13/52] rerfactor(8): Refactor Document components --- src/components/Document/DocumentItem.css | 140 +++++++++- src/components/Document/DocumentItem.jsx | 23 +- src/components/Document/DocumentList.css | 37 ++- src/components/Document/DocumentList.jsx | 45 ++-- src/components/Document/DocumentModal.css | 313 ++++++++++++++++------ src/components/Document/DocumentModal.jsx | 63 +++-- 6 files changed, 497 insertions(+), 124 deletions(-) diff --git a/src/components/Document/DocumentItem.css b/src/components/Document/DocumentItem.css index 765f059..80c74bb 100644 --- a/src/components/Document/DocumentItem.css +++ b/src/components/Document/DocumentItem.css @@ -1,80 +1,210 @@ .document-item { display: grid; - grid-template-columns: 55px minmax(220px, 1fr) 100px 100px 100px 95px; + + grid-template-columns: + 55px + minmax(220px, 1fr) + 100px + 100px + 100px + 95px; + align-items: center; + min-height: 70px; + margin-bottom: 7px; + padding: 0 10px; + border: 1px solid #efcbd7; border-radius: 7px; + background-color: #ffffff; + box-shadow: 0 2px 6px rgba(80, 30, 50, 0.08); } .document-file span { display: inline-flex; + align-items: center; justify-content: center; + width: 32px; height: 27px; + border: 2px solid #ff001e; border-radius: 7px; + color: #ff001e; + font-size: 10px; font-weight: 500; } .document-name { padding-right: 19px; + font-size: 14px; line-height: 14px; + color: #000000; } +/*TIPO / SETOR*/ + .document-type span, .document-access span { display: inline-flex; + align-items: center; justify-content: center; + min-width: 65px; - height: 27px; + min-height: 27px; + padding: 0 7px; - border: 2px solid #004196; + border-radius: 7px; - color: #004196; + font-size: 12px; - background-color: #f8fbff; } +/*Técnico*/ + +.type-técnico { + border: 2px solid #003172; + + background-color: #f3f7ff; + + color: #003172; +} + +/*Normativo*/ + +.type-normativo { + border: 2px solid #6e00db; + + background-color: #faf5ff; + + color: #6e00db; +} + +/*Administrativo*/ + +.type-administrativo { + border: 2px solid #31ac00; + + background-color: #f2fbfa; + + color: #31ac00; +} + +/*Caso o tipo venha diferente dos anteriores*/ + +.document-type span:not( + .type-técnico, + .type-normativo, + .type-administrativo +) { + border: 2px solid #41444b; + + background-color: #f7f7f7; + + color:#41444b; +} + +/*DATA*/ + .document-date { font-size: 13px; + color: #000000; } +/*NÍVEL DE ACESSO*/ + +.access-gestor { + border: 2px solid #9b0a00; + + background-color: #fff5f4; + + color: #9b0a00; +} + +.access-usuário { + border: 2px solid #2563eb; + + background-color: #f3f7ff; + + color: #2563eb; +} + +.access-público { + border: 2px solid #d37000; + + background-color: #f2fbfa; + + color: #d37000; +} + +.document-access span:not( + .access-gestor, + .access-usuário, + .access-público +) { + border: 2px solid #6b7280; + + background-color: #f7f7f7; + + color: #4b5563; +} + +/*AÇÃO*/ + .document-action { display: flex; + justify-content: flex-end; } .document-action button { display: flex; + align-items: center; justify-content: center; + gap: 1px; height: 27px; + padding: 0 8px; border: 2px solid #00867b; border-radius: 7px; background-color: #ffffff; + color: #00867b; font-size: 12px; + cursor: pointer; } .document-action button:hover { background-color: #f3f8ff; +} + +@media (max-width: 900px) { + .document-item { + grid-template-columns: + 45px + minmax(180px, 1fr) + 80px + 90px + 85px + 85px; + } } \ No newline at end of file diff --git a/src/components/Document/DocumentItem.jsx b/src/components/Document/DocumentItem.jsx index 1d963ff..4d89fdf 100644 --- a/src/components/Document/DocumentItem.jsx +++ b/src/components/Document/DocumentItem.jsx @@ -1,18 +1,31 @@ import "./DocumentItem.css"; function DocumentItem({ document, onView }) { + const typeClass = document.type + ?.toLowerCase() + .replace(/\s+/g, "-"); + + const accessClass = document.accessLevel + ?.toLowerCase() + .replace(/\s+/g, "-"); + return (
{document.fileType}
-
+
{document.name}
- {document.type} + + {document.type} +
@@ -20,7 +33,11 @@ function DocumentItem({ document, onView }) {
- {document.accessLevel} + + {document.accessLevel} +
diff --git a/src/components/Document/DocumentList.css b/src/components/Document/DocumentList.css index dec9172..bee8c19 100644 --- a/src/components/Document/DocumentList.css +++ b/src/components/Document/DocumentList.css @@ -2,27 +2,60 @@ width: 100%; } +.document-list-header { + width: 100%; + + margin-bottom: 6px; +} + .document-header { display: grid; - grid-template-columns: 125px minmax(220px, 1fr) 100px 100px 100px 100px; + + grid-template-columns: + 55px + minmax(220px, 1fr) + 100px + 100px + 100px + 95px; align-items: center; - height: 30px; + min-height: 30px; + padding: 0 10px; color: #000000; + font-size: 12px; font-weight: 600; } +.document-list-content { + width: 100%; +} + .empty-list { display: flex; + align-items: center; justify-content: center; height: 100px; color: #8d7c83; + font-size: 13px; +} + +@media (max-width: 900px) { + .document-header { + grid-template-columns: + 45px + minmax(180px, 1fr) + 80px + 90px + 85px + 85px; + } } \ No newline at end of file diff --git a/src/components/Document/DocumentList.jsx b/src/components/Document/DocumentList.jsx index 1b447a9..9ee58c5 100644 --- a/src/components/Document/DocumentList.jsx +++ b/src/components/Document/DocumentList.jsx @@ -1,31 +1,36 @@ import DocumentItem from "./DocumentItem"; + import "./DocumentList.css"; function DocumentList({ documents, onView }) { return (
-
-
Arquivo
-
Nome do documento
-
Setor/Tipo
-
Atualizado
-
Nível de Acesso
-
+
+
+
Arquivo
+
Nome do documento
+
Setor/Tipo
+
Atualizado
+
Nível de Acesso
+
+
- {documents.length > 0 ? ( - documents.map((document) => ( - - )) - ) : ( -
- Nenhum documento encontrado. -
- )} +
+ {documents.length > 0 ? ( + documents.map((document) => ( + + )) + ) : ( +
+ Nenhum documento encontrado. +
+ )} +
); } diff --git a/src/components/Document/DocumentModal.css b/src/components/Document/DocumentModal.css index 0a3f96e..29d595c 100644 --- a/src/components/Document/DocumentModal.css +++ b/src/components/Document/DocumentModal.css @@ -1,10 +1,12 @@ .document-modal-overlay { position: fixed; + inset: 0; z-index: 1000; display: flex; + align-items: center; justify-content: center; @@ -14,142 +16,267 @@ } .document-modal { - width: min(550px, 90vw); + width: min(600px, 90vw); - padding: 12px; + max-height: 90vh; + + overflow-y: auto; + + padding: 18px; - border: 1px solid #cba9b5; - border-radius: 20px; + border: 1px solid #d9bec8; + + border-radius: 18px; background: #ffffff; - box-shadow: 0 8px 25px rgba(60, 25, 40, 0.12); + box-shadow: + 0 15px 40px rgba(60, 25, 40, 0.18); } +/*CABEÇALHO*/ + .modal-top { display: flex; + align-items: flex-start; justify-content: space-between; - padding: 0 6px 6px; + padding-bottom: 14px; - border-bottom: 1px solid #d5b9c3; + border-bottom: 1px solid #ead8de; } .modal-code-section { display: flex; + flex-direction: column; + + min-width: 0; } .modal-label { display: block; - margin-bottom: 3px; + margin-bottom: 5px; - font-size: 10px; color: #806d75; + + font-size: 11px; } .modal-code { display: flex; + align-items: center; + gap: 10px; - font-size: 24px; color: #501f35; + + font-size: 23px; + font-weight: 600; + + word-break: break-word; } .modal-pdf-badge { display: inline-flex; + align-items: center; justify-content: center; - width: 65px; - height: 30px; + min-width: 50px; + height: 27px; - border: 1px solid #ff6577; - border-radius: 10px; + padding: 0 8px; - color: #ff6577; + border: 1px solid #c0021c; - font-size: 13px; - font-weight: 500; + border-radius: 8px; + + color: #c0021c; + + font-size: 11px; + font-weight: 600; } .modal-close { - width: 30px; - height: 30px; + width: 32px; + height: 32px; + + flex-shrink: 0; border: none; + + border-radius: 6px; + background: transparent; color: #888888; - font-size: 29px; + font-size: 28px; font-weight: 300; + line-height: 1; + cursor: pointer; } .modal-close:hover { + background: #fff5f7; + color: #4d1d30; } +/*TÍTULO*/ + .modal-title-section { - padding: 7px 6px; + padding: 14px 0; - border-bottom: 1px solid #d5b9c3; + border-bottom: 1px solid #ead8de; } .modal-document-title { margin: 0; - font-size: 11px; - line-height: 17px; color: #3e3438; + + font-size: 13px; + line-height: 19px; } +/*INFORMAÇÕES PRINCIPAIS*/ + .modal-main-info { display: flex; + align-items: flex-end; - gap: 16px; - padding: 8px 6px; + flex-wrap: wrap; + + gap: 14px; + + padding: 16px 0; } .modal-info-group { display: flex; + flex-direction: column; - gap: 3px; + + gap: 5px; } .modal-info-badge { display: inline-flex; + align-items: center; justify-content: center; - min-width: 70px; - height: 30px; + min-width: 80px; + min-height: 30px; padding: 0 10px; - border: 1px solid #a98a98; - border-radius: 9px; + border-radius: 8px; - color: #501f35; + font-size: 12px; +} - font-size: 13px; +/*Técnico*/ - background: #ffffff; +.modal-info-badge.type-técnico { + border: 2px solid #003172; + + background-color: #f3f7ff; + + color: #003172; +} + +/*Normativo*/ + +.modal-info-badge.type-normativo { + border: 2px solid #6e00db; + + background-color: #faf5ff; + + color: #6e00db; +} + +/*Administrativo*/ + +.modal-info-badge.type-administrativo { + border: 2px solid #31ac00; + + background-color: #f2fbfa; + + color: #31ac00; +} + +/*Caso o tipo venha diferente dos anteriores*/ + +.modal-info-badge:not( + .type-técnico, + .type-normativo, + .type-administrativo, + .access-gestor, + .access-usuário, + .access-público +) { + border: 2px solid #41444b; + + background-color: #f7f7f7; + + color: #41444b; +} + +/*NÍVEL DE ACESSO*/ + +.modal-info-badge.access-gestor { + border: 2px solid #9b0a00; + + background-color: #fff5f4; + + color: #9b0a00; +} + +.modal-info-badge.access-usuário { + border: 2px solid #2563eb; + + background-color: #f3f7ff; + + color: #2563eb; +} + +.modal-info-badge.access-público { + border: 2px solid #d37000; + + background-color: #f2fbfa; + + color: #d37000; } +/*CATEGORIA*/ + +.modal-category-badge { + border: 2px solid #b99eaa; + + background-color: #fff7fa; + + color: #501f35; +} + +/*DETALHES*/ + .modal-details { display: grid; + grid-template-columns: 1fr 1fr; - gap: 24px; + gap: 18px; - padding: 5px 6px; + padding-bottom: 16px; } .file-data-section, @@ -160,118 +287,152 @@ .section-title { display: block; - margin-bottom: 5px; + margin-bottom: 7px; + + color: #000000; font-size: 11px; - color: #806d75; } -.file-data-box { - min-height: 128px; +.file-data-box, +.tags-box { + min-height: 130px; + padding: 12px; + + border: 1px solid #d8c2ca; + + border-radius: 9px; + + background: #fffdfd; +} + +.file-data-box { display: flex; + flex-direction: column; - justify-content: space-around; - padding: 8px; + justify-content: space-around; - border: 1px solid #cba9b5; - border-radius: 9px; + gap: 12px; } .file-data-row { display: flex; + align-items: center; justify-content: space-between; gap: 10px; - font-size: 12px; color: #40363a; + + font-size: 12px; } .file-data-row strong { - font-weight: 400; color: #151515; + + font-weight: 600; + + text-align: right; } -.tags-box { - min-height: 128px; +/*TAGS*/ +.tags-box { display: flex; + align-content: flex-start; + flex-wrap: wrap; gap: 7px; - - padding: 8px; - - border: 1px solid #cba9b5; - border-radius: 9px; } .document-tag { - height: 25px; - display: inline-flex; + align-items: center; - padding: 0 8px; + min-height: 25px; + + padding: 0 9px; + + border: 1px solid #dfbdc9; - border: 1px solid #77aeea; border-radius: 12px; - background: #f8fbff; + background: #fff6f8; - color: #1764bc; + color: #713449; - font-size: 10px; + font-size: 12px; } +/*AÇÕES*/ + .modal-actions { display: flex; + justify-content: flex-end; - padding: 15px 6px 8px; + padding-top: 15px; + + border-top: 1px solid #ead8de; } .modal-view-button { display: flex; + align-items: center; - gap: 5px; + justify-content: center; - height: 32px; + gap: 6px; - padding: 0 10px; + min-height: 34px; - border: 1px solid #71a6df; - border-radius: 9px; + padding: 0 13px; - background: #ffffff; + border: 1px solid #6d3048; - color: #275b8d; + border-radius: 8px; - font-size: 13px; + background: #6d3048; - box-shadow: 0 3px 10px rgba(60, 130, 210, 0.22); + color: #ffffff; + + font-size: 12px; + + box-shadow: 0 3px 10px rgba(109, 48, 72, 0.20); cursor: pointer; } .modal-view-button:hover { - background: #f4f9ff; + background: #54243a; + + border-color: #54243a; } +/*RESPONSIVIDADE*/ + @media (max-width: 650px) { + .document-modal { + width: 95vw; + + padding: 14px; + } + + .modal-code { + font-size: 19px; + } + .modal-details { grid-template-columns: 1fr; } .modal-main-info { - flex-wrap: wrap; - } - - .modal-code { - font-size: 20px; + align-items: stretch; } } \ No newline at end of file diff --git a/src/components/Document/DocumentModal.jsx b/src/components/Document/DocumentModal.jsx index f295fc7..ad6b19d 100644 --- a/src/components/Document/DocumentModal.jsx +++ b/src/components/Document/DocumentModal.jsx @@ -14,12 +14,15 @@ function DocumentModal({ document, onClose, onViewPdf }) { ]; return ( -
+
event.stopPropagation()} > -
+
Código da norma @@ -27,7 +30,7 @@ function DocumentModal({ document, onClose, onViewPdf }) {
{document.code || document.name} - + PDF @@ -41,10 +44,9 @@ function DocumentModal({ document, onClose, onViewPdf }) { > × -
+
- {/* TÍTULO */} -
+
Título do arquivo @@ -52,15 +54,25 @@ function DocumentModal({ document, onClose, onViewPdf }) {

{document.name}

-
+ -
+
Setor/Tipo - + {document.type}
@@ -70,7 +82,17 @@ function DocumentModal({ document, onClose, onViewPdf }) { Nível de Acesso - + {document.accessLevel}
@@ -80,13 +102,13 @@ function DocumentModal({ document, onClose, onViewPdf }) { Categoria - + {document.category || document.type}
-
+ -
+
Dados do arquivo @@ -95,6 +117,7 @@ function DocumentModal({ document, onClose, onViewPdf }) {
↻ Revisão: + {document.revision || "5J"} @@ -102,6 +125,7 @@ function DocumentModal({ document, onClose, onViewPdf }) {
◷ Data de Atualização: + {document.updatedAt} @@ -109,6 +133,7 @@ function DocumentModal({ document, onClose, onViewPdf }) {
▤ Tamanho do arquivo: + {document.fileSize || "66.8 MB"} @@ -116,7 +141,6 @@ function DocumentModal({ document, onClose, onViewPdf }) {
- {/* TAGS */}
🏷 Tags @@ -124,15 +148,18 @@ function DocumentModal({ document, onClose, onViewPdf }) {
{tags.map((tag) => ( - + {tag} ))}
-
+
-
+
-
+
); From cd7bc2659fefbeac3fb1d5e194cf20c3e3a10c5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cain=C3=A3=20Melo?= <163151125+CainaNascimentoMelo@users.noreply.github.com> Date: Sat, 12 Sep 2026 12:38:42 -0300 Subject: [PATCH 14/52] refactor(8): Update document access levels and types --- src/data/documents.js | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/src/data/documents.js b/src/data/documents.js index 519c44d..4542470 100644 --- a/src/data/documents.js +++ b/src/data/documents.js @@ -6,7 +6,7 @@ const documents = [ type: "Técnico", category: "MIL-HDBK", updatedAt: "05/05/2004", - accessLevel: "Nível 1", + accessLevel: "Gestor", fileType: "PDF", revision: "5J", fileSize: "66.8 MB", @@ -19,7 +19,7 @@ const documents = [ type: "Técnico", category: "ATA", updatedAt: "08/09/2026", - accessLevel: "Nível 1", + accessLevel: "Usuário", fileType: "PDF", revision: "Rev. 3", fileSize: "8.9 MB", @@ -29,10 +29,10 @@ const documents = [ id: 3, code: "SAE-ARP4761", name: "GUIDELINES AND METHODS FOR CONDUCTING THE SAFETY ASSESSMENT PROCESS ON CIVIL AIRBORNE SYSTEMS AND EQUIPMENT", - type: "Segurança", + type: "Normativo", category: "SAE-ARP", updatedAt: "07/09/2026", - accessLevel: "Nível 2", + accessLevel: "Público", fileType: "PDF", revision: "Original", fileSize: "18.5 MB", @@ -45,7 +45,7 @@ const documents = [ type: "Técnico", category: "NASA-STD", updatedAt: "06/09/2026", - accessLevel: "Nível 1", + accessLevel: "Gestor", fileType: "PDF", revision: "Rev. B", fileSize: "4.8 MB", @@ -55,10 +55,10 @@ const documents = [ id: 5, code: "AS9100D", name: "QUALITY MANAGEMENT SYSTEMS - REQUIREMENTS FOR AVIATION, SPACE AND DEFENSE ORGANIZATIONS", - type: "Qualidade", + type: "Normativo", category: "AS9100", updatedAt: "05/09/2026", - accessLevel: "Nível 1", + accessLevel: "Usuário", fileType: "PDF", revision: "D", fileSize: "5.7 MB", @@ -68,10 +68,10 @@ const documents = [ id: 6, code: "RTCA-DO-178C", name: "SOFTWARE CONSIDERATIONS IN AIRBORNE SYSTEMS AND EQUIPMENT CERTIFICATION", - type: "Software", + type: "Administrativo", category: "RTCA", updatedAt: "04/09/2026", - accessLevel: "Nível 2", + accessLevel: "Gestor", fileType: "PDF", revision: "C", fileSize: "7.2 MB", @@ -81,10 +81,10 @@ const documents = [ id: 7, code: "MIL-HDBK-17-3F", name: "COMPOSITE MATERIALS HANDBOOK: POLYMER MATRIX COMPOSITES", - type: "Materiais", + type: "Técnico", category: "MIL-HDBK", updatedAt: "03/09/2026", - accessLevel: "Nível 1", + accessLevel: "Usuário", fileType: "PDF", revision: "3F", fileSize: "42.3 MB", @@ -94,10 +94,10 @@ const documents = [ id: 8, code: "ASTM-E8", name: "STANDARD TEST METHODS FOR TENSION TESTING OF METALLIC MATERIALS", - type: "Ensaios", + type: "Normativo", category: "ASTM", updatedAt: "02/09/2026", - accessLevel: "Nível 2", + accessLevel: "Público", fileType: "PDF", revision: "2022", fileSize: "1.9 MB", @@ -107,10 +107,10 @@ const documents = [ id: 9, code: "NASA-STD-5009", name: "NONDESTRUCTIVE EVALUATION REQUIREMENTS FOR FRACTURE CONTROL PROGRAMS", - type: "Inspeção", + type: "Técnico", category: "NASA-STD", updatedAt: "01/09/2026", - accessLevel: "Nível 1", + accessLevel: "Gestor", fileType: "PDF", revision: "Rev. A", fileSize: "2.7 MB", @@ -120,10 +120,10 @@ const documents = [ id: 10, code: "SAE-ARP4754A", name: "GUIDELINES FOR DEVELOPMENT OF CIVIL AIRCRAFT AND SYSTEMS", - type: "Engenharia", + type: "Normativo", category: "SAE-ARP", updatedAt: "30/08/2026", - accessLevel: "Nível 2", + accessLevel: "Usuário", fileType: "PDF", revision: "A", fileSize: "9.6 MB", @@ -133,10 +133,10 @@ const documents = [ id: 11, code: "RTCA-DO-254", name: "DESIGN ASSURANCE GUIDANCE FOR AIRBORNE ELECTRONIC HARDWARE", - type: "Eletrônica", + type: "Administrativo", category: "RTCA", updatedAt: "29/08/2026", - accessLevel: "Nível 1", + accessLevel: "Gestor", fileType: "PDF", revision: "A", fileSize: "6.4 MB", @@ -146,10 +146,10 @@ const documents = [ id: 12, code: "ASTM-E290", name: "STANDARD TEST METHODS FOR BEND TESTING OF MATERIALS FOR DUCTILITY", - type: "Ensaios", + type: "Normativo", category: "ASTM", updatedAt: "28/08/2026", - accessLevel: "Nível 1", + accessLevel: "Público", fileType: "PDF", revision: "2021", fileSize: "1.4 MB", From a540000b2d839fc3050298cf36b13084f9a7f3d1 Mon Sep 17 00:00:00 2001 From: gabrielvascf Date: Tue, 15 Sep 2026 01:07:42 -0300 Subject: [PATCH 15/52] fix(22): change ci permissions to allow sonar comments on PRs --- .github/workflows/ci-frontend.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/ci-frontend.yml b/.github/workflows/ci-frontend.yml index 966007c..7d48809 100644 --- a/.github/workflows/ci-frontend.yml +++ b/.github/workflows/ci-frontend.yml @@ -14,6 +14,7 @@ on: permissions: contents: read + pull-requests: write concurrency: group: frontend-ci-${{ github.workflow }}-${{ github.ref }} @@ -52,6 +53,7 @@ jobs: needs: commit-build env: SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: - name: Checkout do código @@ -64,6 +66,7 @@ jobs: uses: SonarSource/sonarqube-scan-action@7006c4492b2e0ee0f816d36501671557c97f5995 # v8.1.0 env: SONAR_TOKEN: ${{ env.SONAR_TOKEN }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Informar ausência do token do SonarCloud if: env.SONAR_TOKEN == '' From 47ae47c386582a32fed2bae60c841cc37983624a Mon Sep 17 00:00:00 2001 From: gabrielvascf Date: Tue, 15 Sep 2026 01:11:42 -0300 Subject: [PATCH 16/52] fix(22): change ci write permission to sonar job level --- .github/workflows/ci-frontend.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci-frontend.yml b/.github/workflows/ci-frontend.yml index 7d48809..a080e30 100644 --- a/.github/workflows/ci-frontend.yml +++ b/.github/workflows/ci-frontend.yml @@ -14,7 +14,6 @@ on: permissions: contents: read - pull-requests: write concurrency: group: frontend-ci-${{ github.workflow }}-${{ github.ref }} @@ -51,6 +50,9 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 10 needs: commit-build + permissions: + contents: read + pull-requests: write env: SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From 5c84c4461bb7998f49438c81c67cd9a37ba1696a Mon Sep 17 00:00:00 2001 From: gabrielvascf Date: Tue, 15 Sep 2026 01:19:14 -0300 Subject: [PATCH 17/52] fix(22): revert ci write permission and change sonar.sources to analyze only the application. --- .github/workflows/ci-frontend.yml | 4 +--- sonar-project.properties | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci-frontend.yml b/.github/workflows/ci-frontend.yml index a080e30..7d48809 100644 --- a/.github/workflows/ci-frontend.yml +++ b/.github/workflows/ci-frontend.yml @@ -14,6 +14,7 @@ on: permissions: contents: read + pull-requests: write concurrency: group: frontend-ci-${{ github.workflow }}-${{ github.ref }} @@ -50,9 +51,6 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 10 needs: commit-build - permissions: - contents: read - pull-requests: write env: SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/sonar-project.properties b/sonar-project.properties index 1ce073e..4ea4ba3 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -8,7 +8,7 @@ sonar.projectVersion=1.0 # Path is relative to the sonar-project.properties file. Replace "\" by "/" on Windows. -sonar.sources=. +sonar.sources=src # Encoding of the source code. Default is default system encoding sonar.sourceEncoding=UTF-8 From 2939b6dbda54092295612cb397ffa22c356d3453 Mon Sep 17 00:00:00 2001 From: gabrielvascf Date: Tue, 15 Sep 2026 01:23:20 -0300 Subject: [PATCH 18/52] fix(22): update sonar.organization to match current org --- sonar-project.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sonar-project.properties b/sonar-project.properties index 4ea4ba3..07db20a 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -1,5 +1,5 @@ -sonar.projectKey=sqlutionsfatec_analysis-frontend -sonar.organization=sqlutionsfatec +sonar.projectKey=SQLutionsFATEC_API-6-Semestre-Frontend +sonar.organization=sqlutionsfatec-2 # This is the name and version displayed in the SonarCloud UI. From 8060a578434889599b0a0ec5fc420937d2a99a75 Mon Sep 17 00:00:00 2001 From: CainaNascimentoMelo Date: Wed, 16 Sep 2026 21:47:11 -0300 Subject: [PATCH 19/52] feat(4): Add back front integration for DocumentList and Home --- src/components/Document/DocumentItem.jsx | 34 +++--- src/pages/Home.jsx | 148 +++++++++-------------- 2 files changed, 78 insertions(+), 104 deletions(-) diff --git a/src/components/Document/DocumentItem.jsx b/src/components/Document/DocumentItem.jsx index 4d89fdf..c4e695c 100644 --- a/src/components/Document/DocumentItem.jsx +++ b/src/components/Document/DocumentItem.jsx @@ -1,5 +1,18 @@ import "./DocumentItem.css"; +function formatarData(dataISO) { + if (!dataISO) return "-"; + + const data = new Date(dataISO); + if (isNaN(data.getTime())) return dataISO; + + return data.toLocaleDateString("pt-BR", { + day: "2-digit", + month: "2-digit", + year: "numeric", + }); +} + function DocumentItem({ document, onView }) { const typeClass = document.type ?.toLowerCase() @@ -12,31 +25,26 @@ function DocumentItem({ document, onView }) { return (
- {document.fileType} + {document.tipo_arquivo}
-
- {document.name} +
+ {document.nome}
- {document.type} + {document.setor}
- {document.updatedAt} + {formatarData(document.data_atualizacao)}
- - {document.accessLevel} + + {document.nivel}
@@ -54,7 +62,6 @@ function DocumentItem({ document, onView }) { stroke="currentColor" strokeWidth="1.8" /> - - Visualizar
diff --git a/src/pages/Home.jsx b/src/pages/Home.jsx index d6c4c21..358fc11 100644 --- a/src/pages/Home.jsx +++ b/src/pages/Home.jsx @@ -1,56 +1,57 @@ -import { useMemo, useState } from "react"; +import { useEffect, useState } from "react"; import SearchBar from "../components/SearchBar/SearchBar"; import DocumentList from "../components/Document/DocumentList"; import Pagination from "../components/Pagination/Pagination"; import DocumentModal from "../components/Document/DocumentModal"; -import documents from "../data/documents"; +import { fetchDocuments } from "../services/documentService"; import "./Home.css"; -const DOCUMENTS_PER_PAGE = 10; - function Home() { const [search, setSearch] = useState(""); + const [documents, setDocuments] = useState([]); + const [totalPages, setTotalPages] = useState(1); const [currentPage, setCurrentPage] = useState(1); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(null); const [selectedDocument, setSelectedDocument] = useState(null); - const filteredDocuments = useMemo(() => { - return documents.filter((document) => - document.name - .toLowerCase() - .includes(search.toLowerCase()) - ); - }, [search]); - - const totalPages = Math.ceil( - filteredDocuments.length / DOCUMENTS_PER_PAGE - ); - - const validPage = - totalPages === 0 - ? 1 - : Math.min(currentPage, totalPages); - - const firstDocumentIndex = - (validPage - 1) * DOCUMENTS_PER_PAGE; - - const currentDocuments = filteredDocuments.slice( - firstDocumentIndex, - firstDocumentIndex + DOCUMENTS_PER_PAGE - ); + useEffect(() => { + const timer = setTimeout(async () => { + setLoading(true); + setError(null); + + try { + const data = await fetchDocuments({ + nome: search, + page: currentPage, + }); + console.log(data); + + setDocuments(data.results || []); + setTotalPages(data.pages || 1); + } catch (err) { + console.error("Erro ao buscar documentos:", err); + setError("Não foi possível carregar os documentos."); + setDocuments([]); + setTotalPages(1); + } finally { + setLoading(false); + } + }, 400); + + return () => clearTimeout(timer); + }, [search, currentPage]); function handleSearch(value) { setSearch(value); - setCurrentPage(1); + setCurrentPage(1); } function handlePageChange(page) { - if (page < 1 || page > totalPages) { - return; - } - + if (page < 1 || page > totalPages) return; setCurrentPage(page); } @@ -59,82 +60,49 @@ function Home() { window.open(document.pdfUrl, "_blank"); return; } - - console.log( - "PDF ainda não disponível para o documento:", - document.name - ); + console.log("PDF ainda não disponível:", document.nome); } return (
- - - - - - + + + + -

Documentos

- - +
- - - + {loading &&

Carregando documentos...

} + {error &&

{error}

} + + {!loading && !error && ( + <> + + + + )}
Date: Wed, 16 Sep 2026 21:48:12 -0300 Subject: [PATCH 20/52] feat(4): Add axios and documentService --- src/services/api.js | 8 ++++++++ src/services/documentService.js | 12 ++++++++++++ 2 files changed, 20 insertions(+) create mode 100644 src/services/api.js create mode 100644 src/services/documentService.js diff --git a/src/services/api.js b/src/services/api.js new file mode 100644 index 0000000..2a0f198 --- /dev/null +++ b/src/services/api.js @@ -0,0 +1,8 @@ + +import axios from 'axios'; + +const api = axios.create({ + baseURL: import.meta.env.VITE_API_URL || 'http://localhost:8000', +}); + +export default api; \ No newline at end of file diff --git a/src/services/documentService.js b/src/services/documentService.js new file mode 100644 index 0000000..469ecf6 --- /dev/null +++ b/src/services/documentService.js @@ -0,0 +1,12 @@ +import api from "./api"; + +export async function fetchDocuments({ nome = "", page = 1 } = {}) { + const response = await api.get("/api/documentos/", { + params: { + nome: nome, + page: page, + }, + }); + + return response.data; +} \ No newline at end of file From ebb0d2fb7351c5318f8fee2282c8fba7a569ace3 Mon Sep 17 00:00:00 2001 From: CainaNascimentoMelo Date: Wed, 16 Sep 2026 21:54:13 -0300 Subject: [PATCH 21/52] feat(4): Add axios in package.json --- package-lock.json | 311 +++++++++++++++++++++++++++++++++++++++++++++- package.json | 1 + 2 files changed, 310 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 47c0342..d0c88a4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,7 @@ "name": "iaazimmute", "version": "0.0.0", "dependencies": { + "axios": "^1.20.0", "react": "^19.2.8", "react-dom": "^19.2.8" }, @@ -921,6 +922,18 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "license": "MIT", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, "node_modules/ajv": { "version": "6.15.0", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", @@ -938,6 +951,24 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, + "node_modules/axios": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.20.0.tgz", + "integrity": "sha512-r8aOh8j9cGKpgQAqpzrUHnSIc6a59Y3Xf/cv8sy1DrHCkZHzQGEuoq1tARk6qSyDdtQGSDgpb9kFlruzPvrgwg==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.16.0", + "form-data": "^4.0.6", + "https-proxy-agent": "^5.0.1", + "proxy-from-env": "^2.1.0" + } + }, "node_modules/balanced-match": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", @@ -1022,6 +1053,19 @@ "qified": "^0.10.1" } }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/caniuse-lite": { "version": "1.0.30001810", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001810.tgz", @@ -1043,6 +1087,18 @@ ], "license": "CC-BY-4.0" }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/convert-source-map": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", @@ -1076,7 +1132,6 @@ "version": "4.4.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -1097,6 +1152,15 @@ "dev": true, "license": "MIT" }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/detect-libc": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", @@ -1107,6 +1171,20 @@ "node": ">=8" } }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/electron-to-chromium": { "version": "1.5.422", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.422.tgz", @@ -1114,6 +1192,51 @@ "dev": true, "license": "ISC" }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", + "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/escalade": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", @@ -1407,6 +1530,42 @@ "dev": true, "license": "ISC" }, + "node_modules/follow-redirects": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.0.tgz", + "integrity": "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.6.tgz", + "integrity": "sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.4", + "mime-types": "^2.1.35" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -1422,6 +1581,15 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -1432,6 +1600,43 @@ "node": ">=6.9.0" } }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", @@ -1458,6 +1663,45 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/hashery": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/hashery/-/hashery-1.5.1.tgz", @@ -1471,6 +1715,18 @@ "node": ">=20" } }, + "node_modules/hasown": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/hermes-estree": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.25.1.tgz", @@ -1495,6 +1751,19 @@ "dev": true, "license": "MIT" }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "license": "MIT", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", @@ -1903,6 +2172,36 @@ "yallist": "^3.0.2" } }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/minimatch": { "version": "10.2.6", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz", @@ -1923,7 +2222,6 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, "license": "MIT" }, "node_modules/nanoid": { @@ -2091,6 +2389,15 @@ "node": ">= 0.8.0" } }, + "node_modules/proxy-from-env": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz", + "integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", diff --git a/package.json b/package.json index 6af50bd..94c5129 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "preview": "vite preview" }, "dependencies": { + "axios": "^1.20.0", "react": "^19.2.8", "react-dom": "^19.2.8" }, From 394e385a1f43da40bf177889f7041bfe336d232a Mon Sep 17 00:00:00 2001 From: CainaNascimentoMelo Date: Wed, 16 Sep 2026 22:06:25 -0300 Subject: [PATCH 22/52] feat(4): Add DocumentList and Home tests --- src/tests/coverage/DocumentoList.test.jsx | 58 +++++++++ src/tests/coverage/Home.test.jsx | 152 ++++++++++++++++++++++ 2 files changed, 210 insertions(+) create mode 100644 src/tests/coverage/DocumentoList.test.jsx create mode 100644 src/tests/coverage/Home.test.jsx diff --git a/src/tests/coverage/DocumentoList.test.jsx b/src/tests/coverage/DocumentoList.test.jsx new file mode 100644 index 0000000..ed82aa7 --- /dev/null +++ b/src/tests/coverage/DocumentoList.test.jsx @@ -0,0 +1,58 @@ +import { render, screen } from "@testing-library/react"; +import userEvent from "@testing-library/user-event"; +import { describe, expect, it, vi } from "vitest"; + +import DocumentList from "./DocumentList"; + +vi.mock("./DocumentItem", () => ({ + default: ({ document, onView }) => ( +
+ {document.name} + +
+ ), +})); + +describe("DocumentList", () => { + it("renderiza os cabeçalhos da lista", () => { + render(); + + expect(screen.getByText("Arquivo")).toBeInTheDocument(); + expect(screen.getByText("Nome do documento")).toBeInTheDocument(); + expect(screen.getByText("Setor/Tipo")).toBeInTheDocument(); + expect(screen.getByText("Atualizado")).toBeInTheDocument(); + expect(screen.getByText("Nível de Acesso")).toBeInTheDocument(); + }); + + it("renderiza os documentos recebidos", () => { + const documents = [ + { id: 1, name: "Documento 1" }, + { id: 2, name: "Documento 2" }, + ]; + + render(); + + expect(screen.getAllByTestId("document-item")).toHaveLength(2); + expect(screen.getByText("Documento 1")).toBeInTheDocument(); + expect(screen.getByText("Documento 2")).toBeInTheDocument(); + }); + + it("exibe mensagem quando não existem documentos", () => { + render(); + + expect( + screen.getByText("Nenhum documento encontrado.") + ).toBeInTheDocument(); + }); + + it("chama onView ao visualizar um documento", async () => { + const onView = vi.fn(); + const document = { id: 1, name: "Documento 1" }; + + render(); + + await userEvent.click(screen.getByRole("button", { name: "Visualizar" })); + + expect(onView).toHaveBeenCalledWith(document); + }); +}); \ No newline at end of file diff --git a/src/tests/coverage/Home.test.jsx b/src/tests/coverage/Home.test.jsx new file mode 100644 index 0000000..e123c46 --- /dev/null +++ b/src/tests/coverage/Home.test.jsx @@ -0,0 +1,152 @@ +import { act, fireEvent, render, screen } from "@testing-library/react"; +import { beforeEach, describe, expect, it, vi } from "vitest"; + +import Home from "./Home"; +import { fetchDocuments } from "../services/documentService"; + +vi.mock("../services/documentService", () => ({ + fetchDocuments: vi.fn(), +})); + +vi.mock("../components/SearchBar/SearchBar", () => ({ + default: ({ value, onChange }) => ( + onChange(event.target.value)} + /> + ), +})); + +vi.mock("../components/Document/DocumentList", () => ({ + default: ({ documents, onView }) => ( +
+ {documents.map((document) => ( + + ))} +
+ ), +})); + +vi.mock("../components/Pagination/Pagination", () => ({ + default: ({ currentPage, totalPages, onPageChange }) => ( + + ), +})); + +vi.mock("../components/Document/DocumentModal", () => ({ + default: ({ document, onViewPdf }) => + document ? ( + + ) : null, +})); + +describe("Home", () => { + beforeEach(() => { + vi.useFakeTimers(); + vi.clearAllMocks(); + }); + + it("carrega e exibe os documentos", async () => { + fetchDocuments.mockResolvedValue({ + results: [{ id: 1, nome: "Documento 1" }], + pages: 2, + }); + + render(); + + expect(screen.getByText("Carregando documentos...")).toBeInTheDocument(); + + await act(async () => { + await vi.advanceTimersByTimeAsync(400); + }); + + expect(fetchDocuments).toHaveBeenCalledWith({ + nome: "", + page: 1, + }); + expect(screen.getByText("Documento 1")).toBeInTheDocument(); + expect(screen.getByLabelText("Próxima página")).toBeEnabled(); + }); + + it("exibe mensagem de erro quando a busca falha", async () => { + fetchDocuments.mockRejectedValue(new Error("Erro na API")); + + render(); + + await act(async () => { + await vi.advanceTimersByTimeAsync(400); + }); + + expect( + screen.getByText("Não foi possível carregar os documentos.") + ).toBeInTheDocument(); + }); + + it("realiza uma nova busca ao alterar o texto", async () => { + fetchDocuments.mockResolvedValue({ + results: [], + pages: 1, + }); + + render(); + + await act(async () => { + await vi.advanceTimersByTimeAsync(400); + }); + + fireEvent.change(screen.getByLabelText("Pesquisar"), { + target: { value: "relatório" }, + }); + + await act(async () => { + await vi.advanceTimersByTimeAsync(400); + }); + + expect(fetchDocuments).toHaveBeenLastCalledWith({ + nome: "relatório", + page: 1, + }); + }); + + it("abre o PDF do documento selecionado", async () => { + const windowOpen = vi + .spyOn(window, "open") + .mockImplementation(() => null); + + fetchDocuments.mockResolvedValue({ + results: [ + { + id: 1, + nome: "Documento 1", + pdfUrl: "https://exemplo.com/documento.pdf", + }, + ], + pages: 1, + }); + + render(); + + await act(async () => { + await vi.advanceTimersByTimeAsync(400); + }); + + fireEvent.click(screen.getByText("Documento 1")); + fireEvent.click(screen.getByText("Abrir PDF")); + + expect(windowOpen).toHaveBeenCalledWith( + "https://exemplo.com/documento.pdf", + "_blank" + ); + + windowOpen.mockRestore(); + }); +}); \ No newline at end of file From d1bce1f89109418c04ce843ba2f37b75d1486da9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cain=C3=A3=20Melo?= <163151125+CainaNascimentoMelo@users.noreply.github.com> Date: Wed, 16 Sep 2026 22:40:04 -0300 Subject: [PATCH 23/52] fix(4): Correct NaN error --- src/components/Document/DocumentItem.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Document/DocumentItem.jsx b/src/components/Document/DocumentItem.jsx index c4e695c..b230ecc 100644 --- a/src/components/Document/DocumentItem.jsx +++ b/src/components/Document/DocumentItem.jsx @@ -4,7 +4,7 @@ function formatarData(dataISO) { if (!dataISO) return "-"; const data = new Date(dataISO); - if (isNaN(data.getTime())) return dataISO; + if (Number.isNaN(data.getTime())) return dataISO; return data.toLocaleDateString("pt-BR", { day: "2-digit", From a05f552cb50393ca26ad2f30e03fb6a583197dc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cain=C3=A3=20Melo?= <163151125+CainaNascimentoMelo@users.noreply.github.com> Date: Wed, 16 Sep 2026 22:46:18 -0300 Subject: [PATCH 24/52] style(4): Sort Documents and Home respective folders --- src/components/Document/{ => DocumentItem}/DocumentItem.css | 0 src/components/Document/{ => DocumentItem}/DocumentItem.jsx | 0 src/components/Document/{ => DocumentList}/DocumentList.css | 0 src/components/Document/{ => DocumentList}/DocumentList.jsx | 0 .../Document/{ => DocumentModal}/DocumentModal.css | 0 .../Document/{ => DocumentModal}/DocumentModal.jsx | 0 src/pages/{ => Home}/Home.css | 0 src/pages/{ => Home}/Home.jsx | 6 +++--- 8 files changed, 3 insertions(+), 3 deletions(-) rename src/components/Document/{ => DocumentItem}/DocumentItem.css (100%) rename src/components/Document/{ => DocumentItem}/DocumentItem.jsx (100%) rename src/components/Document/{ => DocumentList}/DocumentList.css (100%) rename src/components/Document/{ => DocumentList}/DocumentList.jsx (100%) rename src/components/Document/{ => DocumentModal}/DocumentModal.css (100%) rename src/components/Document/{ => DocumentModal}/DocumentModal.jsx (100%) rename src/pages/{ => Home}/Home.css (100%) rename src/pages/{ => Home}/Home.jsx (94%) diff --git a/src/components/Document/DocumentItem.css b/src/components/Document/DocumentItem/DocumentItem.css similarity index 100% rename from src/components/Document/DocumentItem.css rename to src/components/Document/DocumentItem/DocumentItem.css diff --git a/src/components/Document/DocumentItem.jsx b/src/components/Document/DocumentItem/DocumentItem.jsx similarity index 100% rename from src/components/Document/DocumentItem.jsx rename to src/components/Document/DocumentItem/DocumentItem.jsx diff --git a/src/components/Document/DocumentList.css b/src/components/Document/DocumentList/DocumentList.css similarity index 100% rename from src/components/Document/DocumentList.css rename to src/components/Document/DocumentList/DocumentList.css diff --git a/src/components/Document/DocumentList.jsx b/src/components/Document/DocumentList/DocumentList.jsx similarity index 100% rename from src/components/Document/DocumentList.jsx rename to src/components/Document/DocumentList/DocumentList.jsx diff --git a/src/components/Document/DocumentModal.css b/src/components/Document/DocumentModal/DocumentModal.css similarity index 100% rename from src/components/Document/DocumentModal.css rename to src/components/Document/DocumentModal/DocumentModal.css diff --git a/src/components/Document/DocumentModal.jsx b/src/components/Document/DocumentModal/DocumentModal.jsx similarity index 100% rename from src/components/Document/DocumentModal.jsx rename to src/components/Document/DocumentModal/DocumentModal.jsx diff --git a/src/pages/Home.css b/src/pages/Home/Home.css similarity index 100% rename from src/pages/Home.css rename to src/pages/Home/Home.css diff --git a/src/pages/Home.jsx b/src/pages/Home/Home.jsx similarity index 94% rename from src/pages/Home.jsx rename to src/pages/Home/Home.jsx index 358fc11..d94ab79 100644 --- a/src/pages/Home.jsx +++ b/src/pages/Home/Home.jsx @@ -1,11 +1,11 @@ import { useEffect, useState } from "react"; -import SearchBar from "../components/SearchBar/SearchBar"; +import SearchBar from "../../components/SearchBar/SearchBar"; import DocumentList from "../components/Document/DocumentList"; -import Pagination from "../components/Pagination/Pagination"; +import Pagination from "../../components/Pagination/Pagination"; import DocumentModal from "../components/Document/DocumentModal"; -import { fetchDocuments } from "../services/documentService"; +import { fetchDocuments } from "../../services/documentService"; import "./Home.css"; From e875431df4187aabe3aefcd36e6325aea4b75d8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cain=C3=A3=20Melo?= <163151125+CainaNascimentoMelo@users.noreply.github.com> Date: Wed, 16 Sep 2026 23:14:38 -0300 Subject: [PATCH 25/52] feat(4): Add react-icons dependency --- package-lock.json | 258 ++++++++++++++++++++++++---------------------- package.json | 3 +- 2 files changed, 136 insertions(+), 125 deletions(-) diff --git a/package-lock.json b/package-lock.json index d0c88a4..e9d706c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,8 @@ "dependencies": { "axios": "^1.20.0", "react": "^19.2.8", - "react-dom": "^19.2.8" + "react-dom": "^19.2.8", + "react-icons": "^5.7.0" }, "devDependencies": { "@eslint/js": "^10.0.1", @@ -557,9 +558,9 @@ "license": "MIT" }, "node_modules/@oxc-project/types": { - "version": "0.148.0", - "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.148.0.tgz", - "integrity": "sha512-Nm4s/jB+4FpFsPhWGEC4h7rzksesmtnMXomo6rCMcg/b8zLQuOziRgkCS1fxDCXOlJB/6Q8oABOZ/OP6RIPj9A==", + "version": "0.150.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.150.0.tgz", + "integrity": "sha512-rDS5/31E9HfPl/CIzGrn0DOlvBbXFseQ5URJ9sYMfstbKLD/c6Gm9vmRzRGDdAXyOIL4zmO37lc9RIwYqVruZw==", "dev": true, "license": "MIT", "funding": { @@ -567,9 +568,9 @@ } }, "node_modules/@rolldown/binding-android-arm-eabi": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm-eabi/-/binding-android-arm-eabi-1.2.7.tgz", - "integrity": "sha512-EypzgnYCwyVY4NDHKzGmNJT5b+XaQEBniHxsMdeIQLB/tcCzZnhqrzHpZFbX9iaxx+5RiB8caATBtfvZP7zVxQ==", + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm-eabi/-/binding-android-arm-eabi-1.2.9.tgz", + "integrity": "sha512-tNISae1QEf/vkb3xkRcjV5SEdzPE97We5IVaa2Z8jSszQPZ8U60B/YCYpw4QI7VidYsBtKavczXf+DyDs9WGxw==", "cpu": [ "arm" ], @@ -584,9 +585,9 @@ } }, "node_modules/@rolldown/binding-android-arm64": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.7.tgz", - "integrity": "sha512-l17HE9EweWaqJZhuUuNBN/FzM62xw+DECVnJyvMsxn8vJFAGLy5QfLDoYAcronkAN8VxKZHezDpulHDPx95vFw==", + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.9.tgz", + "integrity": "sha512-YC8YsI30o606GTZi0VyzYlsDKFP8W61i/QzayHDkLbNEz/IShqAmTa+hsJRj13xTHA0H+6fk4b2UmGn+Q/cMlg==", "cpu": [ "arm64" ], @@ -601,9 +602,9 @@ } }, "node_modules/@rolldown/binding-darwin-arm64": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.7.tgz", - "integrity": "sha512-8ED8ELFvHXc6OCETIn4gXObPiaR6bckM/ipXtbzlPVDRMBfEGjCKgO90F9YtfdpDatVx/ZQw7aZ1vUMf/+T3Mw==", + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.9.tgz", + "integrity": "sha512-IwhlH3qK5urrY8hZiEgGkHKEFN901p/p2bjxCxJlr4GyNnF7wYpUvK+Y43uaRYuC4hpfjzbR3SJC3arX1jGvmw==", "cpu": [ "arm64" ], @@ -618,9 +619,9 @@ } }, "node_modules/@rolldown/binding-darwin-x64": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.7.tgz", - "integrity": "sha512-/WPripjtiAIZ2tWY7ddijORT0Ujg87wxWW/qcoFVCKAWVDPhtY0xr7Dj0M3GyNGz60jGwTElhro/mkF9dT7dDQ==", + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.9.tgz", + "integrity": "sha512-XxpJfVzFh+jilRxIXUqcfYAYcunIc/XEzIizsOL1fcJee5Sf7H3mH8WlLmfHfluz5amqR88QQo9izKtmMlavAw==", "cpu": [ "x64" ], @@ -635,9 +636,9 @@ } }, "node_modules/@rolldown/binding-freebsd-x64": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.7.tgz", - "integrity": "sha512-14DI4NcqpvbICxSnGLx3PmtDaWqRP/KGSGb6C+JLLVPeZRl6dKdHba3pGsqT3vpdTqhEYIPG0MMQ8c0xYqoJxA==", + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.9.tgz", + "integrity": "sha512-kSfvhmgeWyfkbT3p/1s5vSgboogoah2zkm9fX2zjg2hHxSV7T4KhMWRUUaRk4OXNqoD3QAUeRqLcs1aZOK4U1g==", "cpu": [ "x64" ], @@ -652,9 +653,9 @@ } }, "node_modules/@rolldown/binding-linux-arm-gnueabihf": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.7.tgz", - "integrity": "sha512-bxrWIRvHWQvbJwi+VIie/kDJmQxcNE6xxWwZdqF/ExVAigtHkv54WTLQPb+QsZdnFy18fg7JPfWGL0RH6vwIlQ==", + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.9.tgz", + "integrity": "sha512-1RVzG17pxqbTfYLC352JlLt6kKLG+6Hr30n8DlIJqsnV5luUDd2Qdx9Ayw1Cabfyb1K9k0jXEZ7evxkRoT+uiw==", "cpu": [ "arm" ], @@ -669,9 +670,9 @@ } }, "node_modules/@rolldown/binding-linux-arm64-gnu": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.7.tgz", - "integrity": "sha512-toOY2BChBZyuxU7OYX6Tn389di4IzAqPTycVcci0O7FSfBqzRB3RZn+K5Is6ANf4tmgRd/K1yZTsNTXbkXsnLg==", + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.9.tgz", + "integrity": "sha512-BXqPvZ2drqVD+/Z8UpKwcs4Mp7grM+eGFku4CAEKrEtcbAsUpzREphK1sogCRZGreVPiMkiiBtw0n3TPteuqvw==", "cpu": [ "arm64" ], @@ -686,9 +687,9 @@ } }, "node_modules/@rolldown/binding-linux-arm64-musl": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.7.tgz", - "integrity": "sha512-lAIXTH/aiLRLxsTgQvfhjo4K1ydWIp00+V0voOr9beb/9ZmkUFrSIb03dXNFRgMNvkE6oGsF10ioQ6UsI+vS5Q==", + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.9.tgz", + "integrity": "sha512-11vWvo8YDwLzukt27J3aYDWU+gg2P7J+ZOmiJ0hkF5BXZDW7pVya7r40MXDy6ya0i9KamoENSVKIugvJNgFXIA==", "cpu": [ "arm64" ], @@ -703,9 +704,9 @@ } }, "node_modules/@rolldown/binding-linux-ppc64-gnu": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.7.tgz", - "integrity": "sha512-kdnwS28Pkenp/mZMRwjXXXwxQ7pIsm+bF919LUK93BOyhcLsrVKdP2p9fxpiPNPAbNuch8ypQt0pm2P2LYCAGg==", + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.9.tgz", + "integrity": "sha512-a1tijMkdwsIARtc0F39ApURROkf3NwqinI6TOiSSWCTR7dT96dffNvMUtDHnq64wKNTIZOIlzKrFvvFUznJiyw==", "cpu": [ "ppc64" ], @@ -720,9 +721,9 @@ } }, "node_modules/@rolldown/binding-linux-s390x-gnu": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.7.tgz", - "integrity": "sha512-516OdsyLdr5E65paF3yBF55t8mfm9+gmtCsK3xI7XKXIT7EfRlHhxL8K/NR6Hu8BWSgF5+1w74lTL0+nxcc8Qw==", + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.9.tgz", + "integrity": "sha512-x6SQNdAvv4c3hWqTMaWuawzMX9myaCs/yEmlGsxJzkdClnHW7FbrjQuSiRDhuSYzEYoEMhsaJy9qHG/XNemJPQ==", "cpu": [ "s390x" ], @@ -737,9 +738,9 @@ } }, "node_modules/@rolldown/binding-linux-x64-gnu": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.7.tgz", - "integrity": "sha512-r8/z8n7GFaYRln3xmP1Cxy0HH/HLM0uBUPkEuSVEfKGDA89M0FsZRZJRSwe/tJjRx+fpH/gjorfhB8tmEbSFLA==", + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.9.tgz", + "integrity": "sha512-9s0AZ8BFK5/n7B/TBoa2yJE3gI3KURrbXcPBlsAsvjU4VeJKgE90y1YtNxyEUIcHPQkg6/yfF3qihUrcM/Kf0Q==", "cpu": [ "x64" ], @@ -754,9 +755,9 @@ } }, "node_modules/@rolldown/binding-linux-x64-musl": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.7.tgz", - "integrity": "sha512-pAsE8iiDxUg1xBqdhrTfg45AVDVpirjz00sblEYClGNNcMnDb+e8beQgqIAw6LvauX/APvgxUnwrgun/YYGBhw==", + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.9.tgz", + "integrity": "sha512-P7VWAmV+WdJluH7ovnRGoiv2i8To7GAZ+kGzfGup635cyL7SyYl3lSUaA3Gp5THf0n/Co5EyEqb2zbqq+nMOHQ==", "cpu": [ "x64" ], @@ -771,9 +772,9 @@ } }, "node_modules/@rolldown/binding-openharmony-arm64": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.7.tgz", - "integrity": "sha512-lTcIYmmnQQA8Or/2DatS6oSqcdLHvendjS+zLu+FwgToynWMRSmQdpM65fTANJgIS4mjbMOo5KT2lnT9SAb96w==", + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.9.tgz", + "integrity": "sha512-1qixtsE4BK8h+yS3BfmZ09UhA7O/N4IACva6YBr7EBvCJraByTuRcgOTaiA62Tm0vey3UcKXLOaoGHtYmNGEVg==", "cpu": [ "arm64" ], @@ -788,9 +789,9 @@ } }, "node_modules/@rolldown/binding-win32-arm64-msvc": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.7.tgz", - "integrity": "sha512-e3Gu3WxbNk/UqQhxqU7YIYO+9ZBvWNz3U+h/qRFosscMFzdRPbXYSaSWgSnklv2fz1TgzBTcti2z35c/7irsHw==", + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.9.tgz", + "integrity": "sha512-ok8IQjcEPs1AKZfuEUznVBrJw+gK4soq+bx8b1X2XoMqVClarc1q5JDmVtWXY1xfr6ZuHTAsPXHTgTrqKTZeww==", "cpu": [ "arm64" ], @@ -805,9 +806,9 @@ } }, "node_modules/@rolldown/binding-win32-x64-msvc": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.7.tgz", - "integrity": "sha512-W/jg5qoRSqjsEv0+dZi4e687mcHqmVuU0P4fK6qS/xjetW2Gmc1W8j//z5nAeNcC8Ttm0hV46IjcYeuVwYhuiw==", + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.9.tgz", + "integrity": "sha512-Ip2mXoU0hM0boq3Rf+ekuT653OROSo6aSYcPT1VHE4q52KvyxgFkQgrgb/IEsxOuvQ2fZZbs8khJAyCEPM24/g==", "cpu": [ "x64" ], @@ -850,9 +851,9 @@ "license": "MIT" }, "node_modules/@types/react": { - "version": "19.2.18", - "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.18.tgz", - "integrity": "sha512-AnzbBERsrLKtk2XSfTbYRLjQPdy116Sty4q+T+Bp3IC4l6jNBvreVPAHmpq9qhXQM7CXZPjLVmGMw9sy+hxQ3w==", + "version": "19.3.0", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.3.0.tgz", + "integrity": "sha512-N0rFCuH9YoxG9/m61l9MfpJKfmLOVU0em7ipIz6TRgSSkvReLB9vL85GB+yr8Bs5leqpvg96JSwF4ZS1s4viQg==", "dev": true, "license": "MIT", "dependencies": { @@ -860,13 +861,13 @@ } }, "node_modules/@types/react-dom": { - "version": "19.2.7", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.7.tgz", - "integrity": "sha512-I8bPpDLcHBv1qiIiXDCy71Rt8eQDKJP0sMSWJphDdAcdqiJ1sGpZamavoEIRZmYzjia9LuEb2HlYdDpmoENpvQ==", + "version": "19.3.0", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.3.0.tgz", + "integrity": "sha512-ZI7bU42mZXXKHn/qNLEw2IrbiINU7X5+vfgdixBHkCNpYWXjKgfQ/P+uyGb5CjOLB9UcnTeg3rylQtV2hym44Q==", "dev": true, "license": "MIT", "peerDependencies": { - "@types/react": "^19.2.0" + "@types/react": "^19.3.0" } }, "node_modules/@vitejs/plugin-react": { @@ -980,9 +981,9 @@ } }, "node_modules/baseline-browser-mapping": { - "version": "2.11.21", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.21.tgz", - "integrity": "sha512-uh8vpY/1/YyFkunIDFH/12p7/7VdPKA1hejMVEbdkEaWnUz0Hesvx5EbiU6XxjyHZIOju+ZMbQJkRh+es3/spQ==", + "version": "2.11.24", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.24.tgz", + "integrity": "sha512-hYrgxie335U08WqICoGqKRzV1HFXv6zdxwJE4ekCb80CM9a0SVVsN4QPwT67RraRo+9h8IATk6uxHJw7QSkdOg==", "dev": true, "license": "Apache-2.0", "bin": { @@ -993,9 +994,9 @@ } }, "node_modules/brace-expansion": { - "version": "5.0.9", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz", - "integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==", + "version": "5.0.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz", + "integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==", "dev": true, "license": "MIT", "dependencies": { @@ -1006,9 +1007,9 @@ } }, "node_modules/browserslist": { - "version": "4.28.9", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.9.tgz", - "integrity": "sha512-EWazOblFYUvlGZcfGhPUPmYh3nikUxBVb+y9MJun5f3hBi812X+8MSQTujLBtgK3cf51fJWbWfOjyeO954d+Eg==", + "version": "4.29.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.29.0.tgz", + "integrity": "sha512-3GSvyjvDI4Dur1Meg2BekJquu5uF+9R9a1+5M1Mde192eZoXbeXjzgOsgqPS2V8D5wrrip0gR5Hf/GhWQ9ZzaA==", "dev": true, "funding": [ { @@ -1026,11 +1027,11 @@ ], "license": "MIT", "dependencies": { - "baseline-browser-mapping": "^2.11.20", + "baseline-browser-mapping": "^2.11.23", "caniuse-lite": "^1.0.30001810", - "electron-to-chromium": "^1.5.420", - "node-releases": "^2.0.54", - "update-browserslist-db": "^1.3.2" + "electron-to-chromium": "^1.5.427", + "node-releases": "^2.0.55", + "update-browserslist-db": "^1.3.3" }, "bin": { "browserslist": "cli.js" @@ -1186,9 +1187,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.422", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.422.tgz", - "integrity": "sha512-UvA/32XqrLDdZSn7Jllo1AYNcWji/G0d5M0GTViE7KoGBiMunw3a34Sb2KO4ZZyrSEhqsxFoVhWWJshdyfKqJA==", + "version": "1.5.430", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.430.tgz", + "integrity": "sha512-e1QEj72Y4zd8RlNZVmoTg+iCOSVwpk05IOiiQwdrkwCSVlZfPthevErhE+nckGd2YbsXfp1SkisznhGVIXP2NQ==", "dev": true, "license": "ISC" }, @@ -1340,9 +1341,9 @@ } }, "node_modules/eslint-plugin-react-refresh": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.5.6.tgz", - "integrity": "sha512-uZnh24On2bk478AkaDAKcpRiYhS3qFSaSNvpXxV6/Ek/BBDICkWGG7MnBSfjnIlCVBei5vsLlIeQYxbF22+Udg==", + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.5.7.tgz", + "integrity": "sha512-XhJSzLljuYD4UjNuFGJu2v7aD3sqNVK12w5/DCUfrNfHWegZo2+TsavNx8MuxMwEquuFAzNbNfXKU0WoZ+YUIg==", "dev": true, "license": "MIT", "peerDependencies": { @@ -2225,9 +2226,9 @@ "license": "MIT" }, "node_modules/nanoid": { - "version": "3.3.18", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.18.tgz", - "integrity": "sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==", + "version": "3.3.19", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.19.tgz", + "integrity": "sha512-Y2tUNy4ouw6tq5oDSKeQYGOyhkUBhNOcGV/02KC+6kd9eDGqdZd++mjMiIDilrBYvjEnCYvVtsuHCuP+okSfug==", "dev": true, "funding": [ { @@ -2251,9 +2252,9 @@ "license": "MIT" }, "node_modules/node-releases": { - "version": "2.0.54", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.54.tgz", - "integrity": "sha512-YHs7BmmcsdAI5Ozuf8JZo6PT0mv2GIWC9vMfvUC3dp65M8hn7Ux8CPL+2oBI7juNuj9d0ndhTcznq2ODBps9cQ==", + "version": "2.0.55", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.55.tgz", + "integrity": "sha512-mIrE/Cw9y+9Au6dS5vDKDhQza9YvG6w+ZrS6X+ZzA7yFW/soAeaups4Qzn1bL6g5FVy8WtP79+0j82oPIbqRjQ==", "dev": true, "license": "MIT", "engines": { @@ -2429,34 +2430,43 @@ "license": "MIT" }, "node_modules/react": { - "version": "19.2.8", - "resolved": "https://registry.npmjs.org/react/-/react-19.2.8.tgz", - "integrity": "sha512-PWaYA1L/q9u2u7xYQi+Y3L3Yfnie7XyLeaJICV1MGD6LprsBxcAqGjYyr0eY3p+QdsA+x/Irkt4Qif8D63+Sbw==", + "version": "19.3.0", + "resolved": "https://registry.npmjs.org/react/-/react-19.3.0.tgz", + "integrity": "sha512-E8LUcbtBWt20bbl2YoHfx4ZDBdxVTfOKtCZn9cDSJ4l6/nuoApcpIBcj47t2wZoVX8g2ZHuMHbiShgCR1T5Sog==", "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/react-dom": { - "version": "19.2.8", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.8.tgz", - "integrity": "sha512-rVprimfGBG3DR+Tq0IQG2DT5PxKth1WIGDmj5yPmlzr4YBe7uyE+Du4oVqTDXZSHGGGXRtTJEGSSePyQCMBglQ==", + "version": "19.3.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.3.0.tgz", + "integrity": "sha512-JDk8dgif51OjFoDE70+OT9ICyYr+69HlmihNwp1+Nsfbna3t5sIiCa9ZJktDmQ4/1b/rn26hIAR2uYXDMr5r0Q==", "license": "MIT", "dependencies": { - "scheduler": "^0.27.0" + "scheduler": "^0.28.0" }, "peerDependencies": { - "react": "^19.2.8" + "react": "^19.3.0" + } + }, + "node_modules/react-icons": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.7.0.tgz", + "integrity": "sha512-LBLy340Rzqy6+/yVhZKT3B/QpP1BZaesGqasf09HPOBzRarcDIFH0WwXlXQfE7q7ipxK4MSiC5DIBWURCny6fw==", + "license": "MIT", + "peerDependencies": { + "react": "*" } }, "node_modules/rolldown": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.7.tgz", - "integrity": "sha512-g0EtLvBjTUB7jhyV0S/TCup3v/XSVl45vUIGbOGU4QPiyjTenCe4mKuFvW9fEgYmS2Fo42AUssRmNuMziXdrig==", + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.9.tgz", + "integrity": "sha512-hx/Pv0N1haXRb11qkfnK5MXB/iqr7i0yjWQqmO9uHqZpBgQSqzc8UsSnEpalsh+j1I8qQ2CkXAkJC8Br3dKSlg==", "dev": true, "license": "MIT", "dependencies": { - "@oxc-project/types": "=0.148.0", + "@oxc-project/types": "=0.150.0", "@rolldown/pluginutils": "^1.0.0" }, "bin": { @@ -2466,27 +2476,27 @@ "node": "^20.19.0 || >=22.12.0" }, "optionalDependencies": { - "@rolldown/binding-android-arm-eabi": "1.2.7", - "@rolldown/binding-android-arm64": "1.2.7", - "@rolldown/binding-darwin-arm64": "1.2.7", - "@rolldown/binding-darwin-x64": "1.2.7", - "@rolldown/binding-freebsd-x64": "1.2.7", - "@rolldown/binding-linux-arm-gnueabihf": "1.2.7", - "@rolldown/binding-linux-arm64-gnu": "1.2.7", - "@rolldown/binding-linux-arm64-musl": "1.2.7", - "@rolldown/binding-linux-ppc64-gnu": "1.2.7", - "@rolldown/binding-linux-s390x-gnu": "1.2.7", - "@rolldown/binding-linux-x64-gnu": "1.2.7", - "@rolldown/binding-linux-x64-musl": "1.2.7", - "@rolldown/binding-openharmony-arm64": "1.2.7", - "@rolldown/binding-win32-arm64-msvc": "1.2.7", - "@rolldown/binding-win32-x64-msvc": "1.2.7" + "@rolldown/binding-android-arm-eabi": "1.2.9", + "@rolldown/binding-android-arm64": "1.2.9", + "@rolldown/binding-darwin-arm64": "1.2.9", + "@rolldown/binding-darwin-x64": "1.2.9", + "@rolldown/binding-freebsd-x64": "1.2.9", + "@rolldown/binding-linux-arm-gnueabihf": "1.2.9", + "@rolldown/binding-linux-arm64-gnu": "1.2.9", + "@rolldown/binding-linux-arm64-musl": "1.2.9", + "@rolldown/binding-linux-ppc64-gnu": "1.2.9", + "@rolldown/binding-linux-s390x-gnu": "1.2.9", + "@rolldown/binding-linux-x64-gnu": "1.2.9", + "@rolldown/binding-linux-x64-musl": "1.2.9", + "@rolldown/binding-openharmony-arm64": "1.2.9", + "@rolldown/binding-win32-arm64-msvc": "1.2.9", + "@rolldown/binding-win32-x64-msvc": "1.2.9" } }, "node_modules/scheduler": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", - "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.28.0.tgz", + "integrity": "sha512-juorfCmIkIw8tT+p5BXSm6PJjQF/ycEYmKyzURCIt/RaZIhL+PulbQ9Yu2z1HdOJDdqDTlxA1+xKBmHXJsczAw==", "license": "MIT" }, "node_modules/semver": { @@ -2563,9 +2573,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.3.2.tgz", - "integrity": "sha512-UQ+MSxlhRm1bzjhU+DcuXfjFO1FzNtqhK5+9Yvlp90ItDLk5vT932A0rFu619nf7RVS+Y/VeaUW1jaRDqZ8VJw==", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.3.3.tgz", + "integrity": "sha512-pJ2sYawQS0R/WI928Gj5GlPhTGzbMelq0+4INtSYNDV9ErKJcX6xjGWkoG/VnB3dpUm00zALaqkrUD77pO5TDQ==", "dev": true, "funding": [ { @@ -2604,16 +2614,16 @@ } }, "node_modules/vite": { - "version": "8.2.2", - "resolved": "https://registry.npmjs.org/vite/-/vite-8.2.2.tgz", - "integrity": "sha512-cFKLV/PRgAUlIRm5WjMjJ86jrftzpqcgH+Us+DS8mI3CDNiH30Whrz8uHL3+MOLPAgqbMBAqWdAHAphOAM+z/Q==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.3.0.tgz", + "integrity": "sha512-lhZBVvEHefgE+HQZC9O7EBJgCU/nVzFNl7vkS4RE0APtWLP02/8QVIkQtzBxPquh7lq5/78NHipTj7ODQ6XuyQ==", "dev": true, "license": "MIT", "dependencies": { "lightningcss": "^1.33.0", - "picomatch": "^4.0.5", - "postcss": "^8.5.26", - "rolldown": "~1.2.4", + "picomatch": "^4.0.7", + "postcss": "^8.5.28", + "rolldown": "~1.2.6", "tinyglobby": "^0.2.17" }, "bin": { @@ -2630,7 +2640,7 @@ }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", - "@vitejs/devtools": "^0.4.0 || ^0.5.0", + "@vitejs/devtools": "^0.7.1", "esbuild": "^0.27.0 || ^0.28.0", "jiti": ">=1.21.0", "less": "^4.0.0", @@ -2728,9 +2738,9 @@ } }, "node_modules/zod": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/zod/-/zod-4.5.4.tgz", - "integrity": "sha512-sC95tT5iHHH9gtpj6A81kh+NEaRAUFN+qlUPDUbRfOMvNf5QCBqsb3WgvnpVtK5Y+4UfA6KqufotuTvMGiTlsA==", + "version": "4.6.5", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.6.5.tgz", + "integrity": "sha512-v5l/aFXZQeai4awLbOpSoHecE9UiMrnfx75tEXLjNonXVARxQ5mOeipTjROUchszUNCqnE+hqAMujRsRHsut2Q==", "dev": true, "license": "MIT", "funding": { diff --git a/package.json b/package.json index 94c5129..e53069e 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,8 @@ "dependencies": { "axios": "^1.20.0", "react": "^19.2.8", - "react-dom": "^19.2.8" + "react-dom": "^19.2.8", + "react-icons": "^5.7.0" }, "devDependencies": { "@eslint/js": "^10.0.1", From 494db6009373ed868ccc643cdd1074fbc7d5ba8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cain=C3=A3=20Melo?= <163151125+CainaNascimentoMelo@users.noreply.github.com> Date: Wed, 16 Sep 2026 23:25:07 -0300 Subject: [PATCH 26/52] fix(4): Update import paths for Home, DocumentList and App --- src/App.jsx | 2 +- src/components/Document/DocumentList/DocumentList.jsx | 2 +- src/pages/Home/Home.jsx | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/App.jsx b/src/App.jsx index 2355b3d..3eb9b58 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,5 +1,5 @@ import Layout from "./components/Layout/Layout"; -import Home from "./pages/Home"; +import Home from "./pages/Home/Home"; import "./App.css"; diff --git a/src/components/Document/DocumentList/DocumentList.jsx b/src/components/Document/DocumentList/DocumentList.jsx index 9ee58c5..4d74e42 100644 --- a/src/components/Document/DocumentList/DocumentList.jsx +++ b/src/components/Document/DocumentList/DocumentList.jsx @@ -1,4 +1,4 @@ -import DocumentItem from "./DocumentItem"; +import DocumentItem from "../DocumentItem/DocumentItem"; import "./DocumentList.css"; diff --git a/src/pages/Home/Home.jsx b/src/pages/Home/Home.jsx index d94ab79..0353ca2 100644 --- a/src/pages/Home/Home.jsx +++ b/src/pages/Home/Home.jsx @@ -1,9 +1,9 @@ import { useEffect, useState } from "react"; import SearchBar from "../../components/SearchBar/SearchBar"; -import DocumentList from "../components/Document/DocumentList"; +import DocumentList from "../../components/Document/DocumentList/DocumentList"; import Pagination from "../../components/Pagination/Pagination"; -import DocumentModal from "../components/Document/DocumentModal"; +import DocumentModal from "../../components/Document/DocumentModal/DocumentModal"; import { fetchDocuments } from "../../services/documentService"; From a38bafc85cbc7c28314aa8cf96bfab762dfe2bbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cain=C3=A3=20Melo?= <163151125+CainaNascimentoMelo@users.noreply.github.com> Date: Wed, 16 Sep 2026 23:33:18 -0300 Subject: [PATCH 27/52] feat(4): Replace SVG icons with react-icons in components --- .../Document/DocumentItem/DocumentItem.jsx | 22 +------- .../Document/DocumentModal/DocumentModal.jsx | 23 +------- src/components/SearchBar/SearchBar.jsx | 23 +------- src/components/Sidebar/Sidebar.jsx | 52 ++----------------- src/pages/Home/Home.jsx | 11 ++-- 5 files changed, 12 insertions(+), 119 deletions(-) diff --git a/src/components/Document/DocumentItem/DocumentItem.jsx b/src/components/Document/DocumentItem/DocumentItem.jsx index b230ecc..158a114 100644 --- a/src/components/Document/DocumentItem/DocumentItem.jsx +++ b/src/components/Document/DocumentItem/DocumentItem.jsx @@ -1,3 +1,4 @@ +import { FiEye } from "react-icons/fi"; import "./DocumentItem.css"; function formatarData(dataISO) { @@ -50,26 +51,7 @@ function DocumentItem({ document, onView }) {
diff --git a/src/components/Document/DocumentModal/DocumentModal.jsx b/src/components/Document/DocumentModal/DocumentModal.jsx index ad6b19d..0aa6771 100644 --- a/src/components/Document/DocumentModal/DocumentModal.jsx +++ b/src/components/Document/DocumentModal/DocumentModal.jsx @@ -1,3 +1,4 @@ +import { FiEye } from "react-icons/fi"; import "./DocumentModal.css"; function DocumentModal({ document, onClose, onViewPdf }) { @@ -164,27 +165,7 @@ function DocumentModal({ document, onClose, onViewPdf }) { className="modal-view-button" onClick={() => onViewPdf(document)} > - - - - - - + Visualizar diff --git a/src/components/SearchBar/SearchBar.jsx b/src/components/SearchBar/SearchBar.jsx index 2673612..440b685 100644 --- a/src/components/SearchBar/SearchBar.jsx +++ b/src/components/SearchBar/SearchBar.jsx @@ -1,3 +1,4 @@ +import { FiSearch } from "react-icons/fi"; import "./SearchBar.css"; function SearchBar({ value, onChange }) { @@ -11,27 +12,7 @@ function SearchBar({ value, onChange }) { />
); diff --git a/src/components/Sidebar/Sidebar.jsx b/src/components/Sidebar/Sidebar.jsx index 21778e2..5dd652c 100644 --- a/src/components/Sidebar/Sidebar.jsx +++ b/src/components/Sidebar/Sidebar.jsx @@ -1,3 +1,4 @@ +import { FiFileText, FiLogOut } from "react-icons/fi"; import logo from "../../assets/AkaerLogo.png"; import "./Sidebar.css"; @@ -12,60 +13,13 @@ function Sidebar() { diff --git a/src/pages/Home/Home.jsx b/src/pages/Home/Home.jsx index 0353ca2..9e1b651 100644 --- a/src/pages/Home/Home.jsx +++ b/src/pages/Home/Home.jsx @@ -1,3 +1,4 @@ +import { FiFileText, FiFilter } from "react-icons/fi"; import { useEffect, useState } from "react"; import SearchBar from "../../components/SearchBar/SearchBar"; @@ -67,20 +68,14 @@ function Home() {
- - - - - +

Documentos

From deb52b589bdae8bdea817fa7390a380b493332ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cain=C3=A3=20Melo?= <163151125+CainaNascimentoMelo@users.noreply.github.com> Date: Wed, 16 Sep 2026 23:38:36 -0300 Subject: [PATCH 28/52] feat(4): Add loading and error message styles to Home component --- src/pages/Home/Home.css | 46 ++++++++++++++++++++++++++++++++++++++++- src/pages/Home/Home.jsx | 17 ++++++++++++--- 2 files changed, 59 insertions(+), 4 deletions(-) diff --git a/src/pages/Home/Home.css b/src/pages/Home/Home.css index e109809..d154e21 100644 --- a/src/pages/Home/Home.css +++ b/src/pages/Home/Home.css @@ -70,6 +70,51 @@ margin-top: 25px; } +/* ===== Mensagens de loading e erro ===== */ +.loading-message { + padding: 16px; + color: #6c757d; + font-size: 14px; +} + +.error-message { + display: flex; + align-items: center; + gap: 10px; + + padding: 14px 18px; + margin-top: 16px; + + border: 1px solid #f5c2c7; + border-radius: 8px; + + background-color: #fde8ea; + color: #842029; + + font-size: 14px; +} + +.error-message svg { + flex-shrink: 0; +} + +.error-message .error-text { + display: flex; + flex-direction: column; + gap: 2px; +} + +.error-message .error-title { + font-weight: 600; + font-size: 14px; +} + +.error-message .error-description { + font-size: 13px; + opacity: 0.85; +} + +/* ===== Responsividade ===== */ @media (max-width: 900px) { .page-header { align-items: flex-start; @@ -93,7 +138,6 @@ .header-actions { width: 100%; - justify-content: flex-start; } } \ No newline at end of file diff --git a/src/pages/Home/Home.jsx b/src/pages/Home/Home.jsx index 9e1b651..c9ad150 100644 --- a/src/pages/Home/Home.jsx +++ b/src/pages/Home/Home.jsx @@ -1,4 +1,4 @@ -import { FiFileText, FiFilter } from "react-icons/fi"; +import { FiFileText, FiFilter, FiAlertCircle } from "react-icons/fi"; import { useEffect, useState } from "react"; import SearchBar from "../../components/SearchBar/SearchBar"; @@ -82,8 +82,19 @@ function Home() {
- {loading &&

Carregando documentos...

} - {error &&

{error}

} + {loading && ( +

Carregando documentos...

+ )} + + {error && ( +
+ +
+ Erro ao carregar + {error} +
+
+ )} {!loading && !error && ( <> From e0433bb005ca187eab238a481fc36b32eb714e9e Mon Sep 17 00:00:00 2001 From: GloBrito Date: Thu, 17 Sep 2026 02:25:24 -0300 Subject: [PATCH 29/52] chore(a6-24): adds frontend test dependencies and scripts --- package.json | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 6af50bd..94a08b5 100644 --- a/package.json +++ b/package.json @@ -4,24 +4,32 @@ "version": "0.0.0", "type": "module", "scripts": { - "dev": "vite", - "build": "vite build", - "lint": "eslint .", - "preview": "vite preview" - }, + "dev": "vite", + "build": "vite build", + "lint": "eslint .", + "test": "vitest run", + "test:coverage": "vitest run --coverage", + "preview": "vite preview" +}, "dependencies": { "react": "^19.2.8", "react-dom": "^19.2.8" }, "devDependencies": { "@eslint/js": "^10.0.1", + "@testing-library/dom": "^10.4.2", + "@testing-library/jest-dom": "^6.9.1", + "@testing-library/react": "^16.3.3", "@types/react": "^19.2.18", "@types/react-dom": "^19.2.4", "@vitejs/plugin-react": "^6.1.0", + "@vitest/coverage-v8": "^4.1.11", "eslint": "^10.9.0", "eslint-plugin-react-hooks": "^7.1.1", "eslint-plugin-react-refresh": "^0.5.4", "globals": "^17.11.0", - "vite": "^8.2.2" + "jsdom": "^29.1.1", + "vite": "^8.2.2", + "vitest": "^4.1.11" } } From 81a5e5ce1235b291fc745dd76e1f6277871e86ca Mon Sep 17 00:00:00 2001 From: GloBrito Date: Thu, 17 Sep 2026 02:25:28 -0300 Subject: [PATCH 30/52] chore(a6-24): updates frontend dependency lockfile --- package-lock.json | 1374 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 1339 insertions(+), 35 deletions(-) diff --git a/package-lock.json b/package-lock.json index 47c0342..54ebeec 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,16 +13,80 @@ }, "devDependencies": { "@eslint/js": "^10.0.1", + "@testing-library/dom": "^10.4.2", + "@testing-library/jest-dom": "^6.9.1", + "@testing-library/react": "^16.3.3", "@types/react": "^19.2.18", "@types/react-dom": "^19.2.4", "@vitejs/plugin-react": "^6.1.0", + "@vitest/coverage-v8": "^4.1.11", "eslint": "^10.9.0", "eslint-plugin-react-hooks": "^7.1.1", "eslint-plugin-react-refresh": "^0.5.4", "globals": "^17.11.0", - "vite": "^8.2.2" + "jsdom": "^29.1.1", + "vite": "^8.2.2", + "vitest": "^4.1.11" } }, + "node_modules/@adobe/css-tools": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.5.0.tgz", + "integrity": "sha512-6OzddxPio9UiWTCemp4N8cYLV2ZN1ncRnV1cVGtve7dhPOtRkleRyx32GQCYSwDYgaHU3USMm84tNsvKzRCa1Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@asamuzakjp/css-color": { + "version": "5.1.11", + "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-5.1.11.tgz", + "integrity": "sha512-KVw6qIiCTUQhByfTd78h2yD1/00waTmm9uy/R7Ck/ctUyAPj+AEDLkQIdJW0T8+qGgj3j5bpNKK7Q3G+LedJWg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@asamuzakjp/generational-cache": "^1.0.1", + "@csstools/css-calc": "^3.2.0", + "@csstools/css-color-parser": "^4.1.0", + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-tokenizer": "^4.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, + "node_modules/@asamuzakjp/dom-selector": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@asamuzakjp/dom-selector/-/dom-selector-7.1.1.tgz", + "integrity": "sha512-67RZDnYRc8H/8MLDgQCDE//zoqVFwajkepHZgmXrbwybzXOEwOWGPYGmALYl9J2DOLfFPPs6kKCqmbzV895hTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@asamuzakjp/generational-cache": "^1.0.1", + "@asamuzakjp/nwsapi": "^2.3.9", + "bidi-js": "^1.0.3", + "css-tree": "^3.2.1", + "is-potential-custom-element-name": "^1.0.1" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, + "node_modules/@asamuzakjp/generational-cache": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@asamuzakjp/generational-cache/-/generational-cache-1.0.1.tgz", + "integrity": "sha512-wajfB8KqzMCN2KGNFdLkReeHncd0AslUSrvHVvvYWuU8ghncRJoA50kT3zP9MVL0+9g4/67H+cdvBskj9THPzg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, + "node_modules/@asamuzakjp/nwsapi": { + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/@asamuzakjp/nwsapi/-/nwsapi-2.3.9.tgz", + "integrity": "sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q==", + "dev": true, + "license": "MIT" + }, "node_modules/@babel/code-frame": { "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", @@ -215,6 +279,16 @@ "node": ">=6.0.0" } }, + "node_modules/@babel/runtime": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.7.tgz", + "integrity": "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/template": { "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", @@ -263,6 +337,29 @@ "node": ">=6.9.0" } }, + "node_modules/@bcoe/v8-coverage": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-1.0.2.tgz", + "integrity": "sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@bramus/specificity": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@bramus/specificity/-/specificity-2.4.2.tgz", + "integrity": "sha512-ctxtJ/eA+t+6q2++vj5j7FYX3nRu311q1wfYH3xjlLOsczhlhxAg2FWNUXhpGvAw3BWo1xBcvOV6/YLc2r5FJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "css-tree": "^3.0.0" + }, + "bin": { + "specificity": "bin/cli.js" + } + }, "node_modules/@cacheable/memory": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/@cacheable/memory/-/memory-2.2.0.tgz", @@ -287,6 +384,146 @@ "keyv": "^5.6.0" } }, + "node_modules/@csstools/color-helpers": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-6.1.1.tgz", + "integrity": "sha512-gLNsunvwf3mCi5u5o46/Z/JcJMnhbHSaZ69rkgPzNM3J4s8hWwpPUQB6/tt0EDFyCiWzxANlx+2LJwpYj4zS1w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=20.19.0" + } + }, + "node_modules/@csstools/css-calc": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-3.4.0.tgz", + "integrity": "sha512-XQKj5B7QiZcHiegCOCAzcAOJdhGgWOHbbu62h5e5mkHnn8lWcfiJhllkqWmxu5zWR9jucPHuo1iTB56P033hcg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-tokenizer": "^4.0.0" + } + }, + "node_modules/@csstools/css-color-parser": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-4.2.3.tgz", + "integrity": "sha512-y4LpL+lmpuyKDiEFq2PnZUVFdAjsoB/qQJod79yLNokXyW7jewi+/WJ69EfItj8A2unWtxXnGjw6LYXgXu5ZjA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "dependencies": { + "@csstools/color-helpers": "^6.1.1", + "@csstools/css-calc": "^3.4.0" + }, + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-tokenizer": "^4.0.0" + } + }, + "node_modules/@csstools/css-parser-algorithms": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-4.0.0.tgz", + "integrity": "sha512-+B87qS7fIG3L5h3qwJ/IFbjoVoOe/bpOdh9hAjXbvx0o8ImEmUsGXN0inFOnk2ChCFgqkkGFQ+TpM5rbhkKe4w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "@csstools/css-tokenizer": "^4.0.0" + } + }, + "node_modules/@csstools/css-syntax-patches-for-csstree": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.1.14.tgz", + "integrity": "sha512-HpbVXyrofRXpHpgkNIjU/3EWR4WJvOkO3emNK/L6X/mTJU7bGUI3AkkpoTNXznQLp0KRjLHELTGeKI5dIkI9JQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "peerDependencies": { + "css-tree": "^3.2.1" + }, + "peerDependenciesMeta": { + "css-tree": { + "optional": true + } + } + }, + "node_modules/@csstools/css-tokenizer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-4.0.0.tgz", + "integrity": "sha512-QxULHAm7cNu72w97JUNCBFODFaXpbDg+dP8b/oWFAZ2MTRppA3U00Y2L1HqaS4J6yBqxwa/Y3nMBaxVKbB/NsA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=20.19.0" + } + }, "node_modules/@eslint-community/eslint-utils": { "version": "4.10.1", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.10.1.tgz", @@ -415,6 +652,24 @@ "node": "^20.19.0 || ^22.13.0 || >=24" } }, + "node_modules/@exodus/bytes": { + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/@exodus/bytes/-/bytes-1.15.1.tgz", + "integrity": "sha512-S6mL0yNB/Abt9Ei4tq8gDhcczc4S3+vQ4ra7vxnAf+YHC02srtqxKKZghx2Dq6p0e66THKwR6r8N6P95wEty7Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + }, + "peerDependencies": { + "@noble/hashes": "^1.8.0 || ^2.0.0" + }, + "peerDependenciesMeta": { + "@noble/hashes": { + "optional": true + } + } + }, "node_modules/@humanfs/core": { "version": "0.19.2", "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz", @@ -827,6 +1082,113 @@ "dev": true, "license": "MIT" }, + "node_modules/@standard-schema/spec": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@testing-library/dom": { + "version": "10.4.2", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.2.tgz", + "integrity": "sha512-yzr2S9HyAIdhz2/6qHgbs665Q7PKVcDF05vsOlHPxG1mo36gKVesdYVeDLnXgfjJ03CrKRk08knc6+E/9m8v2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^5.0.1", + "aria-query": "5.3.0", + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.5.0", + "picocolors": "1.1.1", + "pretty-format": "^27.0.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@testing-library/jest-dom": { + "version": "6.9.1", + "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.9.1.tgz", + "integrity": "sha512-zIcONa+hVtVSSep9UT3jZ5rizo2BsxgyDYU7WFD5eICBE7no3881HGeb/QkGfsJs6JTkY1aQhT7rIPC7e+0nnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@adobe/css-tools": "^4.4.0", + "aria-query": "^5.0.0", + "css.escape": "^1.5.1", + "dom-accessibility-api": "^0.6.3", + "picocolors": "^1.1.1", + "redent": "^3.0.0" + }, + "engines": { + "node": ">=14", + "npm": ">=6", + "yarn": ">=1" + } + }, + "node_modules/@testing-library/jest-dom/node_modules/dom-accessibility-api": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.6.3.tgz", + "integrity": "sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@testing-library/react": { + "version": "16.3.3", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-16.3.3.tgz", + "integrity": "sha512-Uo193NgQbPMz6lrrhtRQQFcMC6Re/ELLFbbuVL30WDlZxlpZf9/lMHTAVxPRLw1q1iu9OJmR1c2BLiENRstdBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.12.5" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@testing-library/dom": "^10.0.0", + "@types/react": "^18.0.0 || ^19.0.0", + "@types/react-dom": "^18.0.0 || ^19.0.0", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@types/aria-query": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", + "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/chai": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", + "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" + } + }, + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/esrecurse": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/@types/esrecurse/-/esrecurse-4.3.1.tgz", @@ -898,60 +1260,266 @@ } } }, - "node_modules/acorn": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.18.0.tgz", - "integrity": "sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ==", + "node_modules/@vitest/coverage-v8": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-4.1.11.tgz", + "integrity": "sha512-8MVGEFnJIcdGjcbfKmeq8z0pZHH0JlVtoVZH9Q/qwUp6wyFnEJUBMrw9DCaj+ra3vShGmhavjalMIhPNxZAUcw==", "dev": true, "license": "MIT", - "bin": { - "acorn": "bin/acorn" + "dependencies": { + "@bcoe/v8-coverage": "^1.0.2", + "@vitest/utils": "4.1.11", + "ast-v8-to-istanbul": "^1.0.0", + "istanbul-lib-coverage": "^3.2.2", + "istanbul-lib-report": "^3.0.1", + "istanbul-reports": "^3.2.0", + "magicast": "^0.5.2", + "obug": "^2.1.1", + "std-env": "^4.0.0-rc.1", + "tinyrainbow": "^3.1.0" }, - "engines": { - "node": ">=0.4.0" + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@vitest/browser": "4.1.11", + "vitest": "4.1.11" + }, + "peerDependenciesMeta": { + "@vitest/browser": { + "optional": true + } } }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "node_modules/@vitest/expect": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.11.tgz", + "integrity": "sha512-VX2x5vNJXET47KAFzwERI+KRMtTTCSWTfSMKsW7JsUsXV4psq++e3DvZpuTDOpHcxytiDs6p2nhVb2tVDiiUYw==", "dev": true, "license": "MIT", - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + "dependencies": { + "@standard-schema/spec": "^1.1.0", + "@types/chai": "^5.2.2", + "@vitest/spy": "4.1.11", + "@vitest/utils": "4.1.11", + "chai": "^6.2.2", + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" } }, - "node_modules/ajv": { - "version": "6.15.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", - "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", + "node_modules/@vitest/mocker": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.11.tgz", + "integrity": "sha512-2XJVD55d1o5AZous5CCGKS74g/riOj9odEt2bQpCVZeblHyHdnMeFl4jl0XjU21stf4mbjUkew2eXQZt65g5CQ==", "dev": true, "license": "MIT", "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" + "@vitest/spy": "4.1.11", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.21" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } } }, - "node_modules/balanced-match": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", - "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "node_modules/@vitest/pretty-format": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.11.tgz", + "integrity": "sha512-yiZzPbGTS9Sr/JpFl8zHrcIkAofNbFV6k21vIgQN/cY/oxZeXhJv5sc/MBJ5jFKWmWs+oJHw0UXLZjmf931+Vw==", "dev": true, "license": "MIT", - "engines": { - "node": "18 || 20 || >=22" + "dependencies": { + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" } }, - "node_modules/baseline-browser-mapping": { - "version": "2.11.21", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.21.tgz", - "integrity": "sha512-uh8vpY/1/YyFkunIDFH/12p7/7VdPKA1hejMVEbdkEaWnUz0Hesvx5EbiU6XxjyHZIOju+ZMbQJkRh+es3/spQ==", + "node_modules/@vitest/runner": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.11.tgz", + "integrity": "sha512-LztvUgdwMNJMIkj3hQnnxiC2Xy1zNxq928W/xhjCLaNCzqTZOudjwbQf6v9IntZGPw132i2Lq2rgTRZHD3JHNw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "4.1.11", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.11.tgz", + "integrity": "sha512-pN7ikn1ON7h8ee4gIAp4AzyK+zBtJPzVbqOgu5LCEh4VaJVbPQcgYQYJIMGQPXVeJJq1fnfazis7a5pFNPahog==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.1.11", + "@vitest/utils": "4.1.11", + "magic-string": "^0.30.21", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.11.tgz", + "integrity": "sha512-apNa/prQy2qCeywhnixOHPRCgGNhvg7T4Dapfl1GahLp/R+uhBm5cPyFoNVyqsNd2h1nJxL6BqqdIjiABL60YA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.11.tgz", + "integrity": "sha512-zTCVGpyFsGWBhllOyKlTw/vnr6D9qxsfSDyfbyZmTyjHw5N/VuvzHpHoQjm2ZJzn4RJgx5w4r7V0er69CmLgPQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.1.11", + "convert-source-map": "^2.0.0", + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/acorn": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.18.0.tgz", + "integrity": "sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/aria-query": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", + "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "dequal": "^2.0.3" + } + }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/ast-v8-to-istanbul": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-1.0.6.tgz", + "integrity": "sha512-fvpl29helSO2w/z7utIbrkNXILdrLwDwAMH2I/zPKlGf5244+gf+B4cyS1sANcrPY2h+hWCGSgC8N61s/+AF9A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.31", + "estree-walker": "^3.0.3", + "js-tokens": "^10.0.0" + } + }, + "node_modules/ast-v8-to-istanbul/node_modules/js-tokens": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-10.0.0.tgz", + "integrity": "sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/baseline-browser-mapping": { + "version": "2.11.21", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.21.tgz", + "integrity": "sha512-uh8vpY/1/YyFkunIDFH/12p7/7VdPKA1hejMVEbdkEaWnUz0Hesvx5EbiU6XxjyHZIOju+ZMbQJkRh+es3/spQ==", "dev": true, "license": "Apache-2.0", "bin": { @@ -961,6 +1529,16 @@ "node": ">=6.0.0" } }, + "node_modules/bidi-js": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/bidi-js/-/bidi-js-1.1.0.tgz", + "integrity": "sha512-fX1Onk0tdVPC7obPWB5EbJ1z7NVhLq4m2xZLq2YXBkxzMXIGRpNMU88n0EPgWseKl12J7zXs7qrDxPK4sRs2fg==", + "dev": true, + "license": "MIT", + "dependencies": { + "require-from-string": "^2.0.2" + } + }, "node_modules/brace-expansion": { "version": "5.0.9", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz", @@ -1043,6 +1621,16 @@ ], "license": "CC-BY-4.0" }, + "node_modules/chai": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", + "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/convert-source-map": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", @@ -1065,6 +1653,27 @@ "node": ">= 8" } }, + "node_modules/css-tree": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.2.1.tgz", + "integrity": "sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "mdn-data": "2.27.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + } + }, + "node_modules/css.escape": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", + "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==", + "dev": true, + "license": "MIT" + }, "node_modules/csstype": { "version": "3.2.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", @@ -1072,6 +1681,20 @@ "dev": true, "license": "MIT" }, + "node_modules/data-urls": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-7.0.0.tgz", + "integrity": "sha512-23XHcCF+coGYevirZceTVD7NdJOqVn+49IHyxgszm+JIiHLoB2TkmPtsYkNWT1pvRSGkc35L6NHs0yHkN2SumA==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-mimetype": "^5.0.0", + "whatwg-url": "^16.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, "node_modules/debug": { "version": "4.4.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", @@ -1090,6 +1713,13 @@ } } }, + "node_modules/decimal.js": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz", + "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==", + "dev": true, + "license": "MIT" + }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -1097,6 +1727,16 @@ "dev": true, "license": "MIT" }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/detect-libc": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", @@ -1107,6 +1747,13 @@ "node": ">=8" } }, + "node_modules/dom-accessibility-api": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", + "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", + "dev": true, + "license": "MIT" + }, "node_modules/electron-to-chromium": { "version": "1.5.422", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.422.tgz", @@ -1114,6 +1761,26 @@ "dev": true, "license": "ISC" }, + "node_modules/entities": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-8.1.0.tgz", + "integrity": "sha512-kxL7msIffSuh9aaFAMD7rxAIuTRMAHMeBtgHW2yUdWw732ZNh4MehkF2gdjvtdmikkaIP9bFDDJOPlsvm7avrA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=20.19.0" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/es-module-lexer": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.3.2.tgz", + "integrity": "sha512-poHGpORABojJJucnV9KbOavETW8lBVnphkW77ER5/BQ5Fz7oXSoCNek7IH3vR5nRjdsEz926ibFYX8KtLQmdyw==", + "dev": true, + "license": "MIT" + }, "node_modules/escalade": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", @@ -1312,6 +1979,16 @@ "node": ">=4.0" } }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, "node_modules/esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", @@ -1322,6 +1999,16 @@ "node": ">=0.10.0" } }, + "node_modules/expect-type": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.4.0.tgz", + "integrity": "sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -1458,6 +2145,16 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/hashery": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/hashery/-/hashery-1.5.1.tgz", @@ -1495,6 +2192,26 @@ "dev": true, "license": "MIT" }, + "node_modules/html-encoding-sniffer": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-6.0.0.tgz", + "integrity": "sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@exodus/bytes": "^1.6.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true, + "license": "MIT" + }, "node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", @@ -1515,6 +2232,16 @@ "node": ">=0.8.19" } }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -1538,6 +2265,13 @@ "node": ">=0.10.0" } }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true, + "license": "MIT" + }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -1545,6 +2279,45 @@ "dev": true, "license": "ISC" }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-reports": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", + "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -1552,6 +2325,57 @@ "dev": true, "license": "MIT" }, + "node_modules/jsdom": { + "version": "29.1.1", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-29.1.1.tgz", + "integrity": "sha512-ECi4Fi2f7BdJtUKTflYRTiaMxIB0O6zfR1fX0GXpUrf6flp8QIYn1UT20YQqdSOfk2dfkCwS8LAFoJDEppNK5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@asamuzakjp/css-color": "^5.1.11", + "@asamuzakjp/dom-selector": "^7.1.1", + "@bramus/specificity": "^2.4.2", + "@csstools/css-syntax-patches-for-csstree": "^1.1.3", + "@exodus/bytes": "^1.15.0", + "css-tree": "^3.2.1", + "data-urls": "^7.0.0", + "decimal.js": "^10.6.0", + "html-encoding-sniffer": "^6.0.0", + "is-potential-custom-element-name": "^1.0.1", + "lru-cache": "^11.3.5", + "parse5": "^8.0.1", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^6.0.1", + "undici": "^7.25.0", + "w3c-xmlserializer": "^5.0.0", + "webidl-conversions": "^8.0.1", + "whatwg-mimetype": "^5.0.0", + "whatwg-url": "^16.0.1", + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24.0.0" + }, + "peerDependencies": { + "canvas": "^3.0.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/jsdom/node_modules/lru-cache": { + "version": "11.5.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.2.tgz", + "integrity": "sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, "node_modules/jsesc": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", @@ -1903,6 +2727,84 @@ "yallist": "^3.0.2" } }, + "node_modules/lz-string": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", + "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", + "dev": true, + "license": "MIT", + "bin": { + "lz-string": "bin/bin.js" + } + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/magicast": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.5.5.tgz", + "integrity": "sha512-UicdXN8zQ3JHlxVq+28afMXPr1z7WNY6+7EJnzTdQWkTAlMLF5fNCCKxJHBQwGaNGR11581EiQmQzx73+MvszA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7", + "source-map-js": "^1.2.1" + } + }, + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mdn-data": { + "version": "2.27.1", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.27.1.tgz", + "integrity": "sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/minimatch": { "version": "10.2.6", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz", @@ -1962,6 +2864,20 @@ "node": ">=18" } }, + "node_modules/obug": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/obug/-/obug-2.2.1.tgz", + "integrity": "sha512-XrsrhT5sybtKI6wakr2SPOlGZWWYbUXZ7a0jT8/QOeAPau+1X/bSegNe5YR75oJmEZQbKningirmGOEJCIk61Q==", + "dev": true, + "funding": [ + "https://github.com/sponsors/sxzz", + "https://opencollective.com/debug" + ], + "license": "MIT", + "engines": { + "node": ">=12.20.0" + } + }, "node_modules/optionator": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", @@ -2012,6 +2928,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/parse5": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-8.0.1.tgz", + "integrity": "sha512-z1e/HMG90obSGeidlli3hj7cbocou0/wa5HacvI3ASx34PecNjNQeaHNo5WIZpWofN9kgkqV1q5YvXe3F0FoPw==", + "dev": true, + "license": "MIT", + "dependencies": { + "entities": "^8.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -2032,6 +2961,13 @@ "node": ">=8" } }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -2091,6 +3027,21 @@ "node": ">= 0.8.0" } }, + "node_modules/pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -2142,6 +3093,37 @@ "react": "^19.2.8" } }, + "node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true, + "license": "MIT" + }, + "node_modules/redent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/rolldown": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.7.tgz", @@ -2176,6 +3158,19 @@ "@rolldown/binding-win32-x64-msvc": "1.2.7" } }, + "node_modules/saxes": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", + "dev": true, + "license": "ISC", + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=v12.22.7" + } + }, "node_modules/scheduler": { "version": "0.27.0", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", @@ -2215,6 +3210,13 @@ "node": ">=8" } }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true, + "license": "ISC" + }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -2225,6 +3227,70 @@ "node": ">=0.10.0" } }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true, + "license": "MIT" + }, + "node_modules/std-env": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.2.0.tgz", + "integrity": "sha512-oCUKSupKTHX53EyjDtuZQ64pjLJ6yYCtpmEw0goYxtjG9KpbRe8KAsl2tBUGU9DyMcJ0RwJ8GqJAFzMXcXW1Rw==", + "dev": true, + "license": "MIT" + }, + "node_modules/strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "min-indent": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.3.1.tgz", + "integrity": "sha512-GCvB3aoys96IuDFBMcTB46JOR6mdMtAToqwiW8JlWhsoh1mhHi/xn9ss/Dg7N555GiJyEt2qzoG/NHCwM6h1EA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/tinyglobby": { "version": "0.2.17", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", @@ -2242,6 +3308,62 @@ "url": "https://github.com/sponsors/SuperchupuDev" } }, + "node_modules/tinyrainbow": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.1.tgz", + "integrity": "sha512-yau8yJdTt989Mm0Bd/236QnzEiPf2xLLTqUZRUJOo/3CB078LSwzei343DgtJVmfJKJE3TMINY1u42SQsP6mXw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tldts": { + "version": "7.4.13", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-7.4.13.tgz", + "integrity": "sha512-iHtaIWWIbMDkCeJdTBzZFGgbluE5J+oHlb2g7+oAz1S1gpuVpabRZdQyd471Vl8UUkcz2vXSL8xZH2kyCe8tfA==", + "dev": true, + "license": "MIT", + "dependencies": { + "tldts-core": "^7.4.13" + }, + "bin": { + "tldts": "bin/cli.js" + } + }, + "node_modules/tldts-core": { + "version": "7.4.13", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-7.4.13.tgz", + "integrity": "sha512-mbYsrih5FRtGxs3Usvl/PqwJsNpp+jsmrdFviiK02teHDG0/HebBG/pqCylje3kzgXYzuLoHJF/0mz9W53t8Xg==", + "dev": true, + "license": "MIT" + }, + "node_modules/tough-cookie": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-6.0.2.tgz", + "integrity": "sha512-exgYmnmL/sJpR3upZfXG5PoatXQii55xAiXGXzY+sROLZ/Y+SLcp9PgJNI9Vz37HpQ74WvDcLT8eqm+kV3FzrA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "tldts": "^7.0.5" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/tr46": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-6.0.0.tgz", + "integrity": "sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==", + "dev": true, + "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" + }, + "engines": { + "node": ">=20" + } + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -2255,6 +3377,16 @@ "node": ">= 0.8.0" } }, + "node_modules/undici": { + "version": "7.29.1", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.29.1.tgz", + "integrity": "sha512-RYONW2MeafgYlkVOKYKkA/Ag7BmXqgIWCa8t1m0JcxrQg9pI9lEqRhAOruOBCbAohOa/gkCF+iPi9hrgvTzu6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.18.1" + } + }, "node_modules/update-browserslist-db": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.3.2.tgz", @@ -2374,6 +3506,144 @@ } } }, + "node_modules/vitest": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.11.tgz", + "integrity": "sha512-fhACrNXUidIbGSBr5FlbuBkO7VWC1ZyLl0DO4CU2DrQoAPxX84Ysxs+HeGQpii5lZWV1Q4gBZTTu49mF+A6Edw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/expect": "4.1.11", + "@vitest/mocker": "4.1.11", + "@vitest/pretty-format": "4.1.11", + "@vitest/runner": "4.1.11", + "@vitest/snapshot": "4.1.11", + "@vitest/spy": "4.1.11", + "@vitest/utils": "4.1.11", + "es-module-lexer": "^2.0.0", + "expect-type": "^1.3.0", + "magic-string": "^0.30.21", + "obug": "^2.1.1", + "pathe": "^2.0.3", + "picomatch": "^4.0.3", + "std-env": "^4.0.0-rc.1", + "tinybench": "^2.9.0", + "tinyexec": "^1.0.2", + "tinyglobby": "^0.2.15", + "tinyrainbow": "^3.1.0", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@opentelemetry/api": "^1.9.0", + "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", + "@vitest/browser-playwright": "4.1.11", + "@vitest/browser-preview": "4.1.11", + "@vitest/browser-webdriverio": "4.1.11", + "@vitest/coverage-istanbul": "4.1.11", + "@vitest/coverage-v8": "4.1.11", + "@vitest/ui": "4.1.11", + "happy-dom": "*", + "jsdom": "*", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@opentelemetry/api": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser-playwright": { + "optional": true + }, + "@vitest/browser-preview": { + "optional": true + }, + "@vitest/browser-webdriverio": { + "optional": true + }, + "@vitest/coverage-istanbul": { + "optional": true + }, + "@vitest/coverage-v8": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + }, + "vite": { + "optional": false + } + } + }, + "node_modules/w3c-xmlserializer": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", + "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/webidl-conversions": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-8.0.1.tgz", + "integrity": "sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=20" + } + }, + "node_modules/whatwg-mimetype": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-5.0.0.tgz", + "integrity": "sha512-sXcNcHOC51uPGF0P/D4NVtrkjSU2fNsm9iog4ZvZJsL3rjoDAzXZhkm2MWt1y+PUdggKAYVoMAIYcs78wJ51Cw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + } + }, + "node_modules/whatwg-url": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-16.0.1.tgz", + "integrity": "sha512-1to4zXBxmXHV3IiSSEInrreIlu02vUOvrhxJJH5vcxYTBDAx51cqZiKdyTxlecdKNSjj8EcxGBxNf6Vg+945gw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@exodus/bytes": "^1.11.0", + "tr46": "^6.0.0", + "webidl-conversions": "^8.0.1" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -2390,6 +3660,23 @@ "node": ">= 8" } }, + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/word-wrap": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", @@ -2400,6 +3687,23 @@ "node": ">=0.10.0" } }, + "node_modules/xml-name-validator": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", + "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true, + "license": "MIT" + }, "node_modules/yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", From a197ae5e82850969b7c705ee27ae7627c5bd3a06 Mon Sep 17 00:00:00 2001 From: GloBrito Date: Thu, 17 Sep 2026 02:25:32 -0300 Subject: [PATCH 31/52] test(a6-24): configures vitest and testing environment --- src/test/setup.js | 1 + vitest.config.js | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 src/test/setup.js create mode 100644 vitest.config.js diff --git a/src/test/setup.js b/src/test/setup.js new file mode 100644 index 0000000..f149f27 --- /dev/null +++ b/src/test/setup.js @@ -0,0 +1 @@ +import "@testing-library/jest-dom/vitest"; diff --git a/vitest.config.js b/vitest.config.js new file mode 100644 index 0000000..8994c93 --- /dev/null +++ b/vitest.config.js @@ -0,0 +1,23 @@ +import { defineConfig } from "vitest/config"; +import react from "@vitejs/plugin-react"; + +export default defineConfig({ + plugins: [react()], + test: { + environment: "jsdom", + globals: true, + setupFiles: "./src/test/setup.js", + css: true, + coverage: { + provider: "v8", + reporter: ["text", "lcov"], + reportsDirectory: "./coverage", + exclude: [ + "src/test/**", + "**/*.test.{js,jsx}", + "**/*.spec.{js,jsx}", + "src/main.jsx", + ], + }, + }, +}); From 74f8912207766f74941d58d40730b96d6fe2d2ad Mon Sep 17 00:00:00 2001 From: GloBrito Date: Thu, 17 Sep 2026 02:25:40 -0300 Subject: [PATCH 32/52] test(a6-24): adds frontend component and page tests --- src/components/Document/DocumentItem.test.jsx | 63 ++++++++++ src/components/Document/DocumentList.test.jsx | 65 ++++++++++ .../Document/DocumentModal.test.jsx | 101 +++++++++++++++ src/components/Pagination/Pagination.test.jsx | 78 ++++++++++++ src/components/SearchBar/SearchBar.test.jsx | 55 +++++++++ src/pages/Home.test.jsx | 116 ++++++++++++++++++ 6 files changed, 478 insertions(+) create mode 100644 src/components/Document/DocumentItem.test.jsx create mode 100644 src/components/Document/DocumentList.test.jsx create mode 100644 src/components/Document/DocumentModal.test.jsx create mode 100644 src/components/Pagination/Pagination.test.jsx create mode 100644 src/components/SearchBar/SearchBar.test.jsx create mode 100644 src/pages/Home.test.jsx diff --git a/src/components/Document/DocumentItem.test.jsx b/src/components/Document/DocumentItem.test.jsx new file mode 100644 index 0000000..81d7d6b --- /dev/null +++ b/src/components/Document/DocumentItem.test.jsx @@ -0,0 +1,63 @@ +import { fireEvent, render, screen } from "@testing-library/react"; +import { describe, expect, it, vi } from "vitest"; + +import DocumentItem from "./DocumentItem"; + +const document = { + id: 1, + name: "Documento de teste", + type: "Técnico", + accessLevel: "Gestor", + updatedAt: "05/05/2004", + fileType: "PDF", +}; + +describe("DocumentItem", () => { + it("renderiza as informações do documento", () => { + render( + , + ); + + expect(screen.getByText("PDF")).toBeInTheDocument(); + expect(screen.getByText("Documento de teste")).toBeInTheDocument(); + expect(screen.getByText("Técnico")).toBeInTheDocument(); + expect(screen.getByText("Gestor")).toBeInTheDocument(); + expect(screen.getByText("05/05/2004")).toBeInTheDocument(); + }); + + it("chama onView com o documento ao clicar em Visualizar", () => { + const onView = vi.fn(); + + render( + , + ); + + fireEvent.click(screen.getByRole("button", { name: /visualizar/i })); + + expect(onView).toHaveBeenCalledTimes(1); + expect(onView).toHaveBeenCalledWith(document); + }); + + it("aplica as classes baseadas no tipo e no nível de acesso", () => { + const { container } = render( + , + ); + + expect( + container.querySelector(".type-técnico"), + ).toBeInTheDocument(); + + expect( + container.querySelector(".access-gestor"), + ).toBeInTheDocument(); + }); +}); diff --git a/src/components/Document/DocumentList.test.jsx b/src/components/Document/DocumentList.test.jsx new file mode 100644 index 0000000..8f63796 --- /dev/null +++ b/src/components/Document/DocumentList.test.jsx @@ -0,0 +1,65 @@ +import { render, screen } from "@testing-library/react"; +import { describe, expect, it, vi } from "vitest"; + +import DocumentList from "./DocumentList"; + +const documents = [ + { + id: 1, + name: "Documento A", + type: "Técnico", + accessLevel: "Gestor", + updatedAt: "01/01/2026", + fileType: "PDF", + }, + { + id: 2, + name: "Documento B", + type: "Normativo", + accessLevel: "Público", + updatedAt: "02/01/2026", + fileType: "PDF", + }, +]; + +describe("DocumentList", () => { + it("renderiza os documentos recebidos", () => { + render( + , + ); + + expect(screen.getByText("Documento A")).toBeInTheDocument(); + expect(screen.getByText("Documento B")).toBeInTheDocument(); + }); + + it("exibe a mensagem quando a lista está vazia", () => { + render( + , + ); + + expect( + screen.getByText("Nenhum documento encontrado."), + ).toBeInTheDocument(); + }); + + it("renderiza os cabeçalhos da lista", () => { + render( + , + ); + + expect(screen.getByText("Arquivo")).toBeInTheDocument(); + expect(screen.getByText("Nome do documento")).toBeInTheDocument(); + expect(screen.getByText("Setor/Tipo")).toBeInTheDocument(); + expect(screen.getByText("Atualizado")).toBeInTheDocument(); + expect(screen.getByText("Nível de Acesso")).toBeInTheDocument(); + }); +}); diff --git a/src/components/Document/DocumentModal.test.jsx b/src/components/Document/DocumentModal.test.jsx new file mode 100644 index 0000000..2397db9 --- /dev/null +++ b/src/components/Document/DocumentModal.test.jsx @@ -0,0 +1,101 @@ +import { fireEvent, render, screen } from "@testing-library/react"; +import { describe, expect, it, vi } from "vitest"; + +import DocumentModal from "./DocumentModal"; + +const document = { + id: 1, + code: "MIL-HDBK-5J", + name: "Metalic Materials", + type: "Técnico", + category: "MIL-HDBK", + updatedAt: "05/05/2004", + accessLevel: "Gestor", + revision: "5J", + fileSize: "66.8 MB", +}; + +describe("DocumentModal", () => { + it("não renderiza quando nenhum documento está selecionado", () => { + const { container } = render( + , + ); + + expect(container.firstChild).toBeNull(); + }); + + it("renderiza os dados do documento", () => { + render( + , + ); + + expect(screen.getByText("MIL-HDBK-5J")).toBeInTheDocument(); + expect(screen.getByText("Metalic Materials")).toBeInTheDocument(); + expect(screen.getByText("Técnico")).toBeInTheDocument(); + expect(screen.getByText("Gestor")).toBeInTheDocument(); + expect(screen.getByText("66.8 MB")).toBeInTheDocument(); + expect(screen.getByText("Materiais metálicos")).toBeInTheDocument(); + }); + + it("chama onClose ao clicar no botão Fechar", () => { + const onClose = vi.fn(); + + render( + , + ); + + fireEvent.click( + screen.getByRole("button", { name: "Fechar" }), + ); + + expect(onClose).toHaveBeenCalledTimes(1); + }); + + it("chama onClose ao clicar no overlay", () => { + const onClose = vi.fn(); + + const { container } = render( + , + ); + + fireEvent.click( + container.querySelector(".document-modal-overlay"), + ); + + expect(onClose).toHaveBeenCalledTimes(1); + }); + + it("chama onViewPdf ao clicar em Visualizar", () => { + const onViewPdf = vi.fn(); + + render( + , + ); + + fireEvent.click( + screen.getByRole("button", { name: /visualizar/i }), + ); + + expect(onViewPdf).toHaveBeenCalledWith(document); + }); +}); diff --git a/src/components/Pagination/Pagination.test.jsx b/src/components/Pagination/Pagination.test.jsx new file mode 100644 index 0000000..742fc59 --- /dev/null +++ b/src/components/Pagination/Pagination.test.jsx @@ -0,0 +1,78 @@ +import { fireEvent, render, screen } from "@testing-library/react"; +import { describe, expect, it, vi } from "vitest"; + +import Pagination from "./Pagination"; + +describe("Pagination", () => { + it("não renderiza quando existe apenas uma página", () => { + render( + , + ); + + expect( + screen.queryByRole("button", { name: /página anterior/i }), + ).not.toBeInTheDocument(); + }); + + it("renderiza todas as páginas", () => { + render( + , + ); + + expect(screen.getByRole("button", { name: "1" })).toBeInTheDocument(); + expect(screen.getByRole("button", { name: "2" })).toBeInTheDocument(); + expect(screen.getByRole("button", { name: "3" })).toBeInTheDocument(); + }); + + it("chama onPageChange ao selecionar uma página", () => { + const onPageChange = vi.fn(); + + render( + , + ); + + fireEvent.click(screen.getByRole("button", { name: "2" })); + + expect(onPageChange).toHaveBeenCalledWith(2); + }); + + it("desabilita a página anterior na primeira página", () => { + render( + , + ); + + expect( + screen.getByRole("button", { name: /página anterior/i }), + ).toBeDisabled(); + }); + + it("desabilita a próxima página na última página", () => { + render( + , + ); + + expect( + screen.getByRole("button", { name: /próxima página/i }), + ).toBeDisabled(); + }); +}); diff --git a/src/components/SearchBar/SearchBar.test.jsx b/src/components/SearchBar/SearchBar.test.jsx new file mode 100644 index 0000000..ce53584 --- /dev/null +++ b/src/components/SearchBar/SearchBar.test.jsx @@ -0,0 +1,55 @@ +import { fireEvent, render, screen } from "@testing-library/react"; +import { describe, expect, it, vi } from "vitest"; + +import SearchBar from "./SearchBar"; + +describe("SearchBar", () => { + it("renderiza o campo de pesquisa", () => { + render( + , + ); + + expect( + screen.getByPlaceholderText("Pesquisar documentos..."), + ).toBeInTheDocument(); + }); + + it("renderiza o valor recebido", () => { + render( + , + ); + + expect( + screen.getByDisplayValue("NASA"), + ).toBeInTheDocument(); + }); + + it("chama onChange com o novo valor", () => { + const onChange = vi.fn(); + + render( + , + ); + + const input = screen.getByPlaceholderText( + "Pesquisar documentos...", + ); + + fireEvent.change(input, { + target: { + value: "MIL-HDBK", + }, + }); + + expect(onChange).toHaveBeenCalledWith("MIL-HDBK"); + }); +}); diff --git a/src/pages/Home.test.jsx b/src/pages/Home.test.jsx new file mode 100644 index 0000000..b94021c --- /dev/null +++ b/src/pages/Home.test.jsx @@ -0,0 +1,116 @@ +import { fireEvent, render, screen } from "@testing-library/react"; +import { describe, expect, it } from "vitest"; + +import Home from "./Home"; + +describe("Home", () => { + it("renderiza a página de documentos", () => { + render(); + + expect( + screen.getByRole("heading", { name: "Documentos" }), + ).toBeInTheDocument(); + + expect( + screen.getByPlaceholderText("Pesquisar documentos..."), + ).toBeInTheDocument(); + }); + + it("renderiza os documentos da primeira página", () => { + render(); + + expect( + screen.getByText( + "DEPARTMENT OF DEFENSE HANDBOOK: METALLIC MATERIALS AND ELEMENTS FOR AEROSPACE VEHICLE STRUCTURES", + ), + ).toBeInTheDocument(); + + expect( + screen.getByText( + "SPECIFICATION FOR MANUFACTURERS' TECHNICAL DATA AND AIRCRAFT DOCUMENTATION", + ), + ).toBeInTheDocument(); + }); + + it("filtra documentos pelo nome", () => { + render(); + + const input = screen.getByPlaceholderText( + "Pesquisar documentos...", + ); + + fireEvent.change(input, { + target: { + value: "STRUCTURAL", + }, + }); + + expect( + screen.getByText( + "STRUCTURAL DESIGN AND TEST FACTORS OF SAFETY FOR SPACEFLIGHT HARDWARE", + ), + ).toBeInTheDocument(); + + expect( + screen.queryByText( + "DEPARTMENT OF DEFENSE HANDBOOK: METALLIC MATERIALS AND ELEMENTS FOR AEROSPACE VEHICLE STRUCTURES", + ), + ).not.toBeInTheDocument(); + }); + + it("abre o modal ao clicar em Visualizar", () => { + render(); + + const buttons = screen.getAllByRole("button", { + name: /visualizar/i, + }); + + fireEvent.click(buttons[0]); + + expect( + screen.getByText("Código da norma"), + ).toBeInTheDocument(); + + expect( + screen.getByText("MIL-HDBK-5J"), + ).toBeInTheDocument(); + }); + + it("fecha o modal ao clicar em Fechar", () => { + render(); + + const buttons = screen.getAllByRole("button", { + name: /visualizar/i, + }); + + fireEvent.click(buttons[0]); + + fireEvent.click( + screen.getByRole("button", { name: "Fechar" }), + ); + + expect( + screen.queryByText("Código da norma"), + ).not.toBeInTheDocument(); + }); + + it("abre a segunda página", () => { + render(); + + fireEvent.click( + screen.getByRole("button", { name: "2" }), + ); + + expect( + screen.getByText( + "DESIGN ASSURANCE GUIDANCE FOR AIRBORNE ELECTRONIC HARDWARE", + ), + ).toBeInTheDocument(); + + expect( + screen.queryByText( + "DEPARTMENT OF DEFENSE HANDBOOK: METALLIC MATERIALS AND ELEMENTS FOR AEROSPACE VEHICLE STRUCTURES", + ), + ).not.toBeInTheDocument(); + }); +}); \ No newline at end of file From dba699f427a89dd731994e9ee5131cca8386f396 Mon Sep 17 00:00:00 2001 From: GloBrito Date: Thu, 17 Sep 2026 02:25:45 -0300 Subject: [PATCH 33/52] chore(a6-24): ignores generated coverage files --- eslint.config.js | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/eslint.config.js b/eslint.config.js index ea36dd3..1021f5e 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -1,13 +1,13 @@ -import js from '@eslint/js' -import globals from 'globals' -import reactHooks from 'eslint-plugin-react-hooks' -import reactRefresh from 'eslint-plugin-react-refresh' -import { defineConfig, globalIgnores } from 'eslint/config' +import js from "@eslint/js"; +import globals from "globals"; +import reactHooks from "eslint-plugin-react-hooks"; +import reactRefresh from "eslint-plugin-react-refresh"; +import { defineConfig, globalIgnores } from "eslint/config"; export default defineConfig([ - globalIgnores(['dist']), + globalIgnores(["dist", "coverage"]), { - files: ['**/*.{js,jsx}'], + files: ["**/*.{js,jsx}"], extends: [ js.configs.recommended, reactHooks.configs.flat.recommended, @@ -15,7 +15,11 @@ export default defineConfig([ ], languageOptions: { globals: globals.browser, - parserOptions: { ecmaFeatures: { jsx: true } }, + parserOptions: { + ecmaFeatures: { + jsx: true, + }, + }, }, }, -]) +]); \ No newline at end of file From 2da6f730f210722e6adab4c7d72400a9edb270c7 Mon Sep 17 00:00:00 2001 From: GloBrito Date: Thu, 17 Sep 2026 02:25:51 -0300 Subject: [PATCH 34/52] chore(a6-24): ignores frontend test artifacts --- .gitignore | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.gitignore b/.gitignore index a547bf3..e530176 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,9 @@ dist-ssr *.njsproj *.sln *.sw? + +# Relatórios gerados pelos testes +coverage/ + +# PyCharm / JetBrains +.idea/ From 2587ee9cedc0b296719db563509285250be39ad2 Mon Sep 17 00:00:00 2001 From: GloBrito Date: Thu, 17 Sep 2026 02:25:57 -0300 Subject: [PATCH 35/52] ci(a6-24): configures frontend coverage for sonar --- sonar-project.properties | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/sonar-project.properties b/sonar-project.properties index 07db20a..09ae34a 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -1,14 +1,18 @@ sonar.projectKey=SQLutionsFATEC_API-6-Semestre-Frontend sonar.organization=sqlutionsfatec-2 - -# This is the name and version displayed in the SonarCloud UI. sonar.projectName=Analysis Frontend sonar.projectVersion=1.0 - -# Path is relative to the sonar-project.properties file. Replace "\" by "/" on Windows. sonar.sources=src +sonar.tests=src + +sonar.test.inclusions=src/**/*.test.js,src/**/*.test.jsx,src/**/*.spec.js,src/**/*.spec.jsx + +sonar.exclusions=src/**/*.test.js,src/**/*.test.jsx,src/**/*.spec.js,src/**/*.spec.jsx,src/test/** + +sonar.coverage.exclusions=src/**/*.test.js,src/**/*.test.jsx,src/**/*.spec.js,src/**/*.spec.jsx,src/test/**,src/main.jsx + +sonar.javascript.lcov.reportPaths=coverage/lcov.info -# Encoding of the source code. Default is default system encoding -sonar.sourceEncoding=UTF-8 +sonar.sourceEncoding=UTF-8 \ No newline at end of file From 13a372347e8250e4bc751d0b5bff1537d695a267 Mon Sep 17 00:00:00 2001 From: GloBrito Date: Thu, 17 Sep 2026 02:26:02 -0300 Subject: [PATCH 36/52] ci(a6-24): runs frontend tests before sonar analysis --- .github/workflows/ci-frontend.yml | 64 +++++++++++++++---------------- 1 file changed, 30 insertions(+), 34 deletions(-) diff --git a/.github/workflows/ci-frontend.yml b/.github/workflows/ci-frontend.yml index 7d48809..e24b53c 100644 --- a/.github/workflows/ci-frontend.yml +++ b/.github/workflows/ci-frontend.yml @@ -4,12 +4,17 @@ on: push: branches: - main - - "develop-*" + - develop-1 + pull_request: branches: - main - - "develop-*" - types: [opened, synchronize, reopened] + - develop-1 + types: + - opened + - synchronize + - reopened + workflow_dispatch: permissions: @@ -21,53 +26,44 @@ concurrency: cancel-in-progress: true jobs: - commit-build: - name: "Estágio 1: qualidade e build" + frontend-ci: + name: Tests, Build and SonarCloud runs-on: ubuntu-latest timeout-minutes: 10 steps: - - name: Checkout do código - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 + - name: Checkout repository + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 + with: + fetch-depth: 0 - - name: Configurar Node.js + - name: Set up Node.js uses: actions/setup-node@v4 with: node-version: "22" cache: npm cache-dependency-path: package-lock.json - - name: Instalar dependências + - name: Install dependencies run: npm ci - - name: Executar análise estática com ESLint + - name: Run ESLint run: npm run lint - - name: Gerar build de produção - run: npm run build + - name: Run tests with coverage + run: npm run test:coverage - secondary-build: - name: "Estágio 2: análise no SonarCloud" - runs-on: ubuntu-latest - timeout-minutes: 10 - needs: commit-build - env: - SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Build production application + run: npm run build - steps: - - name: Checkout do código - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 - with: - fetch-depth: 0 + - name: Verify coverage report + run: | + test -f coverage/lcov.info + echo "LCOV coverage report generated successfully." + ls -lh coverage/lcov.info - - name: Executar análise no SonarCloud - if: env.SONAR_TOKEN != '' - uses: SonarSource/sonarqube-scan-action@7006c4492b2e0ee0f816d36501671557c97f5995 # v8.1.0 + - name: Run SonarCloud analysis + uses: SonarSource/sonarqube-scan-action@7006c4492b2e0ee0f816d36501671557c97f5995 env: - SONAR_TOKEN: ${{ env.SONAR_TOKEN }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: Informar ausência do token do SonarCloud - if: env.SONAR_TOKEN == '' - run: echo "::notice::SonarCloud não executado porque o secret SONAR_TOKEN não está disponível." + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file From 46257b7d1510a8ca1a81d55ad60ed73021b699b7 Mon Sep 17 00:00:00 2001 From: Daniel Sendreti Date: Sun, 20 Sep 2026 19:28:29 -0300 Subject: [PATCH 37/52] feat(26): add document detail service and test setup --- eslint.config.js | 2 +- package-lock.json | 1059 ++++++++++++++++++++- package.json | 10 +- src/services/documentService.js | 8 +- src/services/documentService.test.js | 24 + src/tests/coverage/DocumentoList.test.jsx | 19 +- src/tests/coverage/Home.test.jsx | 18 +- src/tests/setup.js | 7 + vite.config.js | 7 +- 9 files changed, 1127 insertions(+), 27 deletions(-) create mode 100644 src/services/documentService.test.js create mode 100644 src/tests/setup.js diff --git a/eslint.config.js b/eslint.config.js index ea36dd3..27d7035 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -5,7 +5,7 @@ import reactRefresh from 'eslint-plugin-react-refresh' import { defineConfig, globalIgnores } from 'eslint/config' export default defineConfig([ - globalIgnores(['dist']), + globalIgnores(['dist', 'ignore']), { files: ['**/*.{js,jsx}'], extends: [ diff --git a/package-lock.json b/package-lock.json index e9d706c..383577d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,6 +15,8 @@ }, "devDependencies": { "@eslint/js": "^10.0.1", + "@testing-library/jest-dom": "^7.0.1", + "@testing-library/react": "^16.3.3", "@types/react": "^19.2.18", "@types/react-dom": "^19.2.4", "@vitejs/plugin-react": "^6.1.0", @@ -22,7 +24,69 @@ "eslint-plugin-react-hooks": "^7.1.1", "eslint-plugin-react-refresh": "^0.5.4", "globals": "^17.11.0", - "vite": "^8.2.2" + "jsdom": "^30.1.0", + "vite": "^8.2.2", + "vitest": "^5.0.1" + } + }, + "node_modules/@adobe/css-tools": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.5.0.tgz", + "integrity": "sha512-6OzddxPio9UiWTCemp4N8cYLV2ZN1ncRnV1cVGtve7dhPOtRkleRyx32GQCYSwDYgaHU3USMm84tNsvKzRCa1Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@asamuzakjp/css-color": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-7.0.0.tgz", + "integrity": "sha512-IxddtGnnoidVSO6O/aiTueptbTThHvi2qGHu9/AWuD1J7i86Ox+jl+Y5SXcDH1RixzQlP2cjH/PjnlImZiAurQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@csstools/css-calc": "^3.3.0", + "@csstools/css-color-parser": "^4.2.0", + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-tokenizer": "^4.0.0", + "lru-cache": "^11.5.2" + }, + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + } + }, + "node_modules/@asamuzakjp/css-color/node_modules/lru-cache": { + "version": "11.5.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.3.tgz", + "integrity": "sha512-U4N8FgzmWxc8k1VH8Kr6lQg18U7Fjvby6wXHVRX/ZZ7IwWbRMgrRbP0Wrb5q5NVinryp4SQampHKdvtecItxUg==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/@asamuzakjp/dom-selector": { + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/@asamuzakjp/dom-selector/-/dom-selector-9.2.1.tgz", + "integrity": "sha512-NT4s3yZLjovPpliRpTvdsdzyPjqRqiCZj9MxnarBihbaY5MbAG7DWAJcrLlhmC7xKTNCXsTELcqB8YsqpLnUFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "bidi-js": "^1.1.0", + "css-tree": "^3.2.1", + "is-potential-custom-element-name": "^1.0.1", + "lru-cache": "^11.5.3" + }, + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + } + }, + "node_modules/@asamuzakjp/dom-selector/node_modules/lru-cache": { + "version": "11.5.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.3.tgz", + "integrity": "sha512-U4N8FgzmWxc8k1VH8Kr6lQg18U7Fjvby6wXHVRX/ZZ7IwWbRMgrRbP0Wrb5q5NVinryp4SQampHKdvtecItxUg==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" } }, "node_modules/@babel/code-frame": { @@ -217,6 +281,16 @@ "node": ">=6.0.0" } }, + "node_modules/@babel/runtime": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.7.tgz", + "integrity": "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/template": { "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", @@ -265,6 +339,19 @@ "node": ">=6.9.0" } }, + "node_modules/@bramus/specificity": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@bramus/specificity/-/specificity-2.4.2.tgz", + "integrity": "sha512-ctxtJ/eA+t+6q2++vj5j7FYX3nRu311q1wfYH3xjlLOsczhlhxAg2FWNUXhpGvAw3BWo1xBcvOV6/YLc2r5FJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "css-tree": "^3.0.0" + }, + "bin": { + "specificity": "bin/cli.js" + } + }, "node_modules/@cacheable/memory": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/@cacheable/memory/-/memory-2.2.0.tgz", @@ -289,6 +376,146 @@ "keyv": "^5.6.0" } }, + "node_modules/@csstools/color-helpers": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-6.1.1.tgz", + "integrity": "sha512-gLNsunvwf3mCi5u5o46/Z/JcJMnhbHSaZ69rkgPzNM3J4s8hWwpPUQB6/tt0EDFyCiWzxANlx+2LJwpYj4zS1w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=20.19.0" + } + }, + "node_modules/@csstools/css-calc": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-3.4.0.tgz", + "integrity": "sha512-XQKj5B7QiZcHiegCOCAzcAOJdhGgWOHbbu62h5e5mkHnn8lWcfiJhllkqWmxu5zWR9jucPHuo1iTB56P033hcg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-tokenizer": "^4.0.0" + } + }, + "node_modules/@csstools/css-color-parser": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-4.2.3.tgz", + "integrity": "sha512-y4LpL+lmpuyKDiEFq2PnZUVFdAjsoB/qQJod79yLNokXyW7jewi+/WJ69EfItj8A2unWtxXnGjw6LYXgXu5ZjA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "dependencies": { + "@csstools/color-helpers": "^6.1.1", + "@csstools/css-calc": "^3.4.0" + }, + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-tokenizer": "^4.0.0" + } + }, + "node_modules/@csstools/css-parser-algorithms": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-4.0.0.tgz", + "integrity": "sha512-+B87qS7fIG3L5h3qwJ/IFbjoVoOe/bpOdh9hAjXbvx0o8ImEmUsGXN0inFOnk2ChCFgqkkGFQ+TpM5rbhkKe4w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "@csstools/css-tokenizer": "^4.0.0" + } + }, + "node_modules/@csstools/css-syntax-patches-for-csstree": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.1.14.tgz", + "integrity": "sha512-HpbVXyrofRXpHpgkNIjU/3EWR4WJvOkO3emNK/L6X/mTJU7bGUI3AkkpoTNXznQLp0KRjLHELTGeKI5dIkI9JQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "peerDependencies": { + "css-tree": "^3.2.1" + }, + "peerDependenciesMeta": { + "css-tree": { + "optional": true + } + } + }, + "node_modules/@csstools/css-tokenizer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-4.0.1.tgz", + "integrity": "sha512-bPlN9S9O1A0euCpEWE4qnvB5YDuyYVsUTrxSgmAM1Is0j4tICHoVyOVAXfWMP/kS9ZrjvyIXWV2PmomiAXXqOw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=20.19.0" + } + }, "node_modules/@eslint-community/eslint-utils": { "version": "4.10.1", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.10.1.tgz", @@ -417,6 +644,24 @@ "node": "^20.19.0 || ^22.13.0 || >=24" } }, + "node_modules/@exodus/bytes": { + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/@exodus/bytes/-/bytes-1.15.1.tgz", + "integrity": "sha512-S6mL0yNB/Abt9Ei4tq8gDhcczc4S3+vQ4ra7vxnAf+YHC02srtqxKKZghx2Dq6p0e66THKwR6r8N6P95wEty7Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + }, + "peerDependencies": { + "@noble/hashes": "^1.8.0 || ^2.0.0" + }, + "peerDependenciesMeta": { + "@noble/hashes": { + "optional": true + } + } + }, "node_modules/@humanfs/core": { "version": "0.19.2", "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz", @@ -829,6 +1074,117 @@ "dev": true, "license": "MIT" }, + "node_modules/@testing-library/dom": { + "version": "10.4.2", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.2.tgz", + "integrity": "sha512-yzr2S9HyAIdhz2/6qHgbs665Q7PKVcDF05vsOlHPxG1mo36gKVesdYVeDLnXgfjJ03CrKRk08knc6+E/9m8v2Q==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^5.0.1", + "aria-query": "5.3.0", + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.5.0", + "picocolors": "1.1.1", + "pretty-format": "^27.0.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@testing-library/jest-dom": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-7.0.1.tgz", + "integrity": "sha512-oMDTC3oA+6CXSO2JZnvOI7CA6oVub6kij5ggk9ohwye5slmkwxYDXcPOVxgMw/RQlticjtO0C1RZkR97HgrWMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@adobe/css-tools": "^4.4.0", + "aria-query": "^5.0.0", + "css.escape": "^1.5.1", + "dom-accessibility-api": "^0.6.3", + "picocolors": "^1.1.1", + "redent": "^3.0.0" + }, + "engines": { + "node": ">=22", + "npm": ">=6", + "yarn": ">=1" + }, + "peerDependencies": { + "@testing-library/dom": ">=10 <11", + "vitest": ">= 0.32" + }, + "peerDependenciesMeta": { + "vitest": { + "optional": true + } + } + }, + "node_modules/@testing-library/jest-dom/node_modules/dom-accessibility-api": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.6.3.tgz", + "integrity": "sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@testing-library/react": { + "version": "16.3.3", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-16.3.3.tgz", + "integrity": "sha512-Uo193NgQbPMz6lrrhtRQQFcMC6Re/ELLFbbuVL30WDlZxlpZf9/lMHTAVxPRLw1q1iu9OJmR1c2BLiENRstdBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.12.5" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@testing-library/dom": "^10.0.0", + "@types/react": "^18.0.0 || ^19.0.0", + "@types/react-dom": "^18.0.0 || ^19.0.0", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@types/aria-query": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", + "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/@types/chai": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", + "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" + } + }, + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/esrecurse": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/@types/esrecurse/-/esrecurse-4.3.1.tgz", @@ -900,6 +1256,44 @@ } } }, + "node_modules/@vitest/mocker": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-5.0.1.tgz", + "integrity": "sha512-6K1DoBNAPGvuOcSsGA4D6x+5zEEff/KmOOP3uetT2TrGpVfI+HRHRnJJfKi5ib/g1vx8IYHQD8s0pbJz8WQI7Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "0.3.31", + "@vitest/spy": "5.0.1", + "estree-walker": "^3.0.3", + "magic-string": "^1.2.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@vitest/spy": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-5.0.1.tgz", + "integrity": "sha512-rbto/mF/SGERxEgYOek7Xm6B9b+y+mVoo+f4b2LymYO8zM1b7uB5nHuhVMTP2hxdzgxvGiZYGxGIaMvL5y180Q==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://opencollective.com/vitest" + } + }, "node_modules/acorn": { "version": "8.18.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.18.0.tgz", @@ -952,6 +1346,51 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/aria-query": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", + "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "dequal": "^2.0.3" + } + }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -993,6 +1432,16 @@ "node": ">=6.0.0" } }, + "node_modules/bidi-js": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/bidi-js/-/bidi-js-1.1.0.tgz", + "integrity": "sha512-fX1Onk0tdVPC7obPWB5EbJ1z7NVhLq4m2xZLq2YXBkxzMXIGRpNMU88n0EPgWseKl12J7zXs7qrDxPK4sRs2fg==", + "dev": true, + "license": "MIT", + "dependencies": { + "require-from-string": "^2.0.2" + } + }, "node_modules/brace-expansion": { "version": "5.0.12", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz", @@ -1088,6 +1537,16 @@ ], "license": "CC-BY-4.0" }, + "node_modules/chai": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", + "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -1122,6 +1581,27 @@ "node": ">= 8" } }, + "node_modules/css-tree": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.2.1.tgz", + "integrity": "sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "mdn-data": "2.27.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + } + }, + "node_modules/css.escape": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", + "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==", + "dev": true, + "license": "MIT" + }, "node_modules/csstype": { "version": "3.2.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", @@ -1129,6 +1609,35 @@ "dev": true, "license": "MIT" }, + "node_modules/data-urls": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-7.0.0.tgz", + "integrity": "sha512-23XHcCF+coGYevirZceTVD7NdJOqVn+49IHyxgszm+JIiHLoB2TkmPtsYkNWT1pvRSGkc35L6NHs0yHkN2SumA==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-mimetype": "^5.0.0", + "whatwg-url": "^16.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, + "node_modules/data-urls/node_modules/whatwg-url": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-16.0.1.tgz", + "integrity": "sha512-1to4zXBxmXHV3IiSSEInrreIlu02vUOvrhxJJH5vcxYTBDAx51cqZiKdyTxlecdKNSjj8EcxGBxNf6Vg+945gw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@exodus/bytes": "^1.11.0", + "tr46": "^6.0.0", + "webidl-conversions": "^8.0.1" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, "node_modules/debug": { "version": "4.4.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", @@ -1146,6 +1655,13 @@ } } }, + "node_modules/decimal.js": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz", + "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==", + "dev": true, + "license": "MIT" + }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -1162,6 +1678,16 @@ "node": ">=0.4.0" } }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/detect-libc": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", @@ -1172,6 +1698,14 @@ "node": ">=8" } }, + "node_modules/dom-accessibility-api": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", + "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", + "dev": true, + "license": "MIT", + "peer": true + }, "node_modules/dunder-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", @@ -1193,6 +1727,19 @@ "dev": true, "license": "ISC" }, + "node_modules/entities": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-8.1.0.tgz", + "integrity": "sha512-kxL7msIffSuh9aaFAMD7rxAIuTRMAHMeBtgHW2yUdWw732ZNh4MehkF2gdjvtdmikkaIP9bFDDJOPlsvm7avrA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=20.19.0" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/es-define-property": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", @@ -1211,6 +1758,13 @@ "node": ">= 0.4" } }, + "node_modules/es-module-lexer": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.3.2.tgz", + "integrity": "sha512-poHGpORABojJJucnV9KbOavETW8lBVnphkW77ER5/BQ5Fz7oXSoCNek7IH3vR5nRjdsEz926ibFYX8KtLQmdyw==", + "dev": true, + "license": "MIT" + }, "node_modules/es-object-atoms": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", @@ -1436,6 +1990,16 @@ "node": ">=4.0" } }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, "node_modules/esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", @@ -1443,7 +2007,17 @@ "dev": true, "license": "BSD-2-Clause", "engines": { - "node": ">=0.10.0" + "node": ">=0.10.0" + } + }, + "node_modules/expect-type": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.4.0.tgz", + "integrity": "sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" } }, "node_modules/fast-deep-equal": { @@ -1752,6 +2326,19 @@ "dev": true, "license": "MIT" }, + "node_modules/html-encoding-sniffer": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-6.0.0.tgz", + "integrity": "sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@exodus/bytes": "^1.6.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, "node_modules/https-proxy-agent": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", @@ -1785,6 +2372,16 @@ "node": ">=0.8.19" } }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -1808,6 +2405,13 @@ "node": ">=0.10.0" } }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true, + "license": "MIT" + }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -1822,6 +2426,56 @@ "dev": true, "license": "MIT" }, + "node_modules/jsdom": { + "version": "30.1.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-30.1.0.tgz", + "integrity": "sha512-h/Q+H+KmlGf49ITw3TrykSVbg04S75S2O7ZtJc9gMGOWBrQRZmx5AJIKLtJ01e6Kszl+/tpFthCVqxNifxhoqg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@asamuzakjp/css-color": "^7.0.0", + "@asamuzakjp/dom-selector": "^9.1.2", + "@bramus/specificity": "^2.4.2", + "@csstools/css-syntax-patches-for-csstree": "^1.1.13", + "@exodus/bytes": "^1.15.1", + "css-tree": "^3.2.1", + "data-urls": "^7.0.0", + "decimal.js": "^10.6.0", + "html-encoding-sniffer": "^6.0.0", + "is-potential-custom-element-name": "^1.0.1", + "lru-cache": "^11.5.2", + "parse5": "^8.0.1", + "saxes": "^6.0.0", + "tough-cookie": "^6.0.2", + "undici": "^8.10.2", + "w3c-xmlserializer": "^5.0.0", + "webidl-conversions": "^8.0.1", + "whatwg-mimetype": "^5.0.0", + "whatwg-url": "^17.1.1", + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + }, + "peerDependencies": { + "canvas": "^3.2.3" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/jsdom/node_modules/lru-cache": { + "version": "11.5.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.3.tgz", + "integrity": "sha512-U4N8FgzmWxc8k1VH8Kr6lQg18U7Fjvby6wXHVRX/ZZ7IwWbRMgrRbP0Wrb5q5NVinryp4SQampHKdvtecItxUg==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, "node_modules/jsesc": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", @@ -2173,6 +2827,27 @@ "yallist": "^3.0.2" } }, + "node_modules/lz-string": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", + "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", + "dev": true, + "license": "MIT", + "peer": true, + "bin": { + "lz-string": "bin/bin.js" + } + }, + "node_modules/magic-string": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-1.4.1.tgz", + "integrity": "sha512-8lyCu36ErXR0J9uaGKlKQoiLZKmtI63YGLE8G2o9jyRPdr4X47LusSOwgOJOzcVtp81fTAAjxR7BwKz682Jhow==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.6.0" + } + }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", @@ -2182,6 +2857,13 @@ "node": ">= 0.4" } }, + "node_modules/mdn-data": { + "version": "2.27.1", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.27.1.tgz", + "integrity": "sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==", + "dev": true, + "license": "CC0-1.0" + }, "node_modules/mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", @@ -2203,6 +2885,16 @@ "node": ">= 0.6" } }, + "node_modules/min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/minimatch": { "version": "10.2.6", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz", @@ -2261,6 +2953,20 @@ "node": ">=18" } }, + "node_modules/obug": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/obug/-/obug-2.2.1.tgz", + "integrity": "sha512-XrsrhT5sybtKI6wakr2SPOlGZWWYbUXZ7a0jT8/QOeAPau+1X/bSegNe5YR75oJmEZQbKningirmGOEJCIk61Q==", + "dev": true, + "funding": [ + "https://github.com/sponsors/sxzz", + "https://opencollective.com/debug" + ], + "license": "MIT", + "engines": { + "node": ">=12.20.0" + } + }, "node_modules/optionator": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", @@ -2311,6 +3017,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/parse5": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-8.0.1.tgz", + "integrity": "sha512-z1e/HMG90obSGeidlli3hj7cbocou0/wa5HacvI3ASx34PecNjNQeaHNo5WIZpWofN9kgkqV1q5YvXe3F0FoPw==", + "dev": true, + "license": "MIT", + "dependencies": { + "entities": "^8.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -2390,6 +3109,22 @@ "node": ">= 0.8.0" } }, + "node_modules/pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, "node_modules/proxy-from-env": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz", @@ -2459,6 +3194,38 @@ "react": "*" } }, + "node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/redent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/rolldown": { "version": "1.2.9", "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.9.tgz", @@ -2493,6 +3260,19 @@ "@rolldown/binding-win32-x64-msvc": "1.2.9" } }, + "node_modules/saxes": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", + "dev": true, + "license": "ISC", + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=v12.22.7" + } + }, "node_modules/scheduler": { "version": "0.28.0", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.28.0.tgz", @@ -2532,6 +3312,13 @@ "node": ">=8" } }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true, + "license": "ISC" + }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -2542,6 +3329,53 @@ "node": ">=0.10.0" } }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true, + "license": "MIT" + }, + "node_modules/std-env": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.2.0.tgz", + "integrity": "sha512-oCUKSupKTHX53EyjDtuZQ64pjLJ6yYCtpmEw0goYxtjG9KpbRe8KAsl2tBUGU9DyMcJ0RwJ8GqJAFzMXcXW1Rw==", + "dev": true, + "license": "MIT" + }, + "node_modules/strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "min-indent": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tinybench": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-6.1.4.tgz", + "integrity": "sha512-9APumHG7r4yOk4X4WlkmE71aZcv1gvin1czO3OQ1U9iJcFA5Ja/ygyb0vPOVHTthFozUYs8CLoLUlM8grb2lTQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/tinyexec": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.3.0.tgz", + "integrity": "sha512-QKAl9m8gWWGHV8jZcPeym6j+XULi6tOf1mT83WYJ4Lk2ytW/uwAWkrP0uFsdoYMdueVJ0qs26wZ+23xeB4ibNQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/tinyglobby": { "version": "0.2.17", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", @@ -2559,6 +3393,52 @@ "url": "https://github.com/sponsors/SuperchupuDev" } }, + "node_modules/tldts": { + "version": "7.4.13", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-7.4.13.tgz", + "integrity": "sha512-iHtaIWWIbMDkCeJdTBzZFGgbluE5J+oHlb2g7+oAz1S1gpuVpabRZdQyd471Vl8UUkcz2vXSL8xZH2kyCe8tfA==", + "dev": true, + "license": "MIT", + "dependencies": { + "tldts-core": "^7.4.13" + }, + "bin": { + "tldts": "bin/cli.js" + } + }, + "node_modules/tldts-core": { + "version": "7.4.13", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-7.4.13.tgz", + "integrity": "sha512-mbYsrih5FRtGxs3Usvl/PqwJsNpp+jsmrdFviiK02teHDG0/HebBG/pqCylje3kzgXYzuLoHJF/0mz9W53t8Xg==", + "dev": true, + "license": "MIT" + }, + "node_modules/tough-cookie": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-6.0.2.tgz", + "integrity": "sha512-exgYmnmL/sJpR3upZfXG5PoatXQii55xAiXGXzY+sROLZ/Y+SLcp9PgJNI9Vz37HpQ74WvDcLT8eqm+kV3FzrA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "tldts": "^7.0.5" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/tr46": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-6.0.0.tgz", + "integrity": "sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==", + "dev": true, + "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" + }, + "engines": { + "node": ">=20" + } + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -2572,6 +3452,16 @@ "node": ">= 0.8.0" } }, + "node_modules/undici": { + "version": "8.10.2", + "resolved": "https://registry.npmjs.org/undici/-/undici-8.10.2.tgz", + "integrity": "sha512-/y4/bH9YNU5hi9NIrpOuvGXFcxrj3CMrV+/AYpowAYTpHn8gX/XPFjNy766FPoYY0miQhdW977JFWKGNhBdwyQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=22.19.0" + } + }, "node_modules/update-browserslist-db": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.3.3.tgz", @@ -2691,6 +3581,137 @@ } } }, + "node_modules/vitest": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-5.0.1.tgz", + "integrity": "sha512-iA95lQbKEkvrtTkdAgnWbXfbipWiiWe/hDl2P5tMi6WFwD76G0NxXAGp/M9EOcYupeGJRr6wppMc7CoA41TQjg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/chai": "^5.2.2", + "@vitest/mocker": "5.0.1", + "chai": "^6.2.2", + "es-module-lexer": "^2.3.2", + "expect-type": "^1.4.0", + "magic-string": "^1.2.3", + "obug": "^2.1.4", + "picomatch": "^4.0.7", + "std-env": "^4.2.0", + "tinybench": "6.1.4", + "tinyexec": "1.3.0", + "tinyglobby": "^0.2.17", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^22.12.0 || ^24.0.0 || >=26.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@opentelemetry/api": "^1.9.0", + "@types/node": "^22.0.0 || >=24.0.0", + "@vitest/browser-playwright": "5.0.1", + "@vitest/browser-preview": "5.0.1", + "@vitest/browser-webdriverio": "^5.0.0-beta.5 || >=5.0.0", + "@vitest/coverage-istanbul": "5.0.1", + "@vitest/coverage-v8": "5.0.1", + "@vitest/ui": "5.0.1", + "happy-dom": "*", + "jsdom": "*", + "vite": "^6.4.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@opentelemetry/api": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser-playwright": { + "optional": true + }, + "@vitest/browser-preview": { + "optional": true + }, + "@vitest/browser-webdriverio": { + "optional": true + }, + "@vitest/coverage-istanbul": { + "optional": true + }, + "@vitest/coverage-v8": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + }, + "vite": { + "optional": false + } + } + }, + "node_modules/w3c-xmlserializer": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", + "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/webidl-conversions": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-8.0.1.tgz", + "integrity": "sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=20" + } + }, + "node_modules/whatwg-mimetype": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-5.0.0.tgz", + "integrity": "sha512-sXcNcHOC51uPGF0P/D4NVtrkjSU2fNsm9iog4ZvZJsL3rjoDAzXZhkm2MWt1y+PUdggKAYVoMAIYcs78wJ51Cw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + } + }, + "node_modules/whatwg-url": { + "version": "17.1.1", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-17.1.1.tgz", + "integrity": "sha512-ohjk1mdUebJVadRt3bAhQhx8lSnISq+GDttK79LFl8EHQkAPvzwctoasC4hs8tBt6kLAncBWWyq1N52qEfKvDw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@exodus/bytes": "^1.15.1", + "tr46": "^6.0.0", + "webidl-conversions": "^8.0.1" + }, + "engines": { + "node": "^22.14.0 || >=24.0.0" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -2707,6 +3728,23 @@ "node": ">= 8" } }, + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/word-wrap": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", @@ -2717,6 +3755,23 @@ "node": ">=0.10.0" } }, + "node_modules/xml-name-validator": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", + "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true, + "license": "MIT" + }, "node_modules/yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", diff --git a/package.json b/package.json index e53069e..c9dca8d 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,9 @@ "dev": "vite", "build": "vite build", "lint": "eslint .", - "preview": "vite preview" + "preview": "vite preview", + "test": "vitest run", + "test:watch": "vitest" }, "dependencies": { "axios": "^1.20.0", @@ -17,6 +19,8 @@ }, "devDependencies": { "@eslint/js": "^10.0.1", + "@testing-library/jest-dom": "^7.0.1", + "@testing-library/react": "^16.3.3", "@types/react": "^19.2.18", "@types/react-dom": "^19.2.4", "@vitejs/plugin-react": "^6.1.0", @@ -24,6 +28,8 @@ "eslint-plugin-react-hooks": "^7.1.1", "eslint-plugin-react-refresh": "^0.5.4", "globals": "^17.11.0", - "vite": "^8.2.2" + "jsdom": "^30.1.0", + "vite": "^8.2.2", + "vitest": "^5.0.1" } } diff --git a/src/services/documentService.js b/src/services/documentService.js index 469ecf6..c8f3462 100644 --- a/src/services/documentService.js +++ b/src/services/documentService.js @@ -9,4 +9,10 @@ export async function fetchDocuments({ nome = "", page = 1 } = {}) { }); return response.data; -} \ No newline at end of file +} + +export async function fetchDocumentById(idDocumento) { + const response = await api.get(`/api/documentos/${idDocumento}/`); + + return response.data; +} diff --git a/src/services/documentService.test.js b/src/services/documentService.test.js new file mode 100644 index 0000000..f510601 --- /dev/null +++ b/src/services/documentService.test.js @@ -0,0 +1,24 @@ +import { describe, expect, it, vi } from 'vitest' + +import api from './api' +import { fetchDocumentById } from './documentService' + +vi.mock('./api', () => ({ + default: { + get: vi.fn(), + }, +})) + +describe('fetchDocumentById', () => { + it('busca o detalhe do documento pelo id e retorna o payload da API', async () => { + const document = { + id_documento: 42, + nome: 'Manual.pdf', + etiquetas: [{ id_etiqueta: 7, nome: 'Importante' }], + } + api.get.mockResolvedValue({ data: document }) + + await expect(fetchDocumentById(42)).resolves.toEqual(document) + expect(api.get).toHaveBeenCalledWith('/api/documentos/42/') + }) +}) diff --git a/src/tests/coverage/DocumentoList.test.jsx b/src/tests/coverage/DocumentoList.test.jsx index ed82aa7..e6afe28 100644 --- a/src/tests/coverage/DocumentoList.test.jsx +++ b/src/tests/coverage/DocumentoList.test.jsx @@ -1,13 +1,12 @@ -import { render, screen } from "@testing-library/react"; -import userEvent from "@testing-library/user-event"; +import { fireEvent, render, screen } from "@testing-library/react"; import { describe, expect, it, vi } from "vitest"; -import DocumentList from "./DocumentList"; +import DocumentList from "../../components/Document/DocumentList/DocumentList"; -vi.mock("./DocumentItem", () => ({ +vi.mock("../../components/Document/DocumentItem/DocumentItem", () => ({ default: ({ document, onView }) => (
- {document.name} + {document.nome}
), @@ -26,8 +25,8 @@ describe("DocumentList", () => { it("renderiza os documentos recebidos", () => { const documents = [ - { id: 1, name: "Documento 1" }, - { id: 2, name: "Documento 2" }, + { id: 1, nome: "Documento 1" }, + { id: 2, nome: "Documento 2" }, ]; render(); @@ -47,12 +46,12 @@ describe("DocumentList", () => { it("chama onView ao visualizar um documento", async () => { const onView = vi.fn(); - const document = { id: 1, name: "Documento 1" }; + const document = { id: 1, nome: "Documento 1" }; render(); - await userEvent.click(screen.getByRole("button", { name: "Visualizar" })); + fireEvent.click(screen.getByRole("button", { name: "Visualizar" })); expect(onView).toHaveBeenCalledWith(document); }); -}); \ No newline at end of file +}); diff --git a/src/tests/coverage/Home.test.jsx b/src/tests/coverage/Home.test.jsx index e123c46..8068fc1 100644 --- a/src/tests/coverage/Home.test.jsx +++ b/src/tests/coverage/Home.test.jsx @@ -1,14 +1,14 @@ import { act, fireEvent, render, screen } from "@testing-library/react"; import { beforeEach, describe, expect, it, vi } from "vitest"; -import Home from "./Home"; -import { fetchDocuments } from "../services/documentService"; +import Home from "../../pages/Home/Home"; +import { fetchDocuments } from "../../services/documentService"; -vi.mock("../services/documentService", () => ({ +vi.mock("../../services/documentService", () => ({ fetchDocuments: vi.fn(), })); -vi.mock("../components/SearchBar/SearchBar", () => ({ +vi.mock("../../components/SearchBar/SearchBar", () => ({ default: ({ value, onChange }) => ( ({ ), })); -vi.mock("../components/Document/DocumentList", () => ({ +vi.mock("../../components/Document/DocumentList/DocumentList", () => ({ default: ({ documents, onView }) => (
{documents.map((document) => ( @@ -30,7 +30,7 @@ vi.mock("../components/Document/DocumentList", () => ({ ), })); -vi.mock("../components/Pagination/Pagination", () => ({ +vi.mock("../../components/Pagination/Pagination", () => ({ default: ({ currentPage, totalPages, onPageChange }) => ( @@ -63,8 +63,6 @@ describe("Home", () => { render(); - expect(screen.getByText("Carregando documentos...")).toBeInTheDocument(); - await act(async () => { await vi.advanceTimersByTimeAsync(400); }); @@ -149,4 +147,4 @@ describe("Home", () => { windowOpen.mockRestore(); }); -}); \ No newline at end of file +}); diff --git a/src/tests/setup.js b/src/tests/setup.js new file mode 100644 index 0000000..e87ca3f --- /dev/null +++ b/src/tests/setup.js @@ -0,0 +1,7 @@ +import '@testing-library/jest-dom/vitest' +import { cleanup } from '@testing-library/react' +import { afterEach } from 'vitest' + +afterEach(() => { + cleanup() +}) diff --git a/vite.config.js b/vite.config.js index 9982072..84e47e7 100644 --- a/vite.config.js +++ b/vite.config.js @@ -1,7 +1,12 @@ import react from '@vitejs/plugin-react' -import { defineConfig } from 'vite' +import { defineConfig } from 'vitest/config' // https://vite.dev/config/ export default defineConfig({ plugins: [react()], + test: { + environment: 'jsdom', + include: ['src/**/*.test.{js,jsx}'], + setupFiles: './src/tests/setup.js', + }, }) From 727d9ae29220676c319fcd79d77a41af55c38b5d Mon Sep 17 00:00:00 2001 From: Daniel Sendreti Date: Sun, 20 Sep 2026 20:32:19 -0300 Subject: [PATCH 38/52] feat(26): load document details in modal --- .../Document/DocumentItem/DocumentItem.jsx | 6 +- .../Document/DocumentList/DocumentList.jsx | 4 +- .../Document/DocumentModal/DocumentModal.jsx | 30 +++++- src/pages/Home/Home.jsx | 58 +++++++++- src/tests/coverage/DocumentoList.test.jsx | 6 +- src/tests/coverage/Home.test.jsx | 102 +++++++++++++++--- 6 files changed, 174 insertions(+), 32 deletions(-) diff --git a/src/components/Document/DocumentItem/DocumentItem.jsx b/src/components/Document/DocumentItem/DocumentItem.jsx index 158a114..5fc384f 100644 --- a/src/components/Document/DocumentItem/DocumentItem.jsx +++ b/src/components/Document/DocumentItem/DocumentItem.jsx @@ -15,11 +15,11 @@ function formatarData(dataISO) { } function DocumentItem({ document, onView }) { - const typeClass = document.type + const typeClass = document.setor ?.toLowerCase() .replace(/\s+/g, "-"); - const accessClass = document.accessLevel + const accessClass = document.nivel ?.toLowerCase() .replace(/\s+/g, "-"); @@ -59,4 +59,4 @@ function DocumentItem({ document, onView }) { ); } -export default DocumentItem; \ No newline at end of file +export default DocumentItem; diff --git a/src/components/Document/DocumentList/DocumentList.jsx b/src/components/Document/DocumentList/DocumentList.jsx index 4d74e42..afa4e73 100644 --- a/src/components/Document/DocumentList/DocumentList.jsx +++ b/src/components/Document/DocumentList/DocumentList.jsx @@ -20,7 +20,7 @@ function DocumentList({ documents, onView }) { {documents.length > 0 ? ( documents.map((document) => ( @@ -35,4 +35,4 @@ function DocumentList({ documents, onView }) { ); } -export default DocumentList; \ No newline at end of file +export default DocumentList; diff --git a/src/components/Document/DocumentModal/DocumentModal.jsx b/src/components/Document/DocumentModal/DocumentModal.jsx index 0aa6771..e1888ce 100644 --- a/src/components/Document/DocumentModal/DocumentModal.jsx +++ b/src/components/Document/DocumentModal/DocumentModal.jsx @@ -1,7 +1,33 @@ import { FiEye } from "react-icons/fi"; import "./DocumentModal.css"; -function DocumentModal({ document, onClose, onViewPdf }) { +function DocumentModal({ document, onClose, onViewPdf, loading, error, onRetry }) { + if (loading || error) { + return ( +
+
event.stopPropagation()} + > + + + {loading ? ( +

Carregando detalhes do documento...

+ ) : ( +
+

{error}

+ +
+ )} +
+
+ ); + } + if (!document) { return null; } @@ -174,4 +200,4 @@ function DocumentModal({ document, onClose, onViewPdf }) { ); } -export default DocumentModal; \ No newline at end of file +export default DocumentModal; diff --git a/src/pages/Home/Home.jsx b/src/pages/Home/Home.jsx index c9ad150..ae1c42b 100644 --- a/src/pages/Home/Home.jsx +++ b/src/pages/Home/Home.jsx @@ -1,12 +1,12 @@ import { FiFileText, FiFilter, FiAlertCircle } from "react-icons/fi"; -import { useEffect, useState } from "react"; +import { useEffect, useRef, useState } from "react"; import SearchBar from "../../components/SearchBar/SearchBar"; import DocumentList from "../../components/Document/DocumentList/DocumentList"; import Pagination from "../../components/Pagination/Pagination"; import DocumentModal from "../../components/Document/DocumentModal/DocumentModal"; -import { fetchDocuments } from "../../services/documentService"; +import { fetchDocumentById, fetchDocuments } from "../../services/documentService"; import "./Home.css"; @@ -18,6 +18,9 @@ function Home() { const [loading, setLoading] = useState(false); const [error, setError] = useState(null); const [selectedDocument, setSelectedDocument] = useState(null); + const [documentDetailsLoading, setDocumentDetailsLoading] = useState(false); + const [documentDetailsError, setDocumentDetailsError] = useState(null); + const detailRequestId = useRef(0); useEffect(() => { const timer = setTimeout(async () => { @@ -64,6 +67,48 @@ function Home() { console.log("PDF ainda não disponível:", document.nome); } + async function loadDocumentDetails(idDocumento) { + const requestId = ++detailRequestId.current; + + setDocumentDetailsLoading(true); + setDocumentDetailsError(null); + + try { + const document = await fetchDocumentById(idDocumento); + + if (requestId === detailRequestId.current) { + setSelectedDocument(document); + } + } catch (err) { + if (requestId === detailRequestId.current) { + console.error("Erro ao buscar detalhes do documento:", err); + setDocumentDetailsError("Não foi possível carregar os detalhes do documento."); + } + } finally { + if (requestId === detailRequestId.current) { + setDocumentDetailsLoading(false); + } + } + } + + function handleOpenDocument(document) { + setSelectedDocument(document); + loadDocumentDetails(document.id_documento); + } + + function handleCloseDocumentModal() { + detailRequestId.current += 1; + setSelectedDocument(null); + setDocumentDetailsLoading(false); + setDocumentDetailsError(null); + } + + function handleRetryDocumentDetails() { + if (selectedDocument?.id_documento) { + loadDocumentDetails(selectedDocument.id_documento); + } + } + return (
@@ -100,7 +145,7 @@ function Home() { <> setSelectedDocument(null)} + loading={documentDetailsLoading} + error={documentDetailsError} + onClose={handleCloseDocumentModal} + onRetry={handleRetryDocumentDetails} onViewPdf={handleViewPdf} />
); } -export default Home; \ No newline at end of file +export default Home; diff --git a/src/tests/coverage/DocumentoList.test.jsx b/src/tests/coverage/DocumentoList.test.jsx index e6afe28..3c7bc94 100644 --- a/src/tests/coverage/DocumentoList.test.jsx +++ b/src/tests/coverage/DocumentoList.test.jsx @@ -25,8 +25,8 @@ describe("DocumentList", () => { it("renderiza os documentos recebidos", () => { const documents = [ - { id: 1, nome: "Documento 1" }, - { id: 2, nome: "Documento 2" }, + { id_documento: 1, nome: "Documento 1" }, + { id_documento: 2, nome: "Documento 2" }, ]; render(); @@ -46,7 +46,7 @@ describe("DocumentList", () => { it("chama onView ao visualizar um documento", async () => { const onView = vi.fn(); - const document = { id: 1, nome: "Documento 1" }; + const document = { id_documento: 1, nome: "Documento 1" }; render(); diff --git a/src/tests/coverage/Home.test.jsx b/src/tests/coverage/Home.test.jsx index 8068fc1..8b92314 100644 --- a/src/tests/coverage/Home.test.jsx +++ b/src/tests/coverage/Home.test.jsx @@ -2,9 +2,13 @@ import { act, fireEvent, render, screen } from "@testing-library/react"; import { beforeEach, describe, expect, it, vi } from "vitest"; import Home from "../../pages/Home/Home"; -import { fetchDocuments } from "../../services/documentService"; +import { + fetchDocumentById, + fetchDocuments, +} from "../../services/documentService"; vi.mock("../../services/documentService", () => ({ + fetchDocumentById: vi.fn(), fetchDocuments: vi.fn(), })); @@ -22,7 +26,7 @@ vi.mock("../../components/Document/DocumentList/DocumentList", () => ({ default: ({ documents, onView }) => (
{documents.map((document) => ( - ))} @@ -43,9 +47,16 @@ vi.mock("../../components/Pagination/Pagination", () => ({ })); vi.mock("../../components/Document/DocumentModal/DocumentModal", () => ({ - default: ({ document, onViewPdf }) => - document ? ( - + default: ({ document, error, loading, onClose, onRetry }) => + document || error || loading ? ( +
+ {loading && Carregando detalhes} + {error && } + {document && !loading && !error && ( + Detalhe: {document.nome} + )} + +
) : null, })); @@ -115,21 +126,48 @@ describe("Home", () => { }); }); - it("abre o PDF do documento selecionado", async () => { - const windowOpen = vi - .spyOn(window, "open") - .mockImplementation(() => null); - + it("busca e exibe os detalhes do documento selecionado", async () => { fetchDocuments.mockResolvedValue({ results: [ { - id: 1, + id_documento: 1, nome: "Documento 1", - pdfUrl: "https://exemplo.com/documento.pdf", }, ], pages: 1, }); + let resolveDocumentDetails; + fetchDocumentById.mockReturnValue( + new Promise((resolve) => { + resolveDocumentDetails = resolve; + }) + ); + + render(); + + await act(async () => { + await vi.advanceTimersByTimeAsync(400); + }); + + fireEvent.click(screen.getByText("Documento 1")); + expect(fetchDocumentById).toHaveBeenCalledWith(1); + expect(screen.getByText("Carregando detalhes")).toBeInTheDocument(); + + await act(async () => { + resolveDocumentDetails({ id_documento: 1, nome: "Documento completo" }); + }); + + expect(screen.getByText("Detalhe: Documento completo")).toBeInTheDocument(); + }); + + it("permite tentar novamente ao falhar ao buscar os detalhes", async () => { + fetchDocuments.mockResolvedValue({ + results: [{ id_documento: 1, nome: "Documento 1" }], + pages: 1, + }); + fetchDocumentById + .mockRejectedValueOnce(new Error("Erro na API")) + .mockResolvedValueOnce({ id_documento: 1, nome: "Documento completo" }); render(); @@ -138,13 +176,43 @@ describe("Home", () => { }); fireEvent.click(screen.getByText("Documento 1")); - fireEvent.click(screen.getByText("Abrir PDF")); - expect(windowOpen).toHaveBeenCalledWith( - "https://exemplo.com/documento.pdf", - "_blank" + await act(async () => {}); + + expect(screen.getByText("Tentar novamente")).toBeInTheDocument(); + fireEvent.click(screen.getByText("Tentar novamente")); + + await act(async () => {}); + + expect(fetchDocumentById).toHaveBeenCalledTimes(2); + expect(screen.getByText("Detalhe: Documento completo")).toBeInTheDocument(); + }); + + it("ignora a resposta de detalhes depois que o modal é fechado", async () => { + fetchDocuments.mockResolvedValue({ + results: [{ id_documento: 1, nome: "Documento 1" }], + pages: 1, + }); + let resolveDocumentDetails; + fetchDocumentById.mockReturnValue( + new Promise((resolve) => { + resolveDocumentDetails = resolve; + }) ); - windowOpen.mockRestore(); + render(); + + await act(async () => { + await vi.advanceTimersByTimeAsync(400); + }); + + fireEvent.click(screen.getByText("Documento 1")); + fireEvent.click(screen.getByText("Fechar modal")); + + await act(async () => { + resolveDocumentDetails({ id_documento: 1, nome: "Documento completo" }); + }); + + expect(screen.queryByText("Detalhe: Documento completo")).not.toBeInTheDocument(); }); }); From 9f9ff805ed5257982cc27dbf345fb0b9936ae366 Mon Sep 17 00:00:00 2001 From: Daniel Sendreti Date: Sun, 20 Sep 2026 20:45:03 -0300 Subject: [PATCH 39/52] feat(26): display document details and tags in modal --- .../Document/DocumentModal/DocumentModal.css | 12 +- .../Document/DocumentModal/DocumentModal.jsx | 165 +++++------------- .../DocumentModal/DocumentModal.test.jsx | 76 ++++++++ src/pages/Home/Home.jsx | 4 +- src/tests/coverage/Home.test.jsx | 21 ++- 5 files changed, 151 insertions(+), 127 deletions(-) create mode 100644 src/components/Document/DocumentModal/DocumentModal.test.jsx diff --git a/src/components/Document/DocumentModal/DocumentModal.css b/src/components/Document/DocumentModal/DocumentModal.css index 29d595c..05df264 100644 --- a/src/components/Document/DocumentModal/DocumentModal.css +++ b/src/components/Document/DocumentModal/DocumentModal.css @@ -370,6 +370,11 @@ font-size: 12px; } +.tags-empty { + color: #806d75; + font-size: 12px; +} + /*AÇÕES*/ .modal-actions { @@ -435,4 +440,9 @@ .modal-main-info { align-items: stretch; } -} \ No newline at end of file +} + +.modal-view-button:disabled { + cursor: not-allowed; + opacity: 0.6; +} diff --git a/src/components/Document/DocumentModal/DocumentModal.jsx b/src/components/Document/DocumentModal/DocumentModal.jsx index e1888ce..88998c0 100644 --- a/src/components/Document/DocumentModal/DocumentModal.jsx +++ b/src/components/Document/DocumentModal/DocumentModal.jsx @@ -1,16 +1,26 @@ import { FiEye } from "react-icons/fi"; import "./DocumentModal.css"; +function formatDate(value) { + if (!value) return "-"; + + const date = new Date(value); + if (Number.isNaN(date.getTime())) return value; + + return date.toLocaleDateString("pt-BR", { + day: "2-digit", + month: "2-digit", + year: "numeric", + }); +} + function DocumentModal({ document, onClose, onViewPdf, loading, error, onRetry }) { if (loading || error) { return (
-
event.stopPropagation()} - > +
event.stopPropagation()}> {loading ? ( @@ -28,160 +38,72 @@ function DocumentModal({ document, onClose, onViewPdf, loading, error, onRetry } ); } - if (!document) { - return null; - } + if (!document) return null; - const tags = [ - "Materiais metálicos", - "Manutenção", - "MIL-HDBK", - "Engenharia", - "Handbook", - ]; + const tags = document.etiquetas || []; return ( -
-
event.stopPropagation()} - > +
+
event.stopPropagation()}>
- - Código da norma - + Arquivo
- {document.code || document.name} - + {document.nome} - PDF + {document.tipo_arquivo?.toUpperCase() || "ARQUIVO"}
-
-
- - Título do arquivo - - -

- {document.name} -

-
-
- - Setor/Tipo - - - - {document.type} - -
- -
- - Nível de Acesso - - - - {document.accessLevel} - + Setor + {document.setor}
- - Categoria - - - - {document.category || document.type} - + Nivel de acesso + {document.nivel}
- - Dados do arquivo - + Dados do arquivo
- ↻ Revisão: - - - {document.revision || "5J"} - + Tipo: + {document.tipo_arquivo || "-"}
- ◷ Data de Atualização: - - - {document.updatedAt} - -
- -
- ▤ Tamanho do arquivo: - - - {document.fileSize || "66.8 MB"} - + Data de atualizacao: + {formatDate(document.data_atualizacao)}
- - 🏷 Tags - + Tags
- {tags.map((tag) => ( - - {tag} - - ))} + {tags.length > 0 ? ( + tags.map((tag) => ( + + {tag.nome} + + )) + ) : ( + Nenhuma etiqueta atribuida. + )}
@@ -189,6 +111,7 @@ function DocumentModal({ document, onClose, onViewPdf, loading, error, onRetry }
} {document && !loading && !error && ( - Detalhe: {document.nome} + <> + Detalhe: {document.nome} + + )}
@@ -127,6 +130,7 @@ describe("Home", () => { }); it("busca e exibe os detalhes do documento selecionado", async () => { + const windowOpen = vi.spyOn(window, "open").mockImplementation(() => null); fetchDocuments.mockResolvedValue({ results: [ { @@ -154,10 +158,21 @@ describe("Home", () => { expect(screen.getByText("Carregando detalhes")).toBeInTheDocument(); await act(async () => { - resolveDocumentDetails({ id_documento: 1, nome: "Documento completo" }); + resolveDocumentDetails({ + id_documento: 1, + nome: "Documento completo", + data: "http://localhost:8000/media/documentos/manual.pdf", + }); }); expect(screen.getByText("Detalhe: Documento completo")).toBeInTheDocument(); + fireEvent.click(screen.getByText("Abrir PDF")); + expect(windowOpen).toHaveBeenCalledWith( + "http://localhost:8000/media/documentos/manual.pdf", + "_blank" + ); + + windowOpen.mockRestore(); }); it("permite tentar novamente ao falhar ao buscar os detalhes", async () => { From ab2ab3ca0c96a72487af3e5492fbd23f7351c8a1 Mon Sep 17 00:00:00 2001 From: CainaNascimentoMelo Date: Tue, 22 Sep 2026 20:09:22 -0300 Subject: [PATCH 40/52] feat(A6-32): Add tags search --- src/services/documentService.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/services/documentService.js b/src/services/documentService.js index 469ecf6..717d61b 100644 --- a/src/services/documentService.js +++ b/src/services/documentService.js @@ -3,7 +3,8 @@ import api from "./api"; export async function fetchDocuments({ nome = "", page = 1 } = {}) { const response = await api.get("/api/documentos/", { params: { - nome: nome, + nome: nome, + etiquetas: nome, page: page, }, }); From f7d25d724e543e88a1e01418e31ef577a9611c77 Mon Sep 17 00:00:00 2001 From: CainaNascimentoMelo Date: Tue, 22 Sep 2026 20:20:14 -0300 Subject: [PATCH 41/52] remove(A6-32): Remove Akaer logo sidebar --- src/components/Sidebar/Sidebar.css | 30 ++---------------------------- src/components/Sidebar/Sidebar.jsx | 7 ------- 2 files changed, 2 insertions(+), 35 deletions(-) diff --git a/src/components/Sidebar/Sidebar.css b/src/components/Sidebar/Sidebar.css index 42fbeb0..db2083b 100644 --- a/src/components/Sidebar/Sidebar.css +++ b/src/components/Sidebar/Sidebar.css @@ -8,6 +8,8 @@ display: flex; flex-direction: column; + padding-top: 30px; + border-right: 1px solid #ead5dc; background: linear-gradient( @@ -17,30 +19,6 @@ ); } -.sidebar-logo { - height: 200px; - - display: flex; - align-items: center; - justify-content: center; -} - -.sidebar-logo-mark { - width: 128px; - height: 128px; - - display: flex; - align-items: center; - justify-content: center; -} - -.sidebar-logo-mark img { - max-width: 100%; - max-height: 100%; - - object-fit: contain; -} - .sidebar-menu { display: flex; flex-direction: column; @@ -112,10 +90,6 @@ padding: 0 12px; } - .sidebar-logo { - height: 160px; - } - .logout-button { left: 12px; } diff --git a/src/components/Sidebar/Sidebar.jsx b/src/components/Sidebar/Sidebar.jsx index 5dd652c..e3770a3 100644 --- a/src/components/Sidebar/Sidebar.jsx +++ b/src/components/Sidebar/Sidebar.jsx @@ -1,16 +1,9 @@ import { FiFileText, FiLogOut } from "react-icons/fi"; -import logo from "../../assets/AkaerLogo.png"; import "./Sidebar.css"; function Sidebar() { return (
From 25ae11fc9c66000551cab1d28fb013a054179418 Mon Sep 17 00:00:00 2001 From: d-broder Date: Wed, 23 Sep 2026 13:08:09 -0300 Subject: [PATCH 45/52] build(26): reverts "build(26): configure vitest coverage and fix sonarcloud quality gate" --- .github/workflows/ci-frontend.yml | 18 +----- .gitignore | 2 - package-lock.json | 104 ------------------------------ package.json | 4 +- sonar-project.properties | 5 -- vite.config.js | 11 +--- 6 files changed, 3 insertions(+), 141 deletions(-) diff --git a/.github/workflows/ci-frontend.yml b/.github/workflows/ci-frontend.yml index fb85135..7d48809 100644 --- a/.github/workflows/ci-frontend.yml +++ b/.github/workflows/ci-frontend.yml @@ -46,16 +46,6 @@ jobs: - name: Gerar build de produção run: npm run build - - name: Executar testes e gerar coverage - run: npm run test:coverage - - - name: Fazer upload do relatório de cobertura - uses: actions/upload-artifact@v4 - with: - name: coverage-report - path: coverage/ - retention-days: 1 - secondary-build: name: "Estágio 2: análise no SonarCloud" runs-on: ubuntu-latest @@ -71,12 +61,6 @@ jobs: with: fetch-depth: 0 - - name: Fazer download do relatório de cobertura - uses: actions/download-artifact@v4 - with: - name: coverage-report - path: coverage/ - - name: Executar análise no SonarCloud if: env.SONAR_TOKEN != '' uses: SonarSource/sonarqube-scan-action@7006c4492b2e0ee0f816d36501671557c97f5995 # v8.1.0 @@ -86,4 +70,4 @@ jobs: - name: Informar ausência do token do SonarCloud if: env.SONAR_TOKEN == '' - run: echo "::notice::SonarCloud não executado porque o secret SONAR_TOKEN não está disponível." \ No newline at end of file + run: echo "::notice::SonarCloud não executado porque o secret SONAR_TOKEN não está disponível." diff --git a/.gitignore b/.gitignore index 3252172..a547bf3 100644 --- a/.gitignore +++ b/.gitignore @@ -22,5 +22,3 @@ dist-ssr *.njsproj *.sln *.sw? - -coverage/ \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 1289a57..383577d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,7 +20,6 @@ "@types/react": "^19.2.18", "@types/react-dom": "^19.2.4", "@vitejs/plugin-react": "^6.1.0", - "@vitest/coverage-v8": "^5.0.1", "eslint": "^10.9.0", "eslint-plugin-react-hooks": "^7.1.1", "eslint-plugin-react-refresh": "^0.5.4", @@ -340,16 +339,6 @@ "node": ">=6.9.0" } }, - "node_modules/@bcoe/v8-coverage": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-1.0.2.tgz", - "integrity": "sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, "node_modules/@bramus/specificity": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/@bramus/specificity/-/specificity-2.4.2.tgz", @@ -1267,58 +1256,6 @@ } } }, - "node_modules/@vitest/coverage-v8": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-5.0.1.tgz", - "integrity": "sha512-FRC8ACiudC3dI6MTplzRSYWHDRnIv2IPfbzs4FdoJNsMal/35sWV8hwIfV8ZcqzSPy+uXHeMVONt9CEqtOU17w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@bcoe/v8-coverage": "^1.0.2", - "@vitest/istanbul-lib-coverage": "^1.0.0", - "@vitest/istanbul-lib-report": "^1.0.0", - "ast-v8-to-istanbul": "^1.0.5", - "magicast": "^0.5.4", - "obug": "^2.1.4", - "std-env": "^4.2.0", - "tinyrainbow": "^3.1.1" - }, - "funding": { - "url": "https://opencollective.com/vitest" - }, - "peerDependencies": { - "@vitest/browser": "5.0.1", - "vitest": "5.0.1" - }, - "peerDependenciesMeta": { - "@vitest/browser": { - "optional": true - } - } - }, - "node_modules/@vitest/istanbul-lib-coverage": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@vitest/istanbul-lib-coverage/-/istanbul-lib-coverage-1.0.1.tgz", - "integrity": "sha512-k3DJZ8LhMBK9NS4SclF1ASD3OgXEWDorbIcPTRDK0/Zae6fRvu+fJRxtFdLfHsa9Y24beCdPnoNZ4LviTNstfA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=22" - } - }, - "node_modules/@vitest/istanbul-lib-report": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@vitest/istanbul-lib-report/-/istanbul-lib-report-1.0.1.tgz", - "integrity": "sha512-1EOLRfsTMnyAr3+kEAsP4o9dhaDlGPpD7H5iLBBeq//YpNB1VIahkPhB+eRp9N2Dkfw8oySROjE3yf9XDeaIkQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/istanbul-lib-coverage": "1.0.1" - }, - "engines": { - "node": ">=22" - } - }, "node_modules/@vitest/mocker": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-5.0.1.tgz", @@ -1454,25 +1391,6 @@ "node": ">=12" } }, - "node_modules/ast-v8-to-istanbul": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-1.0.7.tgz", - "integrity": "sha512-kFL68AG6ajd8fg248zwM9GQrUWEp79gsmjum34OEXjs4yHuUMZfYKwOLW9GMmB4oNvVrj+EAGxsP7ye2UR9UlA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.31", - "estree-walker": "^3.0.3", - "js-tokens": "^10.0.0" - } - }, - "node_modules/ast-v8-to-istanbul/node_modules/js-tokens": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-10.0.0.tgz", - "integrity": "sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==", - "dev": true, - "license": "MIT" - }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -2930,18 +2848,6 @@ "@jridgewell/sourcemap-codec": "^1.6.0" } }, - "node_modules/magicast": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.5.5.tgz", - "integrity": "sha512-UicdXN8zQ3JHlxVq+28afMXPr1z7WNY6+7EJnzTdQWkTAlMLF5fNCCKxJHBQwGaNGR11581EiQmQzx73+MvszA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.29.7", - "@babel/types": "^7.29.7", - "source-map-js": "^1.2.1" - } - }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", @@ -3487,16 +3393,6 @@ "url": "https://github.com/sponsors/SuperchupuDev" } }, - "node_modules/tinyrainbow": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.1.tgz", - "integrity": "sha512-yau8yJdTt989Mm0Bd/236QnzEiPf2xLLTqUZRUJOo/3CB078LSwzei343DgtJVmfJKJE3TMINY1u42SQsP6mXw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14.0.0" - } - }, "node_modules/tldts": { "version": "7.4.13", "resolved": "https://registry.npmjs.org/tldts/-/tldts-7.4.13.tgz", diff --git a/package.json b/package.json index 7142330..c9dca8d 100644 --- a/package.json +++ b/package.json @@ -9,8 +9,7 @@ "lint": "eslint .", "preview": "vite preview", "test": "vitest run", - "test:watch": "vitest", - "test:coverage": "vitest run --coverage" + "test:watch": "vitest" }, "dependencies": { "axios": "^1.20.0", @@ -25,7 +24,6 @@ "@types/react": "^19.2.18", "@types/react-dom": "^19.2.4", "@vitejs/plugin-react": "^6.1.0", - "@vitest/coverage-v8": "^5.0.1", "eslint": "^10.9.0", "eslint-plugin-react-hooks": "^7.1.1", "eslint-plugin-react-refresh": "^0.5.4", diff --git a/sonar-project.properties b/sonar-project.properties index da5b19d..07db20a 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -12,8 +12,3 @@ sonar.sources=src # Encoding of the source code. Default is default system encoding sonar.sourceEncoding=UTF-8 - -sonar.javascript.lcov.reportPaths=coverage/lcov.info -sonar.exclusions=**/*.test.jsx, **/*.test.js, src/tests/**/*, src/tests/setup.js, vite.config.js -sonar.tests=src -sonar.test.inclusions=**/*.test.jsx, **/*.test.js \ No newline at end of file diff --git a/vite.config.js b/vite.config.js index 7986c80..84e47e7 100644 --- a/vite.config.js +++ b/vite.config.js @@ -1,21 +1,12 @@ import react from '@vitejs/plugin-react' import { defineConfig } from 'vitest/config' +// https://vite.dev/config/ export default defineConfig({ plugins: [react()], test: { environment: 'jsdom', include: ['src/**/*.test.{js,jsx}'], setupFiles: './src/tests/setup.js', - coverage: { - provider: 'v8', - reporter: ['text', 'lcov'], - include: ['src/**/*.{js,jsx}'], - exclude: [ - 'src/**/*.test.{js,jsx}', - 'src/tests/**/*', - 'src/tests/setup.js' - ], - }, }, }) From 3fd7f9b1e60d6a85a0fe9d266fc4d48406e81f49 Mon Sep 17 00:00:00 2001 From: d-broder Date: Wed, 23 Sep 2026 15:03:28 -0300 Subject: [PATCH 46/52] fix(26): add aria-hidden attribute to icons in DocumentModal --- src/components/Document/DocumentModal/DocumentModal.jsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/Document/DocumentModal/DocumentModal.jsx b/src/components/Document/DocumentModal/DocumentModal.jsx index e986168..8a04de2 100644 --- a/src/components/Document/DocumentModal/DocumentModal.jsx +++ b/src/components/Document/DocumentModal/DocumentModal.jsx @@ -20,7 +20,7 @@ function DocumentModal({ document, onClose, onViewPdf, loading, error, onRetry }
event.stopPropagation()}> {loading ? ( @@ -58,7 +58,7 @@ function DocumentModal({ document, onClose, onViewPdf, loading, error, onRetry }
@@ -114,7 +114,7 @@ function DocumentModal({ document, onClose, onViewPdf, loading, error, onRetry } disabled={!document.data} onClick={() => onViewPdf(document)} > - +