From 08732deb1775ac681ad3e81277aca3d03cacd4df Mon Sep 17 00:00:00 2001 From: Filipe Frigini Date: Sat, 21 Mar 2026 14:06:26 -0300 Subject: [PATCH 01/19] feat(Admin): Scaffold Admin Portal React project with Next.js - Create MeAjudaAi.Web.Admin-React with NX - Add Tailwind CSS v4 configuration - Add basic Next.js App Router structure --- src/Web/MeAjudaAi.Web.Admin-React/.swcrc | 30 ++ src/Web/MeAjudaAi.Web.Admin-React/index.d.ts | 6 + .../MeAjudaAi.Web.Admin-React/next-env.d.ts | 5 + .../MeAjudaAi.Web.Admin-React/next.config.js | 20 + .../postcss.config.js | 15 + .../MeAjudaAi.Web.Admin-React/project.json | 9 + .../MeAjudaAi.Web.Admin-React/public/.gitkeep | 0 .../public/favicon.ico | Bin 0 -> 15086 bytes .../src/app/api/hello/route.ts | 3 + .../src/app/global.css | 505 ++++++++++++++++++ .../src/app/layout.tsx | 18 + .../src/app/page.tsx | 467 ++++++++++++++++ .../tailwind.config.js | 23 + .../MeAjudaAi.Web.Admin-React/tsconfig.json | 39 ++ src/Web/package.json | 3 + 15 files changed, 1143 insertions(+) create mode 100644 src/Web/MeAjudaAi.Web.Admin-React/.swcrc create mode 100644 src/Web/MeAjudaAi.Web.Admin-React/index.d.ts create mode 100644 src/Web/MeAjudaAi.Web.Admin-React/next-env.d.ts create mode 100644 src/Web/MeAjudaAi.Web.Admin-React/next.config.js create mode 100644 src/Web/MeAjudaAi.Web.Admin-React/postcss.config.js create mode 100644 src/Web/MeAjudaAi.Web.Admin-React/project.json create mode 100644 src/Web/MeAjudaAi.Web.Admin-React/public/.gitkeep create mode 100644 src/Web/MeAjudaAi.Web.Admin-React/public/favicon.ico create mode 100644 src/Web/MeAjudaAi.Web.Admin-React/src/app/api/hello/route.ts create mode 100644 src/Web/MeAjudaAi.Web.Admin-React/src/app/global.css create mode 100644 src/Web/MeAjudaAi.Web.Admin-React/src/app/layout.tsx create mode 100644 src/Web/MeAjudaAi.Web.Admin-React/src/app/page.tsx create mode 100644 src/Web/MeAjudaAi.Web.Admin-React/tailwind.config.js create mode 100644 src/Web/MeAjudaAi.Web.Admin-React/tsconfig.json diff --git a/src/Web/MeAjudaAi.Web.Admin-React/.swcrc b/src/Web/MeAjudaAi.Web.Admin-React/.swcrc new file mode 100644 index 000000000..e912f1855 --- /dev/null +++ b/src/Web/MeAjudaAi.Web.Admin-React/.swcrc @@ -0,0 +1,30 @@ +{ + "jsc": { + "target": "es2017", + "parser": { + "syntax": "typescript", + "decorators": true, + "dynamicImport": true + }, + "transform": { + "decoratorMetadata": true, + "legacyDecorator": true + }, + "keepClassNames": true, + "externalHelpers": true, + "loose": true + }, + "module": { + "type": "commonjs" + }, + "sourceMaps": true, + "exclude": [ + "jest.config.[ct]s", + ".*\\.spec.tsx?$", + ".*\\.test.tsx?$", + "./src/jest-setup.ts$", + "./**/jest-setup.ts$", + ".*.js$", + ".*.d.ts$" + ] +} diff --git a/src/Web/MeAjudaAi.Web.Admin-React/index.d.ts b/src/Web/MeAjudaAi.Web.Admin-React/index.d.ts new file mode 100644 index 000000000..7ba08fa17 --- /dev/null +++ b/src/Web/MeAjudaAi.Web.Admin-React/index.d.ts @@ -0,0 +1,6 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +declare module '*.svg' { + const content: any; + export const ReactComponent: any; + export default content; +} diff --git a/src/Web/MeAjudaAi.Web.Admin-React/next-env.d.ts b/src/Web/MeAjudaAi.Web.Admin-React/next-env.d.ts new file mode 100644 index 000000000..1b3be0840 --- /dev/null +++ b/src/Web/MeAjudaAi.Web.Admin-React/next-env.d.ts @@ -0,0 +1,5 @@ +/// +/// + +// NOTE: This file should not be edited +// see https://nextjs.org/docs/app/api-reference/config/typescript for more information. diff --git a/src/Web/MeAjudaAi.Web.Admin-React/next.config.js b/src/Web/MeAjudaAi.Web.Admin-React/next.config.js new file mode 100644 index 000000000..6a591025e --- /dev/null +++ b/src/Web/MeAjudaAi.Web.Admin-React/next.config.js @@ -0,0 +1,20 @@ +//@ts-check + +// eslint-disable-next-line @typescript-eslint/no-var-requires +const { composePlugins, withNx } = require('@nx/next'); + +/** + * @type {import('@nx/next/plugins/with-nx').WithNxOptions} + **/ +const nextConfig = { + // Use this to set Nx-specific options + // See: https://nx.dev/recipes/next/next-config-setup + nx: {}, +}; + +const plugins = [ + // Add more Next.js plugins to this list if needed. + withNx, +]; + +module.exports = composePlugins(...plugins)(nextConfig); diff --git a/src/Web/MeAjudaAi.Web.Admin-React/postcss.config.js b/src/Web/MeAjudaAi.Web.Admin-React/postcss.config.js new file mode 100644 index 000000000..c72626d6c --- /dev/null +++ b/src/Web/MeAjudaAi.Web.Admin-React/postcss.config.js @@ -0,0 +1,15 @@ +const { join } = require('path'); + +// Note: If you use library-specific PostCSS/Tailwind configuration then you should remove the `postcssConfig` build +// option from your application's configuration (i.e. project.json). +// +// See: https://nx.dev/guides/using-tailwind-css-in-react#step-4:-applying-configuration-to-libraries + +module.exports = { + plugins: { + tailwindcss: { + config: join(__dirname, 'tailwind.config.js'), + }, + autoprefixer: {}, + }, +}; diff --git a/src/Web/MeAjudaAi.Web.Admin-React/project.json b/src/Web/MeAjudaAi.Web.Admin-React/project.json new file mode 100644 index 000000000..59807d030 --- /dev/null +++ b/src/Web/MeAjudaAi.Web.Admin-React/project.json @@ -0,0 +1,9 @@ +{ + "name": "MeAjudaAi.Web.Admin-React", + "$schema": "../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "MeAjudaAi.Web.Admin-React", + "projectType": "application", + "tags": [], + "// targets": "to see all targets run: nx show project MeAjudaAi.Web.Admin-React --web", + "targets": {} +} diff --git a/src/Web/MeAjudaAi.Web.Admin-React/public/.gitkeep b/src/Web/MeAjudaAi.Web.Admin-React/public/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/src/Web/MeAjudaAi.Web.Admin-React/public/favicon.ico b/src/Web/MeAjudaAi.Web.Admin-React/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..317ebcb2336e0833a22dddf0ab287849f26fda57 GIT binary patch literal 15086 zcmeI332;U^%p|z7g|#(P)qFEA@4f!_@qOK2 z_lJl}!lhL!VT_U|uN7%8B2iKH??xhDa;*`g{yjTFWHvXn;2s{4R7kH|pKGdy(7z!K zgftM+Ku7~24TLlh(!g)gz|foI94G^t2^IO$uvX$3(OR0<_5L2sB)lMAMy|+`xodJ{ z_Uh_1m)~h?a;2W{dmhM;u!YGo=)OdmId_B<%^V^{ovI@y`7^g1_V9G}*f# zNzAtvou}I!W1#{M^@ROc(BZ! z+F!!_aR&Px3_reO(EW+TwlW~tv*2zr?iP7(d~a~yA|@*a89IUke+c472NXM0wiX{- zl`UrZC^1XYyf%1u)-Y)jj9;MZ!SLfd2Hl?o|80Su%Z?To_=^g_Jt0oa#CT*tjx>BI z16wec&AOWNK<#i0Qd=1O$fymLRoUR*%;h@*@v7}wApDl^w*h}!sYq%kw+DKDY)@&A z@9$ULEB3qkR#85`lb8#WZw=@})#kQig9oqy^I$dj&k4jU&^2(M3q{n1AKeGUKPFbr z1^<)aH;VsG@J|B&l>UtU#Ejv3GIqERzYgL@UOAWtW<{p#zy`WyJgpCy8$c_e%wYJL zyGHRRx38)HyjU3y{-4z6)pzb>&Q1pR)B&u01F-|&Gx4EZWK$nkUkOI|(D4UHOXg_- zw{OBf!oWQUn)Pe(=f=nt=zkmdjpO^o8ZZ9o_|4tW1ni+Un9iCW47*-ut$KQOww!;u z`0q)$s6IZO!~9$e_P9X!hqLxu`fpcL|2f^I5d4*a@Dq28;@2271v_N+5HqYZ>x;&O z05*7JT)mUe&%S0@UD)@&8SmQrMtsDfZT;fkdA!r(S=}Oz>iP)w=W508=Rc#nNn7ym z1;42c|8($ALY8#a({%1#IXbWn9-Y|0eDY$_L&j{63?{?AH{);EzcqfydD$@-B`Y3<%IIj7S7rK_N}je^=dEk%JQ4c z!tBdTPE3Tse;oYF>cnrapWq*o)m47X1`~6@(!Y29#>-#8zm&LXrXa(3=7Z)ElaQqj z-#0JJy3Fi(C#Rx(`=VXtJ63E2_bZGCz+QRa{W0e2(m3sI?LOcUBx)~^YCqZ{XEPX)C>G>U4tfqeH8L(3|pQR*zbL1 zT9e~4Tb5p9_G}$y4t`i*4t_Mr9QYvL9C&Ah*}t`q*}S+VYh0M6GxTTSXI)hMpMpIq zD1ImYqJLzbj0}~EpE-aH#VCH_udYEW#`P2zYmi&xSPs_{n6tBj=MY|-XrA;SGA_>y zGtU$?HXm$gYj*!N)_nQ59%lQdXtQZS3*#PC-{iB_sm+ytD*7j`D*k(P&IH2GHT}Eh z5697eQECVIGQAUe#eU2I!yI&%0CP#>%6MWV z@zS!p@+Y1i1b^QuuEF*13CuB zu69dve5k7&Wgb+^s|UB08Dr3u`h@yM0NTj4h7MnHo-4@xmyr7(*4$rpPwsCDZ@2be zRz9V^GnV;;?^Lk%ynzq&K(Aix`mWmW`^152Hoy$CTYVehpD-S1-W^#k#{0^L`V6CN+E z!w+xte;2vu4AmVNEFUOBmrBL>6MK@!O2*N|2=d|Y;oN&A&qv=qKn73lDD zI(+oJAdgv>Yr}8(&@ZuAZE%XUXmX(U!N+Z_sjL<1vjy1R+1IeHt`79fnYdOL{$ci7 z%3f0A*;Zt@ED&Gjm|OFTYBDe%bbo*xXAQsFz+Q`fVBH!N2)kaxN8P$c>sp~QXnv>b zwq=W3&Mtmih7xkR$YA)1Yi?avHNR6C99!u6fh=cL|KQ&PwF!n@ud^n(HNIImHD!h87!i*t?G|p0o+eelJ?B@A64_9%SBhNaJ64EvKgD&%LjLCYnNfc; znj?%*p@*?dq#NqcQFmmX($wms@CSAr9#>hUR^=I+=0B)vvGX%T&#h$kmX*s=^M2E!@N9#m?LhMvz}YB+kd zG~mbP|D(;{s_#;hsKK9lbVK&Lo734x7SIFJ9V_}2$@q?zm^7?*XH94w5Qae{7zOMUF z^?%F%)c1Y)Q?Iy?I>knw*8gYW#ok|2gdS=YYZLiD=CW|Nj;n^x!=S#iJ#`~Ld79+xXpVmUK^B(xO_vO!btA9y7w3L3-0j-y4 z?M-V{%z;JI`bk7yFDcP}OcCd*{Q9S5$iGA7*E1@tfkyjAi!;wP^O71cZ^Ep)qrQ)N z#wqw0_HS;T7x3y|`P==i3hEwK%|>fZ)c&@kgKO1~5<5xBSk?iZV?KI6&i72H6S9A* z=U(*e)EqEs?Oc04)V-~K5AUmh|62H4*`UAtItO$O(q5?6jj+K^oD!04r=6#dsxp?~}{`?&sXn#q2 zGuY~7>O2=!u@@Kfu7q=W*4egu@qPMRM>(eyYyaIE<|j%d=iWNdGsx%c!902v#ngNg z@#U-O_4xN$s_9?(`{>{>7~-6FgWpBpqXb`Ydc3OFL#&I}Irse9F_8R@4zSS*Y*o*B zXL?6*Aw!AfkNCgcr#*yj&p3ZDe2y>v$>FUdKIy_2N~}6AbHc7gA3`6$g@1o|dE>vz z4pl(j9;kyMsjaw}lO?(?Xg%4k!5%^t#@5n=WVc&JRa+XT$~#@rldvN3S1rEpU$;XgxVny7mki3 z-Hh|jUCHrUXuLr!)`w>wgO0N%KTB-1di>cj(x3Bav`7v z3G7EIbU$z>`Nad7Rk_&OT-W{;qg)-GXV-aJT#(ozdmnA~Rq3GQ_3mby(>q6Ocb-RgTUhTN)))x>m&eD;$J5Bg zo&DhY36Yg=J=$Z>t}RJ>o|@hAcwWzN#r(WJ52^g$lh^!63@hh+dR$&_dEGu&^CR*< z!oFqSqO@>xZ*nC2oiOd0eS*F^IL~W-rsrO`J`ej{=ou_q^_(<$&-3f^J z&L^MSYWIe{&pYq&9eGaArA~*kA span { + flex-grow: 1; + font-weight: 400; + transition-property: + background-color, + border-color, + color, + fill, + stroke, + opacity, + box-shadow, + transform, + filter, + backdrop-filter, + -webkit-backdrop-filter; + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + transition-duration: 150ms; +} +.list-item-link > span > span { + color: rgba(107, 114, 128, 1); + display: block; + flex-grow: 1; + font-size: 0.75rem; + font-weight: 300; + line-height: 1rem; + transition-property: + background-color, + border-color, + color, + fill, + stroke, + opacity, + box-shadow, + transform, + filter, + backdrop-filter, + -webkit-backdrop-filter; + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + transition-duration: 150ms; +} +.list-item-link svg:last-child { + height: 1rem; + transition-property: all; + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + transition-duration: 150ms; + width: 1rem; +} +.list-item-link:hover { + color: rgba(255, 255, 255, 1); + background-color: hsla(162, 47%, 50%, 1); +} +.list-item-link:hover > span { +} +.list-item-link:hover > span > span { + color: rgba(243, 244, 246, 1); +} +.list-item-link:hover svg:last-child { + transform: translateX(0.25rem); +} +#other-links { +} +.button-pill { + padding: 1.5rem 2rem; + transition-duration: 300ms; + transition-property: + background-color, + border-color, + color, + fill, + stroke, + opacity, + box-shadow, + transform, + filter, + backdrop-filter, + -webkit-backdrop-filter; + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + align-items: center; + display: flex; +} +.button-pill svg { + transition-property: + background-color, + border-color, + color, + fill, + stroke, + opacity, + box-shadow, + transform, + filter, + backdrop-filter, + -webkit-backdrop-filter; + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + transition-duration: 150ms; + flex-shrink: 0; + width: 3rem; +} +.button-pill > span { + letter-spacing: -0.025em; + font-weight: 400; + font-size: 1.125rem; + line-height: 1.75rem; + padding-left: 1rem; + padding-right: 1rem; +} +.button-pill span span { + display: block; + font-size: 0.875rem; + font-weight: 300; + line-height: 1.25rem; +} +.button-pill:hover svg, +.button-pill:hover { + color: rgba(255, 255, 255, 1) !important; +} +#nx-console:hover { + background-color: rgba(0, 122, 204, 1); +} +#nx-console svg { + color: rgba(0, 122, 204, 1); +} +#nx-console-jetbrains { + margin-top: 2rem; +} +#nx-console-jetbrains:hover { + background-color: rgba(255, 49, 140, 1); +} +#nx-console-jetbrains svg { + color: rgba(255, 49, 140, 1); +} +#nx-repo:hover { + background-color: rgba(24, 23, 23, 1); +} +#nx-repo svg { + color: rgba(24, 23, 23, 1); +} +#nx-cloud { + margin-bottom: 2rem; + margin-top: 2rem; + padding: 2.5rem 2rem; +} +#nx-cloud > div { + align-items: center; + display: flex; +} +#nx-cloud > div svg { + border-radius: 0.375rem; + flex-shrink: 0; + width: 3rem; +} +#nx-cloud > div h2 { + font-size: 1.125rem; + font-weight: 400; + letter-spacing: -0.025em; + line-height: 1.75rem; + padding-left: 1rem; + padding-right: 1rem; +} +#nx-cloud > div h2 span { + display: block; + font-size: 0.875rem; + font-weight: 300; + line-height: 1.25rem; +} +#nx-cloud p { + font-size: 1rem; + line-height: 1.5rem; + margin-top: 1rem; +} +#nx-cloud pre { + margin-top: 1rem; +} +#nx-cloud a { + color: rgba(107, 114, 128, 1); + display: block; + font-size: 0.875rem; + line-height: 1.25rem; + margin-top: 1.5rem; + text-align: right; +} +#nx-cloud a:hover { + text-decoration: underline; +} +#commands { + padding: 2.5rem 2rem; + margin-top: 3.5rem; +} +#commands h2 { + font-size: 1.25rem; + font-weight: 400; + letter-spacing: -0.025em; + line-height: 1.75rem; + padding-left: 1rem; + padding-right: 1rem; +} +#commands p { + font-size: 1rem; + font-weight: 300; + line-height: 1.5rem; + margin-top: 1rem; + padding-left: 1rem; + padding-right: 1rem; +} +details { + align-items: center; + display: flex; + margin-top: 1rem; + padding-left: 1rem; + padding-right: 1rem; + width: 100%; +} +details pre > span { + color: rgba(181, 181, 181, 1); + display: block; +} +summary { + border-radius: 0.5rem; + display: flex; + font-weight: 400; + padding: 0.5rem; + cursor: pointer; + transition-property: + background-color, + border-color, + color, + fill, + stroke, + opacity, + box-shadow, + transform, + filter, + backdrop-filter, + -webkit-backdrop-filter; + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + transition-duration: 150ms; +} +summary:hover { + background-color: rgba(243, 244, 246, 1); +} +summary svg { + height: 1.5rem; + margin-right: 1rem; + width: 1.5rem; +} +#love { + color: rgba(107, 114, 128, 1); + font-size: 0.875rem; + line-height: 1.25rem; + margin-top: 3.5rem; + opacity: 0.6; + text-align: center; +} +#love svg { + color: rgba(252, 165, 165, 1); + width: 1.25rem; + height: 1.25rem; + display: inline; + margin-top: -0.25rem; +} +@media screen and (min-width: 768px) { + #hero { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } + #hero .logo-container { + display: flex; + } + #middle-content { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } +} diff --git a/src/Web/MeAjudaAi.Web.Admin-React/src/app/layout.tsx b/src/Web/MeAjudaAi.Web.Admin-React/src/app/layout.tsx new file mode 100644 index 000000000..2e6a012b3 --- /dev/null +++ b/src/Web/MeAjudaAi.Web.Admin-React/src/app/layout.tsx @@ -0,0 +1,18 @@ +import './global.css'; + +export const metadata = { + title: 'Welcome to MeAjudaAi.Web.Admin-React', + description: 'Generated by create-nx-workspace', +}; + +export default function RootLayout({ + children, +}: { + children: React.ReactNode; +}) { + return ( + + {children} + + ); +} diff --git a/src/Web/MeAjudaAi.Web.Admin-React/src/app/page.tsx b/src/Web/MeAjudaAi.Web.Admin-React/src/app/page.tsx new file mode 100644 index 000000000..dae2082ac --- /dev/null +++ b/src/Web/MeAjudaAi.Web.Admin-React/src/app/page.tsx @@ -0,0 +1,467 @@ +export default function Index() { + /* + * Replace the elements below with your own. + * + * Note: The corresponding styles are in the ./index.tailwind file. + */ + return ( +
+
+
+
+

+ Hello there, + Welcome MeAjudaAi.Web.Admin-React šŸ‘‹ +

+
+ +
+
+

+ + + + You're up and running +

+ What's next? +
+
+ + + +
+
+ + + +
+

Next steps

+

Here are some things you can do with Nx:

+
+ + + + + Add UI library + +
+                # Generate UI lib
+                nx g @nx/next:library ui
+                # Add a component
+                nx g @nx/next:component ui/src/lib/button
+              
+
+
+ + + + + View project details + +
nx show project MeAjudaAi.Web.Admin-React --web
+
+
+ + + + + View interactive project graph + +
nx graph
+
+
+ + + + + Run affected commands + +
+                # see what's been affected by changes
+                nx affected:graph
+                # run tests for current changes
+                nx affected:test
+                # run e2e tests for current changes
+                nx affected:e2e
+              
+
+
+ +

+ Carefully crafted with + + + +

+
+
+
+ ); +} diff --git a/src/Web/MeAjudaAi.Web.Admin-React/tailwind.config.js b/src/Web/MeAjudaAi.Web.Admin-React/tailwind.config.js new file mode 100644 index 000000000..a1b266a84 --- /dev/null +++ b/src/Web/MeAjudaAi.Web.Admin-React/tailwind.config.js @@ -0,0 +1,23 @@ +// const { createGlobPatternsForDependencies } = require('@nx/next/tailwind'); + +// The above utility import will not work if you are using Next.js' --turbo. +// Instead you will have to manually add the dependent paths to be included. +// For example +// ../libs/buttons/**/*.{ts,tsx,js,jsx,html}', <--- Adding a shared lib +// !../libs/buttons/**/*.{stories,spec}.{ts,tsx,js,jsx,html}', <--- Skip adding spec/stories files from shared lib + +// If you are **not** using `--turbo` you can uncomment both lines 1 & 19. +// A discussion of the issue can be found: https://github.com/nrwl/nx/issues/26510 + +/** @type {import('tailwindcss').Config} */ +module.exports = { + content: [ + './{src,pages,components,app}/**/*.{ts,tsx,js,jsx,html}', + '!./{src,pages,components,app}/**/*.{stories,spec}.{ts,tsx,js,jsx,html}', + // ...createGlobPatternsForDependencies(__dirname) + ], + theme: { + extend: {}, + }, + plugins: [], +}; diff --git a/src/Web/MeAjudaAi.Web.Admin-React/tsconfig.json b/src/Web/MeAjudaAi.Web.Admin-React/tsconfig.json new file mode 100644 index 000000000..d30455784 --- /dev/null +++ b/src/Web/MeAjudaAi.Web.Admin-React/tsconfig.json @@ -0,0 +1,39 @@ +{ + "extends": "../tsconfig.base.json", + "compilerOptions": { + "jsx": "preserve", + + "strict": true, + "noEmit": true, + "emitDeclarationOnly": false, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "bundler", + "resolveJsonModule": true, + "isolatedModules": true, + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": true, + "allowSyntheticDefaultImports": true, + "forceConsistentCasingInFileNames": true, + "incremental": true, + "plugins": [{ "name": "next" }] + }, + "include": [ + "**/*.ts", + "**/*.tsx", + "**/*.js", + "**/*.jsx", + + "../MeAjudaAi.Web.Admin-React/.next/types/**/*.ts", + "../dist/MeAjudaAi.Web.Admin-React/.next/types/**/*.ts", + + "next-env.d.ts" + ], + "exclude": [ + "node_modules", + "jest.config.ts", + "jest.config.cts", + "**/*.spec.ts", + "**/*.test.ts" + ] +} diff --git a/src/Web/package.json b/src/Web/package.json index 761502e61..ac8d88167 100644 --- a/src/Web/package.json +++ b/src/Web/package.json @@ -54,6 +54,7 @@ "@typescript-eslint/parser": "^8.0.0", "@vitejs/plugin-react": "^4.2.0", "@vitest/ui": "^4.0.0", + "autoprefixer": "10.4.13", "eslint": "~8.57.0", "eslint-config-prettier": "^10.0.0", "jest": "^29.7.0", @@ -63,7 +64,9 @@ "jsdom": "~22.1.0", "jsonc-eslint-parser": "^2.1.0", "nx": "22.5.4", + "postcss": "8.4.38", "prettier": "~3.6.2", + "tailwindcss": "3.4.3", "ts-jest": "^29.4.0", "ts-node": "10.9.1", "tslib": "^2.3.0", From 8aa16751b18e38008501db688b6c532169c6fc99 Mon Sep 17 00:00:00 2001 From: Filipe Frigini Date: Sat, 21 Mar 2026 14:10:13 -0300 Subject: [PATCH 02/19] feat(Admin): Add foundation for Admin Portal React app - Add Tailwind v4 CSS variables theme in global.css - Create admin layout with sidebar navigation - Add UI components: Card, Button, Badge, Input - Create dashboard with KPI cards and Recharts pie chart - Add providers page with mock data table - Add placeholder pages: documents, categories, services, allowed-cities, settings - Configure next-auth with Keycloak provider - Set up AppProviders with TanStack Query --- .../src/app/(admin)/allowed-cities/page.tsx | 28 + .../src/app/(admin)/categories/page.tsx | 28 + .../src/app/(admin)/dashboard/page.tsx | 115 ++++ .../src/app/(admin)/documents/page.tsx | 28 + .../src/app/(admin)/layout.tsx | 14 + .../src/app/(admin)/providers/page.tsx | 92 +++ .../src/app/(admin)/services/page.tsx | 28 + .../src/app/(admin)/settings/page.tsx | 24 + .../src/app/global.css | 554 ++---------------- .../src/app/layout.tsx | 19 +- .../src/app/page.tsx | 468 +-------------- .../src/components/layout/sidebar.tsx | 86 +++ .../components/providers/app-providers.tsx | 30 + .../src/components/ui/badge.tsx | 27 + .../src/components/ui/button.tsx | 43 ++ .../src/components/ui/card.tsx | 47 ++ .../src/components/ui/input.tsx | 20 + .../src/lib/auth/auth.ts | 22 + 18 files changed, 703 insertions(+), 970 deletions(-) create mode 100644 src/Web/MeAjudaAi.Web.Admin-React/src/app/(admin)/allowed-cities/page.tsx create mode 100644 src/Web/MeAjudaAi.Web.Admin-React/src/app/(admin)/categories/page.tsx create mode 100644 src/Web/MeAjudaAi.Web.Admin-React/src/app/(admin)/dashboard/page.tsx create mode 100644 src/Web/MeAjudaAi.Web.Admin-React/src/app/(admin)/documents/page.tsx create mode 100644 src/Web/MeAjudaAi.Web.Admin-React/src/app/(admin)/layout.tsx create mode 100644 src/Web/MeAjudaAi.Web.Admin-React/src/app/(admin)/providers/page.tsx create mode 100644 src/Web/MeAjudaAi.Web.Admin-React/src/app/(admin)/services/page.tsx create mode 100644 src/Web/MeAjudaAi.Web.Admin-React/src/app/(admin)/settings/page.tsx create mode 100644 src/Web/MeAjudaAi.Web.Admin-React/src/components/layout/sidebar.tsx create mode 100644 src/Web/MeAjudaAi.Web.Admin-React/src/components/providers/app-providers.tsx create mode 100644 src/Web/MeAjudaAi.Web.Admin-React/src/components/ui/badge.tsx create mode 100644 src/Web/MeAjudaAi.Web.Admin-React/src/components/ui/button.tsx create mode 100644 src/Web/MeAjudaAi.Web.Admin-React/src/components/ui/card.tsx create mode 100644 src/Web/MeAjudaAi.Web.Admin-React/src/components/ui/input.tsx create mode 100644 src/Web/MeAjudaAi.Web.Admin-React/src/lib/auth/auth.ts diff --git a/src/Web/MeAjudaAi.Web.Admin-React/src/app/(admin)/allowed-cities/page.tsx b/src/Web/MeAjudaAi.Web.Admin-React/src/app/(admin)/allowed-cities/page.tsx new file mode 100644 index 000000000..8659ee68e --- /dev/null +++ b/src/Web/MeAjudaAi.Web.Admin-React/src/app/(admin)/allowed-cities/page.tsx @@ -0,0 +1,28 @@ +"use client"; + +import { MapPin, Plus } from "lucide-react"; +import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card"; +import { Button } from "@/components/ui/button"; + +export default function AllowedCitiesPage() { + return ( +
+
+
+

Cidades Permitidas

+

Gerencie cidades atendidas

+
+ +
+ + + + Cidades Ativas + + +

Funcionalidade em desenvolvimento.

+
+
+
+ ); +} diff --git a/src/Web/MeAjudaAi.Web.Admin-React/src/app/(admin)/categories/page.tsx b/src/Web/MeAjudaAi.Web.Admin-React/src/app/(admin)/categories/page.tsx new file mode 100644 index 000000000..7ad339689 --- /dev/null +++ b/src/Web/MeAjudaAi.Web.Admin-React/src/app/(admin)/categories/page.tsx @@ -0,0 +1,28 @@ +"use client"; + +import { FolderTree, Plus } from "lucide-react"; +import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card"; +import { Button } from "@/components/ui/button"; + +export default function CategoriesPage() { + return ( +
+
+
+

Categorias

+

Gerencie categorias de serviƧos

+
+ +
+ + + + Categorias de ServiƧos + + +

Funcionalidade em desenvolvimento.

+
+
+
+ ); +} diff --git a/src/Web/MeAjudaAi.Web.Admin-React/src/app/(admin)/dashboard/page.tsx b/src/Web/MeAjudaAi.Web.Admin-React/src/app/(admin)/dashboard/page.tsx new file mode 100644 index 000000000..f78430aa4 --- /dev/null +++ b/src/Web/MeAjudaAi.Web.Admin-React/src/app/(admin)/dashboard/page.tsx @@ -0,0 +1,115 @@ +"use client"; + +import { Users, Clock, CheckCircle, AlertCircle } from "lucide-react"; +import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card"; +import { PieChart, Pie, Cell, ResponsiveContainer } from "recharts"; + +const statusData = [ + { name: "Aprovados", value: 145, color: "#22c55e" }, + { name: "Pendentes", value: 32, color: "#f59e0b" }, + { name: "Rejeitados", value: 8, color: "#ef4444" }, +]; + +export default function DashboardPage() { + return ( +
+
+

Dashboard

+

Visão geral dos prestadores e métricas

+
+ +
+ + + + Total de Prestadores + + + + +
185
+

+12 este mĆŖs

+
+
+ + + + + Aguardando Verificação + + + + +
32
+

Revisão pendente

+
+
+ + + + + Aprovados + + + + +
145
+

78% do total

+
+
+ + + + + Rejeitados + + + + +
8
+

4% do total

+
+
+
+ +
+ + + Status de Verificação + + +
+ + + `${name} ${(percent * 100).toFixed(0)}%`} + > + {statusData.map((entry, index) => ( + + ))} + + + +
+
+
+ + + + Prestadores por Tipo + + +

GrƔfico em desenvolvimento

+
+
+
+
+ ); +} diff --git a/src/Web/MeAjudaAi.Web.Admin-React/src/app/(admin)/documents/page.tsx b/src/Web/MeAjudaAi.Web.Admin-React/src/app/(admin)/documents/page.tsx new file mode 100644 index 000000000..1a78ec13a --- /dev/null +++ b/src/Web/MeAjudaAi.Web.Admin-React/src/app/(admin)/documents/page.tsx @@ -0,0 +1,28 @@ +"use client"; + +import { FileText, Upload } from "lucide-react"; +import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card"; +import { Button } from "@/components/ui/button"; + +export default function DocumentsPage() { + return ( +
+
+
+

Documentos

+

Gerencie documentos dos prestadores

+
+ +
+ + + + Documentos Recentes + + +

Funcionalidade em desenvolvimento.

+
+
+
+ ); +} diff --git a/src/Web/MeAjudaAi.Web.Admin-React/src/app/(admin)/layout.tsx b/src/Web/MeAjudaAi.Web.Admin-React/src/app/(admin)/layout.tsx new file mode 100644 index 000000000..cc7dd78f9 --- /dev/null +++ b/src/Web/MeAjudaAi.Web.Admin-React/src/app/(admin)/layout.tsx @@ -0,0 +1,14 @@ +import { Sidebar } from "@/components/layout/sidebar"; + +export default function AdminLayout({ + children, +}: { + children: React.ReactNode; +}) { + return ( +
+ +
{children}
+
+ ); +} diff --git a/src/Web/MeAjudaAi.Web.Admin-React/src/app/(admin)/providers/page.tsx b/src/Web/MeAjudaAi.Web.Admin-React/src/app/(admin)/providers/page.tsx new file mode 100644 index 000000000..4ba196577 --- /dev/null +++ b/src/Web/MeAjudaAi.Web.Admin-React/src/app/(admin)/providers/page.tsx @@ -0,0 +1,92 @@ +"use client"; + +import { useState } from "react"; +import { Search, Plus, Pencil, Trash2, Eye, CheckCircle, XCircle } from "lucide-react"; +import { Card } from "@/components/ui/card"; +import { Button } from "@/components/ui/button"; +import { Badge } from "@/components/ui/badge"; +import { Input } from "@/components/ui/input"; + +const mockProviders = [ + { id: "1", name: "João Silva", email: "joao@email.com", phone: "(11) 99999-9999", type: "Pessoa Física", status: "Aprovado", city: "São Paulo" }, + { id: "2", name: "Maria Santos", email: "maria@email.com", phone: "(11) 88888-8888", type: "Pessoa Física", status: "Pendente", city: "Campinas" }, + { id: "3", name: "Tech Solutions Ltda", email: "contato@techsolutions.com", phone: "(11) 77777-7777", type: "Empresa", status: "Aprovado", city: "São Paulo" }, +]; + +const statusVariant = (status: string) => { + switch (status) { + case "Aprovado": return "success"; + case "Pendente": return "warning"; + case "Rejeitado": return "destructive"; + default: return "secondary"; + } +}; + +export default function ProvidersPage() { + const [search, setSearch] = useState(""); + + const filteredProviders = mockProviders.filter( + (p) => p.name.toLowerCase().includes(search.toLowerCase()) || p.email.toLowerCase().includes(search.toLowerCase()) + ); + + return ( +
+
+
+

Prestadores

+

Gerencie os prestadores de serviƧos

+
+ +
+ + +
+
+ + setSearch(e.target.value)} /> +
+
+
+ + +
+ + + + + + + + + + + + + + {filteredProviders.map((provider) => ( + + + + + + + + + + ))} + +
NomeEmailTelefoneTipoStatusCidadeAƧƵes
{provider.name}{provider.email}{provider.phone}{provider.type}{provider.status}{provider.city} +
+ + + + + +
+
+
+ {filteredProviders.length === 0 &&
Nenhum prestador encontrado
} +
+
+ ); +} diff --git a/src/Web/MeAjudaAi.Web.Admin-React/src/app/(admin)/services/page.tsx b/src/Web/MeAjudaAi.Web.Admin-React/src/app/(admin)/services/page.tsx new file mode 100644 index 000000000..ff026b4cf --- /dev/null +++ b/src/Web/MeAjudaAi.Web.Admin-React/src/app/(admin)/services/page.tsx @@ -0,0 +1,28 @@ +"use client"; + +import { Wrench, Plus } from "lucide-react"; +import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card"; +import { Button } from "@/components/ui/button"; + +export default function ServicesPage() { + return ( +
+
+
+

ServiƧos

+

Gerencie serviƧos disponƭveis

+
+ +
+ + + + CatƔlogo de ServiƧos + + +

Funcionalidade em desenvolvimento.

+
+
+
+ ); +} diff --git a/src/Web/MeAjudaAi.Web.Admin-React/src/app/(admin)/settings/page.tsx b/src/Web/MeAjudaAi.Web.Admin-React/src/app/(admin)/settings/page.tsx new file mode 100644 index 000000000..5bdfa4baa --- /dev/null +++ b/src/Web/MeAjudaAi.Web.Admin-React/src/app/(admin)/settings/page.tsx @@ -0,0 +1,24 @@ +"use client"; + +import { Settings } from "lucide-react"; +import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card"; + +export default function SettingsPage() { + return ( +
+
+

ConfiguraƧƵes

+

PreferĆŖncias do sistema

+
+ + + + ConfiguraƧƵes Gerais + + +

Funcionalidade em desenvolvimento.

+
+
+
+ ); +} diff --git a/src/Web/MeAjudaAi.Web.Admin-React/src/app/global.css b/src/Web/MeAjudaAi.Web.Admin-React/src/app/global.css index 66211edf3..1098ddbfa 100644 --- a/src/Web/MeAjudaAi.Web.Admin-React/src/app/global.css +++ b/src/Web/MeAjudaAi.Web.Admin-React/src/app/global.css @@ -1,505 +1,61 @@ -@tailwind base; -@tailwind components; -@tailwind utilities; +@import "tailwindcss"; -html { - -webkit-text-size-adjust: 100%; - font-family: - ui-sans-serif, - system-ui, - -apple-system, - BlinkMacSystemFont, - Segoe UI, - Roboto, - Helvetica Neue, - Arial, - Noto Sans, - sans-serif, - Apple Color Emoji, - Segoe UI Emoji, - Segoe UI Symbol, - Noto Color Emoji; - line-height: 1.5; - tab-size: 4; - scroll-behavior: smooth; -} -body { - font-family: inherit; - line-height: inherit; - margin: 0; -} -h1, -h2, -p, -pre { - margin: 0; -} -*, -::before, -::after { - box-sizing: border-box; - border-width: 0; - border-style: solid; - border-color: currentColor; -} -h1, -h2 { - font-size: inherit; - font-weight: inherit; -} -a { - color: inherit; - text-decoration: inherit; -} -pre { - font-family: - ui-monospace, - SFMono-Regular, - Menlo, - Monaco, - Consolas, - Liberation Mono, - Courier New, - monospace; -} -svg { - display: block; - vertical-align: middle; - shape-rendering: auto; - text-rendering: optimizeLegibility; -} -pre { - background-color: rgba(55, 65, 81, 1); - border-radius: 0.25rem; - color: rgba(229, 231, 235, 1); - font-family: - ui-monospace, - SFMono-Regular, - Menlo, - Monaco, - Consolas, - Liberation Mono, - Courier New, - monospace; - overflow: scroll; - padding: 0.5rem 0.75rem; -} +@theme inline { + --color-primary: #395873; + --color-primary-foreground: #ffffff; + --color-primary-hover: #2E4760; -.shadow { - box-shadow: - 0 0 #0000, - 0 0 #0000, - 0 10px 15px -3px rgba(0, 0, 0, 0.1), - 0 4px 6px -2px rgba(0, 0, 0, 0.05); -} -.rounded { - border-radius: 1.5rem; -} -.wrapper { - width: 100%; -} -.container { - margin-left: auto; - margin-right: auto; - max-width: 768px; - padding-bottom: 3rem; - padding-left: 1rem; - padding-right: 1rem; - color: rgba(55, 65, 81, 1); - width: 100%; -} -#welcome { - margin-top: 2.5rem; -} -#welcome h1 { - font-size: 3rem; - font-weight: 500; - letter-spacing: -0.025em; - line-height: 1; -} -#welcome span { - display: block; - font-size: 1.875rem; - font-weight: 300; - line-height: 2.25rem; - margin-bottom: 0.5rem; -} -#hero { - align-items: center; - background-color: hsla(214, 62%, 21%, 1); - border: none; - box-sizing: border-box; - color: rgba(55, 65, 81, 1); - display: grid; - grid-template-columns: 1fr; - margin-top: 3.5rem; -} -#hero .text-container { - color: rgba(255, 255, 255, 1); - padding: 3rem 2rem; -} -#hero .text-container h2 { - font-size: 1.5rem; - line-height: 2rem; - position: relative; -} -#hero .text-container h2 svg { - color: hsla(162, 47%, 50%, 1); - height: 2rem; - left: -0.25rem; - position: absolute; - top: 0; - width: 2rem; -} -#hero .text-container h2 span { - margin-left: 2.5rem; -} -#hero .text-container a { - background-color: rgba(255, 255, 255, 1); - border-radius: 0.75rem; - color: rgba(55, 65, 81, 1); - display: inline-block; - margin-top: 1.5rem; - padding: 1rem 2rem; - text-decoration: inherit; -} -#hero .logo-container { - display: none; - justify-content: center; - padding-left: 2rem; - padding-right: 2rem; -} -#hero .logo-container svg { - color: rgba(255, 255, 255, 1); - width: 66.666667%; -} -#middle-content { - align-items: flex-start; - display: grid; - gap: 4rem; - grid-template-columns: 1fr; - margin-top: 3.5rem; -} -#learning-materials { - padding: 2.5rem 2rem; -} -#learning-materials h2 { - font-weight: 500; - font-size: 1.25rem; - letter-spacing: -0.025em; - line-height: 1.75rem; - padding-left: 1rem; - padding-right: 1rem; -} -.list-item-link { - align-items: center; - border-radius: 0.75rem; - display: flex; - margin-top: 1rem; - padding: 1rem; - transition-property: - background-color, - border-color, - color, - fill, - stroke, - opacity, - box-shadow, - transform, - filter, - backdrop-filter, - -webkit-backdrop-filter; - transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); - transition-duration: 150ms; - width: 100%; -} -.list-item-link svg:first-child { - margin-right: 1rem; - height: 1.5rem; - transition-property: - background-color, - border-color, - color, - fill, - stroke, - opacity, - box-shadow, - transform, - filter, - backdrop-filter, - -webkit-backdrop-filter; - transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); - transition-duration: 150ms; - width: 1.5rem; -} -.list-item-link > span { - flex-grow: 1; - font-weight: 400; - transition-property: - background-color, - border-color, - color, - fill, - stroke, - opacity, - box-shadow, - transform, - filter, - backdrop-filter, - -webkit-backdrop-filter; - transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); - transition-duration: 150ms; -} -.list-item-link > span > span { - color: rgba(107, 114, 128, 1); - display: block; - flex-grow: 1; - font-size: 0.75rem; - font-weight: 300; - line-height: 1rem; - transition-property: - background-color, - border-color, - color, - fill, - stroke, - opacity, - box-shadow, - transform, - filter, - backdrop-filter, - -webkit-backdrop-filter; - transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); - transition-duration: 150ms; -} -.list-item-link svg:last-child { - height: 1rem; - transition-property: all; - transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); - transition-duration: 150ms; - width: 1rem; -} -.list-item-link:hover { - color: rgba(255, 255, 255, 1); - background-color: hsla(162, 47%, 50%, 1); -} -.list-item-link:hover > span { -} -.list-item-link:hover > span > span { - color: rgba(243, 244, 246, 1); -} -.list-item-link:hover svg:last-child { - transform: translateX(0.25rem); -} -#other-links { -} -.button-pill { - padding: 1.5rem 2rem; - transition-duration: 300ms; - transition-property: - background-color, - border-color, - color, - fill, - stroke, - opacity, - box-shadow, - transform, - filter, - backdrop-filter, - -webkit-backdrop-filter; - transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); - align-items: center; - display: flex; -} -.button-pill svg { - transition-property: - background-color, - border-color, - color, - fill, - stroke, - opacity, - box-shadow, - transform, - filter, - backdrop-filter, - -webkit-backdrop-filter; - transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); - transition-duration: 150ms; - flex-shrink: 0; - width: 3rem; -} -.button-pill > span { - letter-spacing: -0.025em; - font-weight: 400; - font-size: 1.125rem; - line-height: 1.75rem; - padding-left: 1rem; - padding-right: 1rem; -} -.button-pill span span { - display: block; - font-size: 0.875rem; - font-weight: 300; - line-height: 1.25rem; -} -.button-pill:hover svg, -.button-pill:hover { - color: rgba(255, 255, 255, 1) !important; -} -#nx-console:hover { - background-color: rgba(0, 122, 204, 1); -} -#nx-console svg { - color: rgba(0, 122, 204, 1); -} -#nx-console-jetbrains { - margin-top: 2rem; -} -#nx-console-jetbrains:hover { - background-color: rgba(255, 49, 140, 1); -} -#nx-console-jetbrains svg { - color: rgba(255, 49, 140, 1); -} -#nx-repo:hover { - background-color: rgba(24, 23, 23, 1); -} -#nx-repo svg { - color: rgba(24, 23, 23, 1); -} -#nx-cloud { - margin-bottom: 2rem; - margin-top: 2rem; - padding: 2.5rem 2rem; -} -#nx-cloud > div { - align-items: center; - display: flex; -} -#nx-cloud > div svg { - border-radius: 0.375rem; - flex-shrink: 0; - width: 3rem; -} -#nx-cloud > div h2 { - font-size: 1.125rem; - font-weight: 400; - letter-spacing: -0.025em; - line-height: 1.75rem; - padding-left: 1rem; - padding-right: 1rem; -} -#nx-cloud > div h2 span { - display: block; - font-size: 0.875rem; - font-weight: 300; - line-height: 1.25rem; -} -#nx-cloud p { - font-size: 1rem; - line-height: 1.5rem; - margin-top: 1rem; -} -#nx-cloud pre { - margin-top: 1rem; -} -#nx-cloud a { - color: rgba(107, 114, 128, 1); - display: block; - font-size: 0.875rem; - line-height: 1.25rem; - margin-top: 1.5rem; - text-align: right; -} -#nx-cloud a:hover { - text-decoration: underline; -} -#commands { - padding: 2.5rem 2rem; - margin-top: 3.5rem; -} -#commands h2 { - font-size: 1.25rem; - font-weight: 400; - letter-spacing: -0.025em; - line-height: 1.75rem; - padding-left: 1rem; - padding-right: 1rem; -} -#commands p { - font-size: 1rem; - font-weight: 300; - line-height: 1.5rem; - margin-top: 1rem; - padding-left: 1rem; - padding-right: 1rem; -} -details { - align-items: center; - display: flex; - margin-top: 1rem; - padding-left: 1rem; - padding-right: 1rem; - width: 100%; -} -details pre > span { - color: rgba(181, 181, 181, 1); - display: block; -} -summary { - border-radius: 0.5rem; - display: flex; - font-weight: 400; - padding: 0.5rem; - cursor: pointer; - transition-property: - background-color, - border-color, - color, - fill, - stroke, - opacity, - box-shadow, - transform, - filter, - backdrop-filter, - -webkit-backdrop-filter; - transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); - transition-duration: 150ms; -} -summary:hover { - background-color: rgba(243, 244, 246, 1); -} -summary svg { - height: 1.5rem; - margin-right: 1rem; - width: 1.5rem; -} -#love { - color: rgba(107, 114, 128, 1); - font-size: 0.875rem; - line-height: 1.25rem; - margin-top: 3.5rem; - opacity: 0.6; - text-align: center; + --color-secondary: #f5f5f5; + --color-secondary-foreground: #2e2e2e; + + --color-muted: #f5f5f5; + --color-muted-foreground: #666666; + + --color-destructive: #dc2626; + --color-destructive-foreground: #ffffff; + + --color-border: #e0e0e0; + --color-input: #e0e0e0; + + --color-background: #ffffff; + --color-surface: #ffffff; + --color-surface-raised: #f5f5f5; + --color-foreground: #2e2e2e; + --color-foreground-subtle: #666666; + + --color-card: #ffffff; + --color-card-foreground: #2e2e2e; + + --color-ring: #395873; + + --radius-sm: 0.375rem; + --radius-md: 0.5rem; + --radius-lg: 0.75rem; + --radius-xl: 1rem; } -#love svg { - color: rgba(252, 165, 165, 1); - width: 1.25rem; - height: 1.25rem; - display: inline; - margin-top: -0.25rem; + +:root { + --background: #ffffff; + --foreground: #2e2e2e; + --surface: #ffffff; + --surface-raised: #f5f5f5; + --foreground-subtle: #666666; + --border: #e0e0e0; + --input: #e0e0e0; } -@media screen and (min-width: 768px) { - #hero { - grid-template-columns: repeat(2, minmax(0, 1fr)); - } - #hero .logo-container { - display: flex; - } - #middle-content { - grid-template-columns: repeat(2, minmax(0, 1fr)); + +@media (prefers-color-scheme: dark) { + :root { + --background: #0a0a0a; + --foreground: #ededed; + --surface: #1a1a1a; + --surface-raised: #262626; + --foreground-subtle: #a3a3a3; + --border: #404040; + --input: #404040; } } + +body { + font-family: var(--font-sans), system-ui, -apple-system, sans-serif; +} diff --git a/src/Web/MeAjudaAi.Web.Admin-React/src/app/layout.tsx b/src/Web/MeAjudaAi.Web.Admin-React/src/app/layout.tsx index 2e6a012b3..177c4edc9 100644 --- a/src/Web/MeAjudaAi.Web.Admin-React/src/app/layout.tsx +++ b/src/Web/MeAjudaAi.Web.Admin-React/src/app/layout.tsx @@ -1,8 +1,13 @@ -import './global.css'; +import type { Metadata } from "next"; +import { Inter } from "next/font/google"; +import "./global.css"; +import { AppProviders } from "@/components/providers/app-providers"; -export const metadata = { - title: 'Welcome to MeAjudaAi.Web.Admin-React', - description: 'Generated by create-nx-workspace', +const inter = Inter({ subsets: ["latin"] }); + +export const metadata: Metadata = { + title: "MeAjudaAí - Admin Portal", + description: "Portal de administração do MeAjudaAí", }; export default function RootLayout({ @@ -11,8 +16,10 @@ export default function RootLayout({ children: React.ReactNode; }) { return ( - - {children} + + + {children} + ); } diff --git a/src/Web/MeAjudaAi.Web.Admin-React/src/app/page.tsx b/src/Web/MeAjudaAi.Web.Admin-React/src/app/page.tsx index dae2082ac..9ef12352d 100644 --- a/src/Web/MeAjudaAi.Web.Admin-React/src/app/page.tsx +++ b/src/Web/MeAjudaAi.Web.Admin-React/src/app/page.tsx @@ -1,467 +1,5 @@ -export default function Index() { - /* - * Replace the elements below with your own. - * - * Note: The corresponding styles are in the ./index.tailwind file. - */ - return ( -
-
-
-
-

- Hello there, - Welcome MeAjudaAi.Web.Admin-React šŸ‘‹ -

-
+import { redirect } from "next/navigation"; -
-
-

- - - - You're up and running -

- What's next? -
-
- - - -
-
- - - -
-

Next steps

-

Here are some things you can do with Nx:

-
- - - - - Add UI library - -
-                # Generate UI lib
-                nx g @nx/next:library ui
-                # Add a component
-                nx g @nx/next:component ui/src/lib/button
-              
-
-
- - - - - View project details - -
nx show project MeAjudaAi.Web.Admin-React --web
-
-
- - - - - View interactive project graph - -
nx graph
-
-
- - - - - Run affected commands - -
-                # see what's been affected by changes
-                nx affected:graph
-                # run tests for current changes
-                nx affected:test
-                # run e2e tests for current changes
-                nx affected:e2e
-              
-
-
- -

- Carefully crafted with - - - -

-
-
-
- ); +export default function HomePage() { + redirect("/dashboard"); } diff --git a/src/Web/MeAjudaAi.Web.Admin-React/src/components/layout/sidebar.tsx b/src/Web/MeAjudaAi.Web.Admin-React/src/components/layout/sidebar.tsx new file mode 100644 index 000000000..6f61357de --- /dev/null +++ b/src/Web/MeAjudaAi.Web.Admin-React/src/components/layout/sidebar.tsx @@ -0,0 +1,86 @@ +"use client"; + +import Link from "next/link"; +import { usePathname } from "next/navigation"; +import { + LayoutDashboard, + Users, + FileText, + FolderTree, + Wrench, + MapPin, + Settings, + LogOut, +} from "lucide-react"; +import { signOut, useSession } from "next-auth/react"; +import { twMerge } from "tailwind-merge"; + +const navItems = [ + { href: "/dashboard", label: "Dashboard", icon: LayoutDashboard }, + { href: "/providers", label: "Prestadores", icon: Users }, + { href: "/documents", label: "Documentos", icon: FileText }, + { href: "/categories", label: "Categorias", icon: FolderTree }, + { href: "/services", label: "ServiƧos", icon: Wrench }, + { href: "/allowed-cities", label: "Cidades", icon: MapPin }, + { href: "/settings", label: "ConfiguraƧƵes", icon: Settings }, +]; + +export function Sidebar() { + const pathname = usePathname(); + const { data: session } = useSession(); + + return ( + + ); +} diff --git a/src/Web/MeAjudaAi.Web.Admin-React/src/components/providers/app-providers.tsx b/src/Web/MeAjudaAi.Web.Admin-React/src/components/providers/app-providers.tsx new file mode 100644 index 000000000..85a732d70 --- /dev/null +++ b/src/Web/MeAjudaAi.Web.Admin-React/src/components/providers/app-providers.tsx @@ -0,0 +1,30 @@ +"use client"; + +import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; +import { SessionProvider } from "next-auth/react"; +import { ThemeProvider } from "next-themes"; +import { useState } from "react"; + +export function AppProviders({ children }: { children: React.ReactNode }) { + const [queryClient] = useState( + () => + new QueryClient({ + defaultOptions: { + queries: { + staleTime: 60 * 1000, + refetchOnWindowFocus: false, + }, + }, + }) + ); + + return ( + + + + {children} + + + + ); +} diff --git a/src/Web/MeAjudaAi.Web.Admin-React/src/components/ui/badge.tsx b/src/Web/MeAjudaAi.Web.Admin-React/src/components/ui/badge.tsx new file mode 100644 index 000000000..6ba45cb80 --- /dev/null +++ b/src/Web/MeAjudaAi.Web.Admin-React/src/components/ui/badge.tsx @@ -0,0 +1,27 @@ +import { tv, type VariantProps } from "tailwind-variants"; +import { twMerge } from "tailwind-merge"; +import type { ComponentProps } from "react"; + +export const badgeVariants = tv({ + base: [ + "inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors", + ], + variants: { + variant: { + default: "border-transparent bg-primary text-primary-foreground", + secondary: "border-transparent bg-secondary text-secondary-foreground", + destructive: "border-transparent bg-destructive text-destructive-foreground", + success: "border-transparent bg-green-100 text-green-800", + warning: "border-transparent bg-yellow-100 text-yellow-800", + }, + }, + defaultVariants: { variant: "default" }, +}); + +export interface BadgeProps extends ComponentProps<"span">, VariantProps {} + +export function Badge({ className, variant, ...props }: BadgeProps) { + return ( + + ); +} diff --git a/src/Web/MeAjudaAi.Web.Admin-React/src/components/ui/button.tsx b/src/Web/MeAjudaAi.Web.Admin-React/src/components/ui/button.tsx new file mode 100644 index 000000000..f431788bb --- /dev/null +++ b/src/Web/MeAjudaAi.Web.Admin-React/src/components/ui/button.tsx @@ -0,0 +1,43 @@ +import { tv, type VariantProps } from "tailwind-variants"; +import { twMerge } from "tailwind-merge"; +import type { ComponentProps } from "react"; + +export const buttonVariants = tv({ + base: [ + "inline-flex cursor-pointer items-center justify-center font-medium rounded-lg transition-colors", + "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", + "data-[disabled]:pointer-events-none data-[disabled]:opacity-50", + ], + variants: { + variant: { + primary: "bg-primary text-primary-foreground hover:bg-primary-hover", + secondary: "bg-secondary text-secondary-foreground hover:bg-secondary-hover", + ghost: "border-transparent bg-transparent text-muted-foreground hover:text-foreground hover:bg-muted", + destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90", + }, + size: { + sm: "h-9 px-3 text-sm", + md: "h-10 px-4 text-sm", + lg: "h-11 px-6 text-base", + icon: "h-10 w-10", + }, + }, + defaultVariants: { variant: "primary", size: "md" }, +}); + +export interface ButtonProps extends ComponentProps<"button">, VariantProps {} + +export function Button({ className, variant, size, disabled, children, ...props }: ButtonProps) { + return ( + + ); +} diff --git a/src/Web/MeAjudaAi.Web.Admin-React/src/components/ui/card.tsx b/src/Web/MeAjudaAi.Web.Admin-React/src/components/ui/card.tsx new file mode 100644 index 000000000..27c0032da --- /dev/null +++ b/src/Web/MeAjudaAi.Web.Admin-React/src/components/ui/card.tsx @@ -0,0 +1,47 @@ +import { twMerge } from "tailwind-merge"; +import type { ComponentProps } from "react"; + +export interface CardProps extends ComponentProps<"div"> {} + +export function Card({ className, ...props }: CardProps) { + return ( +
+ ); +} + +export function CardHeader({ className, ...props }: ComponentProps<"div">) { + return ( +
+ ); +} + +export function CardTitle({ className, ...props }: ComponentProps<"h3">) { + return ( +

+ ); +} + +export function CardContent({ className, ...props }: ComponentProps<"div">) { + return ( +
+ ); +} diff --git a/src/Web/MeAjudaAi.Web.Admin-React/src/components/ui/input.tsx b/src/Web/MeAjudaAi.Web.Admin-React/src/components/ui/input.tsx new file mode 100644 index 000000000..d7165ef37 --- /dev/null +++ b/src/Web/MeAjudaAi.Web.Admin-React/src/components/ui/input.tsx @@ -0,0 +1,20 @@ +import { twMerge } from "tailwind-merge"; +import type { ComponentProps } from "react"; + +export const inputStyles = { + base: [ + "flex h-10 w-full rounded-lg border border-input bg-background px-3 py-2 text-sm", + "file:border-0 file:bg-transparent file:text-sm file:font-medium", + "placeholder:text-muted-foreground", + "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2", + "disabled:cursor-not-allowed disabled:opacity-50", + ], +}; + +export interface InputProps extends ComponentProps<"input"> {} + +export function Input({ className, ...props }: InputProps) { + return ( + + ); +} diff --git a/src/Web/MeAjudaAi.Web.Admin-React/src/lib/auth/auth.ts b/src/Web/MeAjudaAi.Web.Admin-React/src/lib/auth/auth.ts new file mode 100644 index 000000000..190970db1 --- /dev/null +++ b/src/Web/MeAjudaAi.Web.Admin-React/src/lib/auth/auth.ts @@ -0,0 +1,22 @@ +import NextAuth, { type NextAuthOptions } from "next-auth"; +import Keycloak from "next-auth/providers/keycloak"; + +export const authOptions: NextAuthOptions = { + providers: [ + Keycloak({ + clientId: process.env.KEYCLOAK_ADMIN_CLIENT_ID ?? "meajudaai-admin", + clientSecret: process.env.KEYCLOAK_ADMIN_CLIENT_SECRET ?? "", + issuer: process.env.KEYCLOAK_ISSUER, + }), + ], + pages: { + signIn: "/login", + error: "/login", + }, + session: { + strategy: "jwt", + maxAge: 30 * 60, + }, +}; + +export default NextAuth(authOptions); From 6753bcbbdf14daa68379a92da4b84adb87b9922c Mon Sep 17 00:00:00 2001 From: Filipe Frigini Date: Sat, 21 Mar 2026 14:10:23 -0300 Subject: [PATCH 03/19] build(deps): update package-lock.json --- src/Web/package-lock.json | 549 +++++++++++++++++++++++++++++++------- 1 file changed, 458 insertions(+), 91 deletions(-) diff --git a/src/Web/package-lock.json b/src/Web/package-lock.json index 7d8b7415b..afca360ff 100644 --- a/src/Web/package-lock.json +++ b/src/Web/package-lock.json @@ -67,6 +67,7 @@ "@typescript-eslint/parser": "^8.0.0", "@vitejs/plugin-react": "^4.2.0", "@vitest/ui": "^4.0.0", + "autoprefixer": "10.4.13", "eslint": "~8.57.0", "eslint-config-prettier": "^10.0.0", "jest": "^29.7.0", @@ -76,7 +77,9 @@ "jsdom": "~22.1.0", "jsonc-eslint-parser": "^2.1.0", "nx": "22.5.4", + "postcss": "8.4.38", "prettier": "~3.6.2", + "tailwindcss": "3.4.3", "ts-jest": "^29.4.0", "ts-node": "10.9.1", "tslib": "^2.3.0", @@ -509,11 +512,17 @@ "node": "^10 || ^12 || >=14" } }, + "MeAjudaAi.Web.Customer/node_modules/tailwindcss": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.2.2.tgz", + "integrity": "sha512-KWBIxs1Xb6NoLdMVqhbhgwZf2PGBpPEiwOqgI4pFIYbNTfBXiKYyWoTsXgBQ9WFg/OlhnvHaY+AEpW7wSmFo2Q==", + "dev": true, + "license": "MIT" + }, "node_modules/@alloc/quick-lru": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", - "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -2678,7 +2687,7 @@ "version": "0.8.1", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@jridgewell/trace-mapping": "0.3.9" @@ -2691,7 +2700,7 @@ "version": "0.3.9", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", @@ -5824,7 +5833,6 @@ "version": "0.3.13", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", @@ -5846,7 +5854,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.0.0" @@ -5867,14 +5874,12 @@ "version": "1.5.5", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "dev": true, "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.31", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", @@ -7484,7 +7489,6 @@ "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, "license": "MIT", "dependencies": { "@nodelib/fs.stat": "2.0.5", @@ -7498,7 +7502,6 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, "license": "MIT", "engines": { "node": ">= 8" @@ -7508,7 +7511,6 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, "license": "MIT", "dependencies": { "@nodelib/fs.scandir": "2.1.5", @@ -11123,6 +11125,13 @@ "jiti": "lib/jiti-cli.mjs" } }, + "node_modules/@tailwindcss/node/node_modules/tailwindcss": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.2.1.tgz", + "integrity": "sha512-/tBrSQ36vCleJkAOsy9kbNTgaxvGbyOamC30PRePTQe/o1MFwEKHQk4Cn7BNGaPtjp+PuUrByJehM1hgxfq4sw==", + "dev": true, + "license": "MIT" + }, "node_modules/@tailwindcss/oxide": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.2.1.tgz", @@ -11378,6 +11387,42 @@ "tailwindcss": "4.2.1" } }, + "node_modules/@tailwindcss/postcss/node_modules/postcss": { + "version": "8.5.8", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz", + "integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/@tailwindcss/postcss/node_modules/tailwindcss": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.2.1.tgz", + "integrity": "sha512-/tBrSQ36vCleJkAOsy9kbNTgaxvGbyOamC30PRePTQe/o1MFwEKHQk4Cn7BNGaPtjp+PuUrByJehM1hgxfq4sw==", + "dev": true, + "license": "MIT" + }, "node_modules/@tanstack/query-core": { "version": "5.90.20", "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.90.20.tgz", @@ -11473,28 +11518,28 @@ "version": "1.0.12", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.12.tgz", "integrity": "sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/@tsconfig/node12": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/@tsconfig/node14": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/@tsconfig/node16": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/@tybys/wasm-util": { @@ -11932,7 +11977,7 @@ "version": "20.19.9", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.9.tgz", "integrity": "sha512-cuVNgarYWZqxRJDQHEB58GEONhOK79QVR/qYx4S7kcUObQvUwvFnYxJuuHUKm2aieN9X3yZB4LZsuYNU1Qphsw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "undici-types": "~6.21.0" @@ -13202,7 +13247,7 @@ "version": "8.16.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", - "dev": true, + "devOptional": true, "license": "MIT", "bin": { "acorn": "bin/acorn" @@ -13238,7 +13283,7 @@ "version": "8.3.5", "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.5.tgz", "integrity": "sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "acorn": "^8.11.0" @@ -13405,11 +13450,16 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "license": "MIT" + }, "node_modules/anymatch": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, "license": "ISC", "dependencies": { "normalize-path": "^3.0.0", @@ -13423,7 +13473,6 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, "license": "MIT", "engines": { "node": ">=8.6" @@ -13461,7 +13510,7 @@ "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/argparse": { @@ -13739,9 +13788,9 @@ } }, "node_modules/autoprefixer": { - "version": "10.4.27", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.27.tgz", - "integrity": "sha512-NP9APE+tO+LuJGn7/9+cohklunJsXWiaWEfV3si4Gi/XHDwVNgkwr1J3RQYFIvPy76GmJ9/bW8vyoU1LcxwKHA==", + "version": "10.4.13", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.13.tgz", + "integrity": "sha512-49vKpMqcZYsJjwotvt4+h/BCjJVnhGwcLpDt5xkcaOG3eLrG/HUYLagrihYsQ+qrIBgIzX1Rw7a6L8I/ZA1Atg==", "dev": true, "funding": [ { @@ -13751,18 +13800,15 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/autoprefixer" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" } ], "license": "MIT", "dependencies": { - "browserslist": "^4.28.1", - "caniuse-lite": "^1.0.30001774", - "fraction.js": "^5.3.4", - "picocolors": "^1.1.1", + "browserslist": "^4.21.4", + "caniuse-lite": "^1.0.30001426", + "fraction.js": "^4.2.0", + "normalize-range": "^0.1.2", + "picocolors": "^1.0.0", "postcss-value-parser": "^4.2.0" }, "bin": { @@ -14298,7 +14344,6 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -14409,7 +14454,6 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, "license": "MIT", "dependencies": { "fill-range": "^7.1.1" @@ -14727,6 +14771,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/camelcase-css": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, "node_modules/caniuse-api": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", @@ -16303,7 +16356,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/cron-parser": { @@ -16475,7 +16528,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", - "dev": true, "license": "MIT", "bin": { "cssesc": "bin/cssesc" @@ -17043,11 +17095,17 @@ "node": ">= 4.0.0" } }, + "node_modules/didyoumean": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", + "license": "Apache-2.0" + }, "node_modules/diff": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.4.tgz", "integrity": "sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==", - "dev": true, + "devOptional": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.3.1" @@ -17076,6 +17134,12 @@ "node": ">=8" } }, + "node_modules/dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", + "license": "MIT" + }, "node_modules/dns-packet": { "version": "5.6.1", "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", @@ -18616,7 +18680,6 @@ "version": "3.3.3", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", - "dev": true, "license": "MIT", "dependencies": { "@nodelib/fs.stat": "^2.0.2", @@ -18633,7 +18696,6 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, "license": "ISC", "dependencies": { "is-glob": "^4.0.1" @@ -18677,7 +18739,6 @@ "version": "1.20.1", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", - "dev": true, "license": "ISC", "dependencies": { "reusify": "^1.0.4" @@ -18710,7 +18771,6 @@ "version": "6.5.0", "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "dev": true, "license": "MIT", "engines": { "node": ">=12.0.0" @@ -18852,7 +18912,6 @@ "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" @@ -19335,16 +19394,16 @@ } }, "node_modules/fraction.js": { - "version": "5.3.4", - "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-5.3.4.tgz", - "integrity": "sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==", + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", + "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", "dev": true, "license": "MIT", "engines": { "node": "*" }, "funding": { - "type": "github", + "type": "patreon", "url": "https://github.com/sponsors/rawify" } }, @@ -19409,7 +19468,6 @@ "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, "hasInstallScript": true, "license": "MIT", "optional": true, @@ -19424,7 +19482,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" @@ -19655,7 +19712,6 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, "license": "ISC", "dependencies": { "is-glob": "^4.0.3" @@ -20001,7 +20057,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "dev": true, "license": "MIT", "dependencies": { "function-bind": "^1.1.2" @@ -20649,7 +20704,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, "license": "MIT", "dependencies": { "binary-extensions": "^2.0.0" @@ -20702,7 +20756,6 @@ "version": "2.16.1", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", - "dev": true, "license": "MIT", "dependencies": { "hasown": "^2.0.2" @@ -20769,7 +20822,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -20835,7 +20887,6 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" @@ -20949,7 +21000,6 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.12.0" @@ -24696,7 +24746,6 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", - "dev": true, "license": "MIT", "engines": { "node": ">=14" @@ -24948,7 +24997,7 @@ "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true, + "devOptional": true, "license": "ISC" }, "node_modules/makeerror": { @@ -25026,7 +25075,6 @@ "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, "license": "MIT", "engines": { "node": ">= 8" @@ -25046,7 +25094,6 @@ "version": "4.0.8", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "dev": true, "license": "MIT", "dependencies": { "braces": "^3.0.3", @@ -25060,7 +25107,6 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, "license": "MIT", "engines": { "node": ">=8.6" @@ -25232,6 +25278,17 @@ "multicast-dns": "cli.js" } }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, "node_modules/nanoid": { "version": "3.3.11", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", @@ -25724,6 +25781,15 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", "dev": true, "license": "MIT", "engines": { @@ -25883,7 +25949,6 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -26440,7 +26505,6 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true, "license": "MIT" }, "node_modules/path-scurry": { @@ -26513,7 +26577,7 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=12" @@ -26537,7 +26601,6 @@ "version": "4.0.7", "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", - "dev": true, "license": "MIT", "engines": { "node": ">= 6" @@ -26758,10 +26821,9 @@ } }, "node_modules/postcss": { - "version": "8.5.8", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz", - "integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==", - "dev": true, + "version": "8.4.38", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz", + "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==", "funding": [ { "type": "opencollective", @@ -26778,9 +26840,9 @@ ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.11", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" + "nanoid": "^3.3.7", + "picocolors": "^1.0.0", + "source-map-js": "^1.2.0" }, "engines": { "node": "^10 || ^12 || >=14" @@ -26909,6 +26971,66 @@ "postcss": "^8.0.0" } }, + "node_modules/postcss-js": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.1.0.tgz", + "integrity": "sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "camelcase-css": "^2.0.1" + }, + "engines": { + "node": "^12 || ^14 || >= 16" + }, + "peerDependencies": { + "postcss": "^8.4.21" + } + }, + "node_modules/postcss-load-config": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz", + "integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "lilconfig": "^3.0.0", + "yaml": "^2.3.4" + }, + "engines": { + "node": ">= 14" + }, + "peerDependencies": { + "postcss": ">=8.0.9", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "postcss": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, "node_modules/postcss-loader": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-6.2.1.tgz", @@ -27174,6 +27296,31 @@ "postcss": "^8.1.0" } }, + "node_modules/postcss-nested": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz", + "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^6.1.1" + }, + "engines": { + "node": ">=12.0" + }, + "peerDependencies": { + "postcss": "^8.2.14" + } + }, "node_modules/postcss-normalize-charset": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-6.0.2.tgz", @@ -27370,7 +27517,6 @@ "version": "6.1.2", "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", - "dev": true, "license": "MIT", "dependencies": { "cssesc": "^3.0.0", @@ -27417,7 +27563,6 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", - "dev": true, "license": "MIT" }, "node_modules/powershell-utils": { @@ -27652,7 +27797,6 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, "funding": [ { "type": "github", @@ -27875,7 +28019,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", - "dev": true, "license": "MIT", "dependencies": { "pify": "^2.3.0" @@ -27885,7 +28028,6 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -28065,7 +28207,6 @@ "version": "1.22.8", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", - "dev": true, "license": "MIT", "dependencies": { "is-core-module": "^2.13.0", @@ -28197,7 +28338,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", - "dev": true, "license": "MIT", "engines": { "iojs": ">=1.0.0", @@ -28522,7 +28662,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, "funding": [ { "type": "github", @@ -30312,6 +30451,43 @@ "postcss": "^8.4.31" } }, + "node_modules/sucrase": { + "version": "3.35.1", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.1.tgz", + "integrity": "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.2", + "commander": "^4.0.0", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "tinyglobby": "^0.2.11", + "ts-interface-checker": "^0.1.9" + }, + "bin": { + "sucrase": "bin/sucrase", + "sucrase-node": "bin/sucrase-node" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/sucrase/node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/sucrase/node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "license": "MIT" + }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -30329,7 +30505,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -30470,11 +30645,152 @@ } }, "node_modules/tailwindcss": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.2.1.tgz", - "integrity": "sha512-/tBrSQ36vCleJkAOsy9kbNTgaxvGbyOamC30PRePTQe/o1MFwEKHQk4Cn7BNGaPtjp+PuUrByJehM1hgxfq4sw==", + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.3.tgz", + "integrity": "sha512-U7sxQk/n397Bmx4JHbJx/iSOOv5G+II3f1kpLpY2QeUv5DcPdcTsYLlusZfq1NthHS1c1cZoyFmmkex1rzke0A==", + "license": "MIT", + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "arg": "^5.0.2", + "chokidar": "^3.5.3", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.3.0", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.21.0", + "lilconfig": "^2.1.0", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.0.0", + "postcss": "^8.4.23", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.1", + "postcss-nested": "^6.0.1", + "postcss-selector-parser": "^6.0.11", + "resolve": "^1.22.2", + "sucrase": "^3.32.0" + }, + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tailwindcss/node_modules/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", "license": "MIT" }, + "node_modules/tailwindcss/node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/tailwindcss/node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/tailwindcss/node_modules/jiti": { + "version": "1.21.7", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", + "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", + "license": "MIT", + "bin": { + "jiti": "bin/jiti.js" + } + }, + "node_modules/tailwindcss/node_modules/lilconfig": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", + "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/tailwindcss/node_modules/object-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/tailwindcss/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/tailwindcss/node_modules/postcss-import": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", + "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/tailwindcss/node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, "node_modules/tapable": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", @@ -30703,6 +31019,27 @@ "dev": true, "license": "MIT" }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "license": "MIT", + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, "node_modules/thingies": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/thingies/-/thingies-2.5.0.tgz", @@ -30754,7 +31091,6 @@ "version": "0.2.15", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", - "dev": true, "license": "MIT", "dependencies": { "fdir": "^6.5.0", @@ -30771,7 +31107,6 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", - "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -30811,7 +31146,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, "license": "MIT", "dependencies": { "is-number": "^7.0.0" @@ -30932,6 +31266,12 @@ "typescript": ">=4.8.4" } }, + "node_modules/ts-interface-checker": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", + "license": "Apache-2.0" + }, "node_modules/ts-jest": { "version": "29.4.6", "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.4.6.tgz", @@ -31033,7 +31373,7 @@ "version": "10.9.1", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@cspotcode/source-map-support": "^0.8.0", @@ -31349,7 +31689,7 @@ "version": "6.21.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/unicode-canonical-property-names-ecmascript": { @@ -31589,7 +31929,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true, "license": "MIT" }, "node_modules/utils-merge": { @@ -31615,7 +31954,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/v8-to-istanbul": { @@ -31738,6 +32077,35 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/vite/node_modules/postcss": { + "version": "8.5.8", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz", + "integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, "node_modules/vitest": { "version": "4.0.18", "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.0.18.tgz", @@ -32681,7 +33049,6 @@ "version": "2.8.2", "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz", "integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==", - "dev": true, "license": "ISC", "bin": { "yaml": "bin.mjs" @@ -32740,7 +33107,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=6" From 8b80a434a7354700134949e642d03a2feb9b7968 Mon Sep 17 00:00:00 2001 From: Filipe Frigini Date: Sat, 21 Mar 2026 14:15:39 -0300 Subject: [PATCH 04/19] feat(Admin): Add API client with TanStack Query hooks - Generate API types from OpenAPI spec (copied from Provider app) - Create admin hooks: useProviders, useAllowedCities, useCategories, useUsers - Add type definitions with Brazilian Portuguese labels - Update providers page to use real API with loading/error states - Add local .gitignore to track OpenAPI generated files --- src/Web/MeAjudaAi.Web.Admin-React/.gitignore | 2 + .../openapi-ts.config.ts | 10 + .../src/app/(admin)/providers/page.tsx | 148 +- .../src/hooks/admin/index.ts | 4 + .../src/hooks/admin/use-allowed-cities.ts | 107 + .../src/hooks/admin/use-categories.ts | 86 + .../src/hooks/admin/use-providers.ts | 143 + .../src/hooks/admin/use-users.ts | 65 + .../generated/@tanstack/react-query.gen.ts | 1754 +++++++++ .../src/lib/api/generated/client.gen.ts | 16 + .../lib/api/generated/client/client.gen.ts | 290 ++ .../src/lib/api/generated/client/index.ts | 25 + .../src/lib/api/generated/client/types.gen.ts | 214 ++ .../src/lib/api/generated/client/utils.gen.ts | 316 ++ .../src/lib/api/generated/core/auth.gen.ts | 41 + .../api/generated/core/bodySerializer.gen.ts | 82 + .../src/lib/api/generated/core/params.gen.ts | 169 + .../api/generated/core/pathSerializer.gen.ts | 171 + .../generated/core/queryKeySerializer.gen.ts | 117 + .../generated/core/serverSentEvents.gen.ts | 243 ++ .../src/lib/api/generated/core/types.gen.ts | 104 + .../src/lib/api/generated/core/utils.gen.ts | 140 + .../src/lib/api/generated/index.ts | 4 + .../src/lib/api/generated/sdk.gen.ts | 1015 +++++ .../src/lib/api/generated/types.gen.ts | 3311 +++++++++++++++++ .../src/lib/api/generated/zod.gen.ts | 1946 ++++++++++ .../src/lib/types.ts | 86 + 27 files changed, 10558 insertions(+), 51 deletions(-) create mode 100644 src/Web/MeAjudaAi.Web.Admin-React/.gitignore create mode 100644 src/Web/MeAjudaAi.Web.Admin-React/openapi-ts.config.ts create mode 100644 src/Web/MeAjudaAi.Web.Admin-React/src/hooks/admin/index.ts create mode 100644 src/Web/MeAjudaAi.Web.Admin-React/src/hooks/admin/use-allowed-cities.ts create mode 100644 src/Web/MeAjudaAi.Web.Admin-React/src/hooks/admin/use-categories.ts create mode 100644 src/Web/MeAjudaAi.Web.Admin-React/src/hooks/admin/use-providers.ts create mode 100644 src/Web/MeAjudaAi.Web.Admin-React/src/hooks/admin/use-users.ts create mode 100644 src/Web/MeAjudaAi.Web.Admin-React/src/lib/api/generated/@tanstack/react-query.gen.ts create mode 100644 src/Web/MeAjudaAi.Web.Admin-React/src/lib/api/generated/client.gen.ts create mode 100644 src/Web/MeAjudaAi.Web.Admin-React/src/lib/api/generated/client/client.gen.ts create mode 100644 src/Web/MeAjudaAi.Web.Admin-React/src/lib/api/generated/client/index.ts create mode 100644 src/Web/MeAjudaAi.Web.Admin-React/src/lib/api/generated/client/types.gen.ts create mode 100644 src/Web/MeAjudaAi.Web.Admin-React/src/lib/api/generated/client/utils.gen.ts create mode 100644 src/Web/MeAjudaAi.Web.Admin-React/src/lib/api/generated/core/auth.gen.ts create mode 100644 src/Web/MeAjudaAi.Web.Admin-React/src/lib/api/generated/core/bodySerializer.gen.ts create mode 100644 src/Web/MeAjudaAi.Web.Admin-React/src/lib/api/generated/core/params.gen.ts create mode 100644 src/Web/MeAjudaAi.Web.Admin-React/src/lib/api/generated/core/pathSerializer.gen.ts create mode 100644 src/Web/MeAjudaAi.Web.Admin-React/src/lib/api/generated/core/queryKeySerializer.gen.ts create mode 100644 src/Web/MeAjudaAi.Web.Admin-React/src/lib/api/generated/core/serverSentEvents.gen.ts create mode 100644 src/Web/MeAjudaAi.Web.Admin-React/src/lib/api/generated/core/types.gen.ts create mode 100644 src/Web/MeAjudaAi.Web.Admin-React/src/lib/api/generated/core/utils.gen.ts create mode 100644 src/Web/MeAjudaAi.Web.Admin-React/src/lib/api/generated/index.ts create mode 100644 src/Web/MeAjudaAi.Web.Admin-React/src/lib/api/generated/sdk.gen.ts create mode 100644 src/Web/MeAjudaAi.Web.Admin-React/src/lib/api/generated/types.gen.ts create mode 100644 src/Web/MeAjudaAi.Web.Admin-React/src/lib/api/generated/zod.gen.ts create mode 100644 src/Web/MeAjudaAi.Web.Admin-React/src/lib/types.ts diff --git a/src/Web/MeAjudaAi.Web.Admin-React/.gitignore b/src/Web/MeAjudaAi.Web.Admin-React/.gitignore new file mode 100644 index 000000000..dc4251dae --- /dev/null +++ b/src/Web/MeAjudaAi.Web.Admin-React/.gitignore @@ -0,0 +1,2 @@ +# Allow OpenAPI generated types +!src/lib/api/generated/ diff --git a/src/Web/MeAjudaAi.Web.Admin-React/openapi-ts.config.ts b/src/Web/MeAjudaAi.Web.Admin-React/openapi-ts.config.ts new file mode 100644 index 000000000..72e918200 --- /dev/null +++ b/src/Web/MeAjudaAi.Web.Admin-React/openapi-ts.config.ts @@ -0,0 +1,10 @@ +import { defineConfig } from '@hey-api/openapi-ts'; + +export default defineConfig({ + input: process.env.NEXT_PUBLIC_OPENAPI_SPEC_URL ?? 'http://localhost:7002/api-docs/v1/swagger.json', + output: './src/lib/api/generated', + plugins: [ + '@tanstack/react-query', + 'zod', + ], +}); diff --git a/src/Web/MeAjudaAi.Web.Admin-React/src/app/(admin)/providers/page.tsx b/src/Web/MeAjudaAi.Web.Admin-React/src/app/(admin)/providers/page.tsx index 4ba196577..df6711a62 100644 --- a/src/Web/MeAjudaAi.Web.Admin-React/src/app/(admin)/providers/page.tsx +++ b/src/Web/MeAjudaAi.Web.Admin-React/src/app/(admin)/providers/page.tsx @@ -1,32 +1,48 @@ "use client"; import { useState } from "react"; -import { Search, Plus, Pencil, Trash2, Eye, CheckCircle, XCircle } from "lucide-react"; +import { Search, Plus, Pencil, Trash2, Eye, CheckCircle, XCircle, Loader2 } from "lucide-react"; import { Card } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; import { Badge } from "@/components/ui/badge"; import { Input } from "@/components/ui/input"; +import { useProviders } from "@/hooks/admin"; +import { + providerTypeLabels, + verificationStatusLabels, + type ProviderDto, + type VerificationStatus, +} from "@/lib/types"; -const mockProviders = [ - { id: "1", name: "João Silva", email: "joao@email.com", phone: "(11) 99999-9999", type: "Pessoa Física", status: "Aprovado", city: "São Paulo" }, - { id: "2", name: "Maria Santos", email: "maria@email.com", phone: "(11) 88888-8888", type: "Pessoa Física", status: "Pendente", city: "Campinas" }, - { id: "3", name: "Tech Solutions Ltda", email: "contato@techsolutions.com", phone: "(11) 77777-7777", type: "Empresa", status: "Aprovado", city: "São Paulo" }, -]; - -const statusVariant = (status: string) => { +const getVerificationBadgeVariant = (status?: VerificationStatus) => { switch (status) { - case "Aprovado": return "success"; - case "Pendente": return "warning"; - case "Rejeitado": return "destructive"; - default: return "secondary"; + case 2: return "success" as const; + case 0: return "warning" as const; + case 3: + case 4: return "destructive" as const; + default: return "secondary" as const; } }; +const getProviderCity = (provider: ProviderDto): string => { + return provider.businessProfile?.primaryAddress?.city ?? "-"; +}; + +const getProviderPhone = (provider: ProviderDto): string => { + const phone = provider.businessProfile?.contactInfo?.phoneNumber; + return phone ?? "-"; +}; + export default function ProvidersPage() { const [search, setSearch] = useState(""); + const { data, isLoading, error } = useProviders(); + + const providers = data?.data ?? []; - const filteredProviders = mockProviders.filter( - (p) => p.name.toLowerCase().includes(search.toLowerCase()) || p.email.toLowerCase().includes(search.toLowerCase()) + const filteredProviders = providers.filter( + (p) => + (p.name?.toLowerCase() ?? "").includes(search.toLowerCase()) || + (p.businessProfile?.contactInfo?.email?.toLowerCase() ?? "").includes(search.toLowerCase()) ); return ( @@ -43,49 +59,79 @@ export default function ProvidersPage() {
- setSearch(e.target.value)} /> + setSearch(e.target.value)} + />
-
- - - - - - - - - - - - - - {filteredProviders.map((provider) => ( - - - - - - - - + {isLoading && ( +
+ +
+ )} + + {error && ( +
+ Erro ao carregar prestadores. Tente novamente. +
+ )} + + {!isLoading && !error && ( +
+
NomeEmailTelefoneTipoStatusCidadeAƧƵes
{provider.name}{provider.email}{provider.phone}{provider.type}{provider.status}{provider.city} -
- - - - - -
-
+ + + + + + + + + - ))} - -
NomeEmailTelefoneTipoStatusCidadeAƧƵes
-
- {filteredProviders.length === 0 &&
Nenhum prestador encontrado
} + + + {filteredProviders.map((provider) => ( + + {provider.name ?? "-"} + + {provider.businessProfile?.contactInfo?.email ?? "-"} + + {getProviderPhone(provider)} + + {providerTypeLabels[provider.type as keyof typeof providerTypeLabels] ?? "-"} + + + + {verificationStatusLabels[provider.verificationStatus as keyof typeof verificationStatusLabels] ?? "-"} + + + {getProviderCity(provider)} + +
+ + + + + +
+ + + ))} + + +
+ )} + + {!isLoading && !error && filteredProviders.length === 0 && ( +
Nenhum prestador encontrado
+ )}

); diff --git a/src/Web/MeAjudaAi.Web.Admin-React/src/hooks/admin/index.ts b/src/Web/MeAjudaAi.Web.Admin-React/src/hooks/admin/index.ts new file mode 100644 index 000000000..9dba5a2e9 --- /dev/null +++ b/src/Web/MeAjudaAi.Web.Admin-React/src/hooks/admin/index.ts @@ -0,0 +1,4 @@ +export * from "./use-providers"; +export * from "./use-allowed-cities"; +export * from "./use-categories"; +export * from "./use-users"; diff --git a/src/Web/MeAjudaAi.Web.Admin-React/src/hooks/admin/use-allowed-cities.ts b/src/Web/MeAjudaAi.Web.Admin-React/src/hooks/admin/use-allowed-cities.ts new file mode 100644 index 000000000..7016c947b --- /dev/null +++ b/src/Web/MeAjudaAi.Web.Admin-React/src/hooks/admin/use-allowed-cities.ts @@ -0,0 +1,107 @@ +"use client"; + +import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"; +import { + apiAllowedCitiesGet, + apiAllowedCitiesGet2, + apiAllowedCitiesPost, + apiAllowedCitiesPut, + apiAllowedCitiesPatch, + apiAllowedCitiesDelete, +} from "@/lib/api/generated"; +import type { + ApiAllowedCitiesGetData, + ApiAllowedCitiesGet2Data, + ApiAllowedCitiesPostData, + ApiAllowedCitiesPutData, + ApiAllowedCitiesPatchData, + ApiAllowedCitiesDeleteData, +} from "@/lib/api/generated"; + +export const allowedCitiesKeys = { + all: ["allowedCities"] as const, + lists: () => [...allowedCitiesKeys.all, "list"] as const, + list: (filters?: ApiAllowedCitiesGetData["query"]) => + [...allowedCitiesKeys.lists(), filters] as const, + details: () => [...allowedCitiesKeys.all, "detail"] as const, + detail: (id: string) => [...allowedCitiesKeys.details(), id] as const, +}; + +export function useAllowedCities(onlyActive?: boolean) { + return useQuery({ + queryKey: allowedCitiesKeys.list({ onlyActive }), + queryFn: () => apiAllowedCitiesGet({ query: { onlyActive } }), + select: (data) => data.data, + }); +} + +export function useAllowedCityById(id: string) { + return useQuery({ + queryKey: allowedCitiesKeys.detail(id), + queryFn: () => apiAllowedCitiesGet2({ path: { id } } as ApiAllowedCitiesGet2Data), + select: (data) => data.data, + enabled: !!id, + }); +} + +export function useCreateAllowedCity() { + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: (data: ApiAllowedCitiesPostData["body"]) => + apiAllowedCitiesPost({ body: data }), + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: allowedCitiesKeys.lists() }); + }, + }); +} + +export function useUpdateAllowedCity() { + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: ({ + id, + ...data + }: ApiAllowedCitiesPutData["path"] & { data: ApiAllowedCitiesPutData["body"] }) => + apiAllowedCitiesPut({ + path: { id }, + body: data.data as ApiAllowedCitiesPutData["body"], + }), + onSuccess: (_, variables) => { + queryClient.invalidateQueries({ queryKey: allowedCitiesKeys.detail(variables.id) }); + queryClient.invalidateQueries({ queryKey: allowedCitiesKeys.lists() }); + }, + }); +} + +export function usePatchAllowedCity() { + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: ({ + id, + ...data + }: ApiAllowedCitiesPatchData["path"] & { data: ApiAllowedCitiesPatchData["body"] }) => + apiAllowedCitiesPatch({ + path: { id }, + body: data.data as ApiAllowedCitiesPatchData["body"], + }), + onSuccess: (_, variables) => { + queryClient.invalidateQueries({ queryKey: allowedCitiesKeys.detail(variables.id) }); + queryClient.invalidateQueries({ queryKey: allowedCitiesKeys.lists() }); + }, + }); +} + +export function useDeleteAllowedCity() { + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: (id: string) => + apiAllowedCitiesDelete({ path: { id } } as ApiAllowedCitiesDeleteData), + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: allowedCitiesKeys.lists() }); + }, + }); +} diff --git a/src/Web/MeAjudaAi.Web.Admin-React/src/hooks/admin/use-categories.ts b/src/Web/MeAjudaAi.Web.Admin-React/src/hooks/admin/use-categories.ts new file mode 100644 index 000000000..6dcc77be1 --- /dev/null +++ b/src/Web/MeAjudaAi.Web.Admin-React/src/hooks/admin/use-categories.ts @@ -0,0 +1,86 @@ +"use client"; + +import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"; +import { + apiCategoriesGet, + apiCategoriesGet2, + apiCategoriesPost, + apiCategoriesPut, + apiCategoriesDelete, +} from "@/lib/api/generated"; +import type { + ApiCategoriesGetData, + ApiCategoriesGet2Data, + ApiCategoriesPostData, + ApiCategoriesPutData, + ApiCategoriesDeleteData, +} from "@/lib/api/generated"; + +export const categoryKeys = { + all: ["categories"] as const, + lists: () => [...categoryKeys.all, "list"] as const, + list: (filters?: ApiCategoriesGetData["query"]) => + [...categoryKeys.lists(), filters] as const, + details: () => [...categoryKeys.all, "detail"] as const, + detail: (id: string) => [...categoryKeys.details(), id] as const, +}; + +export function useCategories() { + return useQuery({ + queryKey: categoryKeys.lists(), + queryFn: () => apiCategoriesGet(), + select: (data) => data.data, + }); +} + +export function useCategoryById(id: string) { + return useQuery({ + queryKey: categoryKeys.detail(id), + queryFn: () => apiCategoriesGet2({ path: { id } } as ApiCategoriesGet2Data), + select: (data) => data.data, + enabled: !!id, + }); +} + +export function useCreateCategory() { + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: (data: ApiCategoriesPostData["body"]) => + apiCategoriesPost({ body: data }), + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: categoryKeys.lists() }); + }, + }); +} + +export function useUpdateCategory() { + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: ({ + id, + ...data + }: ApiCategoriesPutData["path"] & { data: ApiCategoriesPutData["body"] }) => + apiCategoriesPut({ + path: { id }, + body: data.data as ApiCategoriesPutData["body"], + }), + onSuccess: (_, variables) => { + queryClient.invalidateQueries({ queryKey: categoryKeys.detail(variables.id) }); + queryClient.invalidateQueries({ queryKey: categoryKeys.lists() }); + }, + }); +} + +export function useDeleteCategory() { + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: (id: string) => + apiCategoriesDelete({ path: { id } } as ApiCategoriesDeleteData), + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: categoryKeys.lists() }); + }, + }); +} diff --git a/src/Web/MeAjudaAi.Web.Admin-React/src/hooks/admin/use-providers.ts b/src/Web/MeAjudaAi.Web.Admin-React/src/hooks/admin/use-providers.ts new file mode 100644 index 000000000..db8308fbb --- /dev/null +++ b/src/Web/MeAjudaAi.Web.Admin-React/src/hooks/admin/use-providers.ts @@ -0,0 +1,143 @@ +"use client"; + +import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"; +import { + apiProvidersGet, + apiProviderGet, + apiProvidersPost, + apiProvidersPut, + apiProvidersDelete, + apiProvidersGet2, + apiProvidersGet3, + apiActivatePost, + apiDeactivatePost, +} from "@/lib/api/generated"; +import type { + ApiProvidersGetData, + ApiProvidersGet2Data, + ApiProvidersGet3Data, + ApiProviderGetData, + ApiProvidersPostData, + ApiProvidersPutData, + ApiProvidersDeleteData, + ApiActivatePostData, + ApiDeactivatePostData, +} from "@/lib/api/generated"; +import type { ApiProvidersGet2Error, ApiProvidersGet4Error } from "@/lib/api/generated"; + +export const providerKeys = { + all: ["providers"] as const, + lists: () => [...providerKeys.all, "list"] as const, + list: (filters: ApiProvidersGetData["query"]) => + [...providerKeys.lists(), filters] as const, + details: () => [...providerKeys.all, "detail"] as const, + detail: (id: string) => [...providerKeys.details(), id] as const, + byStatus: (status: string) => + [...providerKeys.all, "byStatus", status] as const, + byType: (type: string) => [...providerKeys.all, "byType", type] as const, +}; + +export function useProviders(filters?: ApiProvidersGetData["query"]) { + return useQuery({ + queryKey: providerKeys.list(filters), + queryFn: () => apiProvidersGet({ query: filters }), + select: (data) => data.data, + }); +} + +export function useProviderById(id: string) { + return useQuery({ + queryKey: providerKeys.detail(id), + queryFn: () => apiProviderGet({ path: { id } }), + select: (data) => data.data, + enabled: !!id, + }); +} + +export function useProvidersByStatus(status: string) { + return useQuery({ + queryKey: providerKeys.byStatus(status), + queryFn: () => + apiProvidersGet2({ + query: { verificationStatus: status }, + } as ApiProvidersGet2Data), + select: (data) => data.data, + enabled: !!status, + }); +} + +export function useProvidersByType(type: string) { + return useQuery({ + queryKey: providerKeys.byType(type), + queryFn: () => + apiProvidersGet3({ + query: { type }, + } as ApiProvidersGet3Data), + select: (data) => data.data, + enabled: !!type, + }); +} + +export function useCreateProvider() { + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: (data: ApiProvidersPostData["body"]) => + apiProvidersPost({ body: data }), + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: providerKeys.lists() }); + }, + }); +} + +export function useUpdateProvider() { + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: ({ + id, + ...data + }: ApiProvidersPutData["path"] & { data: ApiProvidersPutData["body"] }) => + apiProvidersPut({ path: { id }, body: data.data as ApiProvidersPutData["body"] }), + onSuccess: (_, variables) => { + queryClient.invalidateQueries({ queryKey: providerKeys.detail(variables.id) }); + queryClient.invalidateQueries({ queryKey: providerKeys.lists() }); + }, + }); +} + +export function useDeleteProvider() { + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: (id: string) => + apiProvidersDelete({ path: { id } } as ApiProvidersDeleteData), + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: providerKeys.lists() }); + }, + }); +} + +export function useActivateProvider() { + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: (id: string) => + apiActivatePost({ path: { id } } as ApiActivatePostData), + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: providerKeys.lists() }); + }, + }); +} + +export function useDeactivateProvider() { + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: (id: string) => + apiDeactivatePost({ path: { id } } as ApiDeactivatePostData), + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: providerKeys.lists() }); + }, + }); +} diff --git a/src/Web/MeAjudaAi.Web.Admin-React/src/hooks/admin/use-users.ts b/src/Web/MeAjudaAi.Web.Admin-React/src/hooks/admin/use-users.ts new file mode 100644 index 000000000..cf73f9393 --- /dev/null +++ b/src/Web/MeAjudaAi.Web.Admin-React/src/hooks/admin/use-users.ts @@ -0,0 +1,65 @@ +"use client"; + +import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"; +import { + apiUsersGet, + apiUsersGet2, + apiUsersPost, + apiUsersDelete, +} from "@/lib/api/generated"; +import type { + ApiUsersGetData, + ApiUsersGet2Data, + ApiUsersPostData, + ApiUsersDeleteData, +} from "@/lib/api/generated"; + +export const userKeys = { + all: ["users"] as const, + lists: () => [...userKeys.all, "list"] as const, + list: (filters?: ApiUsersGetData["query"]) => + [...userKeys.lists(), filters] as const, + details: () => [...userKeys.all, "detail"] as const, + detail: (id: string) => [...userKeys.details(), id] as const, +}; + +export function useUsers(filters?: ApiUsersGetData["query"]) { + return useQuery({ + queryKey: userKeys.list(filters), + queryFn: () => apiUsersGet({ query: filters }), + select: (data) => data.data, + }); +} + +export function useUserById(id: string) { + return useQuery({ + queryKey: userKeys.detail(id), + queryFn: () => apiUsersGet2({ path: { id } } as ApiUsersGet2Data), + select: (data) => data.data, + enabled: !!id, + }); +} + +export function useCreateUser() { + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: (data: ApiUsersPostData["body"]) => + apiUsersPost({ body: data }), + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: userKeys.lists() }); + }, + }); +} + +export function useDeleteUser() { + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: (id: string) => + apiUsersDelete({ path: { id } } as ApiUsersDeleteData), + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: userKeys.lists() }); + }, + }); +} diff --git a/src/Web/MeAjudaAi.Web.Admin-React/src/lib/api/generated/@tanstack/react-query.gen.ts b/src/Web/MeAjudaAi.Web.Admin-React/src/lib/api/generated/@tanstack/react-query.gen.ts new file mode 100644 index 000000000..0fcb3b031 --- /dev/null +++ b/src/Web/MeAjudaAi.Web.Admin-React/src/lib/api/generated/@tanstack/react-query.gen.ts @@ -0,0 +1,1754 @@ +// This file is auto-generated by @hey-api/openapi-ts + +import { type DefaultError, type InfiniteData, infiniteQueryOptions, queryOptions, type UseMutationOptions } from '@tanstack/react-query'; + +import { client } from '../client.gen'; +import { apiActivatePost, apiActivatePost2, apiActivatePost3, apiAllowedCitiesDelete, apiAllowedCitiesGet, apiAllowedCitiesGet2, apiAllowedCitiesPatch, apiAllowedCitiesPost, apiAllowedCitiesPut, apiBecomePost, apiByCityGet, apiByEmailGet, apiByStateGet, apiByTypeGet, apiByUserGet, apiCategoriesDelete, apiCategoriesGet, apiCategoriesGet2, apiCategoriesPost, apiCategoriesPut, apiCategoryGet, apiChangeCategoryPost, apiClientGet, apiCspReportPost, apiDeactivatePost, apiDeactivatePost2, apiDeactivatePost3, apiDocumentsDelete, apiDocumentsPost, apiDocumentsPost2, apiMeGet, apiMePut, apiProfilePut, apiProviderGet, apiProvidersDelete, apiProvidersGet, apiProvidersGet2, apiProvidersGet3, apiProvidersGet4, apiProvidersPost, apiProvidersPut, apiPublicGet, apiRegisterPost, apiRegisterPost2, apiRequestVerificationPost, apiRequireBasicInfoCorrectionPost, apiSearchGet, apiServicesDelete, apiServicesDelete2, apiServicesGet, apiServicesGet2, apiServicesPost, apiServicesPost2, apiServicesPut, apiStatusGet, apiStatusGet2, apiUploadPost, apiUsersDelete, apiUsersGet, apiUsersGet2, apiUsersPost, apiValidatePost, apiVerificationStatusGet, apiVerificationStatusPut, apiVerifyPost, type Options } from '../sdk.gen'; +import type { ApiActivatePost2Data, ApiActivatePost2Response, ApiActivatePost3Data, ApiActivatePost3Response, ApiActivatePostData, ApiActivatePostResponse, ApiAllowedCitiesDeleteData, ApiAllowedCitiesDeleteResponse, ApiAllowedCitiesGet2Data, ApiAllowedCitiesGet2Response, ApiAllowedCitiesGetData, ApiAllowedCitiesGetResponse, ApiAllowedCitiesPatchData, ApiAllowedCitiesPatchError, ApiAllowedCitiesPatchResponse, ApiAllowedCitiesPostData, ApiAllowedCitiesPostError, ApiAllowedCitiesPostResponse, ApiAllowedCitiesPutData, ApiAllowedCitiesPutResponse, ApiBecomePostData, ApiBecomePostError, ApiBecomePostResponse, ApiByCityGetData, ApiByCityGetResponse, ApiByEmailGetData, ApiByEmailGetResponse, ApiByStateGetData, ApiByStateGetResponse, ApiByTypeGetData, ApiByTypeGetResponse, ApiByUserGetData, ApiByUserGetResponse, ApiCategoriesDeleteData, ApiCategoriesDeleteResponse, ApiCategoriesGet2Data, ApiCategoriesGet2Response, ApiCategoriesGetData, ApiCategoriesGetResponse, ApiCategoriesPostData, ApiCategoriesPostResponse, ApiCategoriesPutData, ApiCategoriesPutResponse, ApiCategoryGetData, ApiCategoryGetResponse, ApiChangeCategoryPostData, ApiChangeCategoryPostResponse, ApiClientGetData, ApiClientGetResponse, ApiCspReportPostData, ApiDeactivatePost2Data, ApiDeactivatePost2Response, ApiDeactivatePost3Data, ApiDeactivatePost3Response, ApiDeactivatePostData, ApiDeactivatePostResponse, ApiDocumentsDeleteData, ApiDocumentsDeleteResponse, ApiDocumentsPost2Data, ApiDocumentsPost2Response, ApiDocumentsPostData, ApiDocumentsPostResponse, ApiMeGetData, ApiMeGetResponse, ApiMePutData, ApiMePutResponse, ApiProfilePutData, ApiProfilePutResponse, ApiProviderGetData, ApiProviderGetResponse, ApiProvidersDeleteData, ApiProvidersDeleteResponse, ApiProvidersGet2Data, ApiProvidersGet2Error, ApiProvidersGet2Response, ApiProvidersGet3Data, ApiProvidersGet3Response, ApiProvidersGet4Data, ApiProvidersGet4Error, ApiProvidersGet4Response, ApiProvidersGetData, ApiProvidersPostData, ApiProvidersPostResponse, ApiProvidersPutData, ApiProvidersPutResponse, ApiPublicGetData, ApiPublicGetResponse, ApiRegisterPost2Data, ApiRegisterPostData, ApiRegisterPostResponse, ApiRequestVerificationPostData, ApiRequestVerificationPostError, ApiRequireBasicInfoCorrectionPostData, ApiSearchGetData, ApiSearchGetResponse, ApiServicesDelete2Data, ApiServicesDelete2Response, ApiServicesDeleteData, ApiServicesDeleteResponse, ApiServicesGet2Data, ApiServicesGet2Response, ApiServicesGetData, ApiServicesGetResponse, ApiServicesPost2Data, ApiServicesPost2Response, ApiServicesPostData, ApiServicesPostResponse, ApiServicesPutData, ApiServicesPutResponse, ApiStatusGet2Data, ApiStatusGet2Response, ApiStatusGetData, ApiStatusGetResponse, ApiUploadPostData, ApiUploadPostResponse, ApiUsersDeleteData, ApiUsersDeleteResponse, ApiUsersGet2Data, ApiUsersGet2Response, ApiUsersGetData, ApiUsersGetError, ApiUsersGetResponse, ApiUsersPostData, ApiUsersPostResponse, ApiValidatePostData, ApiValidatePostResponse, ApiVerificationStatusGetData, ApiVerificationStatusGetError, ApiVerificationStatusGetResponse, ApiVerificationStatusPutData, ApiVerificationStatusPutResponse, ApiVerifyPostData } from '../types.gen'; + +export type QueryKey = [ + Pick & { + _id: string; + _infinite?: boolean; + tags?: ReadonlyArray; + } +]; + +const createQueryKey = (id: string, options?: TOptions, infinite?: boolean, tags?: ReadonlyArray): [ + QueryKey[0] +] => { + const params: QueryKey[0] = { _id: id, baseUrl: options?.baseUrl || (options?.client ?? client).getConfig().baseUrl } as QueryKey[0]; + if (infinite) { + params._infinite = infinite; + } + if (tags) { + params.tags = tags; + } + if (options?.body) { + params.body = options.body; + } + if (options?.headers) { + params.headers = options.headers; + } + if (options?.path) { + params.path = options.path; + } + if (options?.query) { + params.query = options.query; + } + return [params]; +}; + +export const apiAllowedCitiesGetQueryKey = (options?: Options) => createQueryKey('apiAllowedCitiesGet', options); + +/** + * Listar todas as cidades permitidas + * + * Recupera todas as cidades permitidas (opcionalmente apenas as ativas) + */ +export const apiAllowedCitiesGetOptions = (options?: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await apiAllowedCitiesGet({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: apiAllowedCitiesGetQueryKey(options) +}); + +/** + * Criar nova cidade permitida + * + * Cria uma nova cidade permitida para operaƧƵes de prestadores (apenas Admin) + */ +export const apiAllowedCitiesPostMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await apiAllowedCitiesPost({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +/** + * Deletar cidade permitida + * + * Deleta uma cidade permitida + */ +export const apiAllowedCitiesDeleteMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await apiAllowedCitiesDelete({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +export const apiAllowedCitiesGet2QueryKey = (options: Options) => createQueryKey('apiAllowedCitiesGet2', options); + +/** + * Buscar cidade permitida por ID + * + * Recupera uma cidade permitida especĆ­fica pelo seu ID + */ +export const apiAllowedCitiesGet2Options = (options: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await apiAllowedCitiesGet2({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: apiAllowedCitiesGet2QueryKey(options) +}); + +/** + * Atualizar parcialmente cidade permitida + * + * Atualiza campos especĆ­ficos de uma cidade permitida (Raio, Ativo) + */ +export const apiAllowedCitiesPatchMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await apiAllowedCitiesPatch({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +/** + * Atualizar cidade permitida + * + * Atualiza uma cidade permitida existente + */ +export const apiAllowedCitiesPutMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await apiAllowedCitiesPut({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +export const apiProvidersGetQueryKey = (options?: Options) => createQueryKey('apiProvidersGet', options); + +/** + * Lista os provedores de identidade social disponĆ­veis. + */ +export const apiProvidersGetOptions = (options?: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await apiProvidersGet({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: apiProvidersGetQueryKey(options) +}); + +export const apiClientGetQueryKey = (options?: Options) => createQueryKey('apiClientGet', options); + +/** + * Retorna a configuração do cliente. + * Apenas informaƧƵes nĆ£o-sensĆ­veis sĆ£o expostas. + * + * Retorna configuraƧƵes nĆ£o-sensĆ­veis necessĆ”rias para o frontend (Keycloak, URLs, feature flags) + */ +export const apiClientGetOptions = (options?: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await apiClientGet({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: apiClientGetQueryKey(options) +}); + +/** + * Gerar URL de upload com SAS token + * + * Gera uma URL de upload com SAS token para envio direto ao Azure Blob Storage. + * + * **Fluxo:** + * 1. Valida informaƧƵes do documento + * 2. Gera SAS token com 1 hora de validade + * 3. Cria registro de documento no banco com status Uploaded + * 4. Retorna URL de upload (com blob name e data de expiração) + * + * **Tipos de documentos suportados:** + * - IdentityDocument: RG, CNH, CPF + * - ProofOfResidence: Comprovante de residĆŖncia + * - CriminalRecord: CertidĆ£o de antecedentes + * - Other: Outros documentos + */ +export const apiUploadPostMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await apiUploadPost({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +export const apiStatusGetQueryKey = (options: Options) => createQueryKey('apiStatusGet', options); + +/** + * Consultar status de documento + * + * Retorna informaƧƵes detalhadas sobre um documento especĆ­fico. + * + * **InformaƧƵes retornadas:** + * - Status atual (Uploaded, PendingVerification, Verified, Rejected, Failed) + * - Datas de upload e verificação + * - Motivo de rejeição (se aplicĆ”vel) + * - Dados extraĆ­dos por OCR (se disponĆ­vel) + * - URLs de acesso ao documento + */ +export const apiStatusGetOptions = (options: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await apiStatusGet({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: apiStatusGetQueryKey(options) +}); + +export const apiProviderGetQueryKey = (options: Options) => createQueryKey('apiProviderGet', options); + +/** + * Listar documentos de um prestador + * + * Retorna todos os documentos associados a um prestador especĆ­fico. + * + * **Casos de uso:** + * - Visualizar todos os documentos enviados + * - Verificar status de verificação de documentos + * - Acompanhar progresso de validação de cadastro + */ +export const apiProviderGetOptions = (options: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await apiProviderGet({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: apiProviderGetQueryKey(options) +}); + +/** + * Solicitar verificação manual + * + * Solicita verificação manual de um documento quando OCR falha ou precisa validação adicional. + * + * **Quando usar:** + * - OCR nĆ£o conseguiu extrair dados do documento + * - Documento foi rejeitado automaticamente mas precisa revisĆ£o + * - Necessidade de validação humana adicional + * + * **Resultado:** + * - Documento entra em fila de verificação manual + * - Status alterado para PendingVerification + * - Administrador serĆ” notificado para anĆ”lise + */ +export const apiRequestVerificationPostMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await apiRequestVerificationPost({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +/** + * Aprovar ou rejeitar documento + * + * Aprova ou rejeita um documento após verificação manual. + * + * **Aprovar documento:** + * ```json + * { + * "IsVerified": true, + * "VerificationNotes": "Documento vĆ”lido e legĆ­vel" + * } + * ``` + * + * **Rejeitar documento:** + * ```json + * { + * "IsVerified": false, + * "VerificationNotes": "Documento ilegĆ­vel ou invĆ”lido" + * } + * ``` + * + * **Requisitos:** + * - Documento deve estar em status PendingVerification + * - Apenas administradores podem executar esta ação + */ +export const apiVerifyPostMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await apiVerifyPost({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +export const apiSearchGetQueryKey = (options: Options) => createQueryKey('apiSearchGet', options); + +/** + * Busca cidades/endereƧos para cadastro + * + * Retorna candidatos de localização baseados na query + */ +export const apiSearchGetOptions = (options: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await apiSearchGet({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: apiSearchGetQueryKey(options) +}); + +export const apiProvidersGet2QueryKey = (options?: Options) => createQueryKey('apiProvidersGet2', options); + +/** + * Consultar prestadores paginados + * + * Recupera uma lista paginada de prestadores de serviƧos do sistema com suporte a filtros de busca. + * + * **CaracterĆ­sticas:** + * - šŸ” Busca por nome, tipo de serviƧo e status de verificação + * - šŸ“„ Paginação otimizada com metadados + * - ⚔ Cache automĆ”tico para consultas frequentes + * - šŸ”’ Controle de acesso baseado em papĆ©is + * - šŸŒ Restrição geogrĆ”fica (piloto em cidades especĆ­ficas) + * + * **Restrição geogrĆ”fica (HTTP 451):** + * + * Este endpoint estĆ” sujeito a restriƧƵes geogrĆ”ficas durante a fase piloto. + * O acesso Ć© permitido apenas para usuĆ”rios nas seguintes cidades: + * + * - **MuriaĆ©** (MG) - IBGE: 3143906 + * - **Itaperuna** (RJ) - IBGE: 3302205 + * - **Linhares** (ES) - IBGE: 3203205 + * + * A localização Ć© determinada atravĆ©s dos headers HTTP: + * - `X-User-City`: Nome da cidade + * - `X-User-State`: Sigla do estado (UF) + * - `X-User-Location`: Combinação "cidade|estado" + * + * Se o acesso for bloqueado, vocĆŖ receberĆ” HTTP 451 com detalhes: + * - Sua localização detectada + * - Lista de cidades permitidas + * - Códigos IBGE para validação + * + * **ParĆ¢metros de busca:** + * - `name`: Termo para filtrar prestadores por nome + * - `type`: Filtro por tipo de serviƧo (ID numĆ©rico) + * - `verificationStatus`: Status de verificação (ID numĆ©rico) + * - `pageNumber`: NĆŗmero da pĆ”gina (padrĆ£o: 1) + * - `pageSize`: Tamanho da pĆ”gina (padrĆ£o: 10, mĆ”ximo: 100) + * + * **Exemplos de uso:** + * - Buscar prestadores: `?name=joĆ£o` + * - Por tipo: `?type=1` + * - Por status: `?verificationStatus=2` + * - Paginação: `?pageNumber=2&pageSize=20` + * - Combinado: `?name=mĆ©dico&type=1&pageNumber=1&pageSize=10` + */ +export const apiProvidersGet2Options = (options?: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await apiProvidersGet2({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: apiProvidersGet2QueryKey(options) +}); + +/** + * Processa requisição de criação de prestador de forma assĆ­ncrona. + * + * Fluxo de execução: + * 1. Converte request em comando CQRS + * 2. Envia comando atravĆ©s do dispatcher + * 3. Processa resultado e retorna resposta HTTP apropriada + * 4. Inclui localização do recurso criado no header + */ +export const apiProvidersPostMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await apiProvidersPost({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +/** + * Processa requisição de exclusĆ£o de prestador de forma assĆ­ncrona. + * + * Fluxo de execução: + * 1. Valida ID do prestador e autorização administrativa + * 2. Cria comando usando mapper ToDeleteCommand + * 3. Envia comando atravĆ©s do dispatcher + * 4. Processa resultado e retorna status apropriado + * 5. Registra evento de auditoria (futuro) + */ +export const apiProvidersDeleteMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await apiProvidersDelete({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +export const apiProvidersGet3QueryKey = (options: Options) => createQueryKey('apiProvidersGet3', options); + +/** + * Implementa a lógica de consulta de prestador por ID. + * + * Processo da consulta: + * 1. Valida ID do prestador no formato GUID + * 2. Cria query usando mapper ToQuery + * 3. Envia query atravĆ©s do dispatcher CQRS + * 4. Retorna resposta HTTP com dados do prestador ou NotFound + */ +export const apiProvidersGet3Options = (options: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await apiProvidersGet3({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: apiProvidersGet3QueryKey(options) +}); + +/** + * Processa requisição de atualização de perfil de forma assĆ­ncrona. + * + * Fluxo de execução: + * 1. Valida ID do prestador e autorização + * 2. Converte request em comando CQRS + * 3. Envia comando atravĆ©s do dispatcher + * 4. Processa resultado e retorna resposta HTTP apropriada + */ +export const apiProvidersPutMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await apiProvidersPut({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +export const apiPublicGetQueryKey = (options: Options) => createQueryKey('apiPublicGet', options); + +/** + * Consultar perfil pĆŗblico do prestador + * + * Recupera dados pĆŗblicos e seguros de um prestador para exibição no site. + * NĆ£o requer autenticação. Aceita ID (GUID) ou slug amigĆ”vel (ex.: "joao-silva-a1b2c3d4"). + * + * **Dados Retornados:** + * - InformaƧƵes bĆ”sicas (Nome, Fantasia, Descrição) + * - Localização aproximada (Cidade/Estado) + * - Avaliação mĆ©dia e contagem de reviews + * - Lista de serviƧos oferecidos (Nota: esta lista serĆ” vazia se a configuração PublicProfilePrivacy do provedor estiver ativa e o solicitante for anĆ“nimo) + * + * **Dados Ocultados (Privacidade):** + * - Documentos (CPF/CNPJ) + * - EndereƧo completo (Rua/NĆŗmero) + * - Dados de auditoria interna + */ +export const apiPublicGetOptions = (options: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await apiPublicGet({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: apiPublicGetQueryKey(options) +}); + +/** + * Tornar-se prestador (usuĆ”rio jĆ” autenticado) + * + * Transforma o usuĆ”rio autenticado em um prestador de serviƧos. Requer token de usuĆ”rio. + */ +export const apiBecomePostMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await apiBecomePost({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +export const apiByUserGetQueryKey = (options: Options) => createQueryKey('apiByUserGet', options); + +/** + * Implementa a lógica de consulta de prestador por ID do usuĆ”rio. + * + * Processo da consulta: + * 1. Valida ID do usuĆ”rio no formato GUID + * 2. Cria query usando mapper ToUserQuery + * 3. Envia query atravĆ©s do dispatcher CQRS + * 4. Retorna resposta HTTP com dados do prestador ou NotFound + */ +export const apiByUserGetOptions = (options: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await apiByUserGet({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: apiByUserGetQueryKey(options) +}); + +export const apiByCityGetQueryKey = (options: Options) => createQueryKey('apiByCityGet', options); + +/** + * Implementa a lógica de consulta de prestadores por cidade. + * + * Processo da consulta: + * 1. Valida parĆ¢metro de cidade + * 2. Cria query usando mapper ToCityQuery + * 3. Envia query atravĆ©s do dispatcher CQRS + * 4. Retorna resposta HTTP com lista de prestadores + */ +export const apiByCityGetOptions = (options: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await apiByCityGet({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: apiByCityGetQueryKey(options) +}); + +export const apiByStateGetQueryKey = (options: Options) => createQueryKey('apiByStateGet', options); + +/** + * Implementa a lógica de consulta de prestadores por estado. + * + * Processo da consulta: + * 1. Valida parĆ¢metro de estado + * 2. Cria query usando mapper ToStateQuery + * 3. Envia query atravĆ©s do dispatcher CQRS + * 4. Retorna resposta HTTP com lista de prestadores + */ +export const apiByStateGetOptions = (options: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await apiByStateGet({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: apiByStateGetQueryKey(options) +}); + +export const apiByTypeGetQueryKey = (options: Options) => createQueryKey('apiByTypeGet', options); + +/** + * Implementa a lógica de consulta de prestadores por tipo. + * + * Processo da consulta: + * 1. Valida enum de tipo do prestador + * 2. Cria query usando mapper ToTypeQuery + * 3. Envia query atravĆ©s do dispatcher CQRS + * 4. Retorna resposta HTTP com lista de prestadores + */ +export const apiByTypeGetOptions = (options: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await apiByTypeGet({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: apiByTypeGetQueryKey(options) +}); + +export const apiVerificationStatusGetQueryKey = (options: Options) => createQueryKey('apiVerificationStatusGet', options); + +/** + * Implementa a lógica de consulta de prestadores por status de verificação. + * + * Processo da consulta: + * 1. Valida enum de status de verificação + * 2. Cria query usando mapper ToVerificationStatusQuery + * 3. Envia query atravĆ©s do dispatcher CQRS + * 4. Retorna resposta HTTP com lista de prestadores + */ +export const apiVerificationStatusGetOptions = (options: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await apiVerificationStatusGet({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: apiVerificationStatusGetQueryKey(options) +}); + +/** + * Processa requisição de adição de documento de forma assĆ­ncrona. + * + * Fluxo de execução: + * 1. Valida ID do prestador e autorização + * 2. Converte request em comando CQRS + * 3. Envia comando atravĆ©s do dispatcher + * 4. Processa resultado e retorna prestador atualizado + */ +export const apiDocumentsPostMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await apiDocumentsPost({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +/** + * Processa requisição de remoção de documento de forma assĆ­ncrona. + * + * Fluxo de execução: + * 1. Valida ID do prestador e autorização + * 2. Cria comando usando mapper ToRemoveDocumentCommand + * 3. Envia comando atravĆ©s do dispatcher + * 4. Processa resultado e retorna prestador atualizado + */ +export const apiDocumentsDeleteMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await apiDocumentsDelete({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +/** + * Processa requisição de atualização de status de forma assĆ­ncrona. + * + * Fluxo de execução: + * 1. Valida ID do prestador e autorização administrativa + * 2. Converte request em comando CQRS + * 3. Envia comando atravĆ©s do dispatcher + * 4. Processa resultado e retorna prestador atualizado + * 5. Registra evento de auditoria (futuro) + */ +export const apiVerificationStatusPutMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await apiVerificationStatusPut({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +/** + * Processa requisição de solicitação de correção de forma assĆ­ncrona. + * + * Fluxo de execução: + * 1. Valida ID do prestador e autorização + * 2. Extrai identidade do usuĆ”rio autenticado do contexto HTTP + * 3. Converte request em comando CQRS com identidade verificada + * 4. Envia comando atravĆ©s do dispatcher + * 5. Processa resultado e retorna confirmação + * 6. Emite evento de domĆ­nio para notificação + */ +export const apiRequireBasicInfoCorrectionPostMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await apiRequireBasicInfoCorrectionPost({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +export const apiMeGetQueryKey = (options?: Options) => createQueryKey('apiMeGet', options); + +export const apiMeGetOptions = (options?: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await apiMeGet({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: apiMeGetQueryKey(options) +}); + +export const apiMePutMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await apiMePut({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +/** + * Upload de documento pelo próprio prestador + * + * Permite que o prestador adicione documentos ao seu próprio perfil. + */ +export const apiDocumentsPost2Mutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await apiDocumentsPost2({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +export const apiStatusGet2QueryKey = (options?: Options) => createQueryKey('apiStatusGet2', options); + +/** + * Status de aprovação do prestador + * + * Retorna o status atual de aprovação e tier do prestador autenticado. + */ +export const apiStatusGet2Options = (options?: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await apiStatusGet2({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: apiStatusGet2QueryKey(options) +}); + +export const apiActivatePostMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await apiActivatePost({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +export const apiDeactivatePostMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await apiDeactivatePost({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +/** + * Auto-registro de prestador de serviƧos + * + * Inicia o cadastro de um prestador. Cria usuĆ”rio no Keycloak com role 'provider-standard' e a entidade Provider com Tier=Standard. Endpoint pĆŗblico, sem autenticação. + */ +export const apiRegisterPostMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await apiRegisterPost({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +/** + * Processa requisição de remoção de serviƧo do provider. + * + * ### Remove um serviƧo do catĆ”logo do provider + * + * **Funcionalidades:** + * - āœ… Remove associação entre provider e serviƧo + * - āœ… Emite evento de domĆ­nio ProviderServiceRemovedDomainEvent + * - āœ… Valida que o provider oferece o serviƧo antes de remover + * + * **Campos obrigatórios:** + * - providerId: ID do provider (UUID) + * - serviceId: ID do serviƧo do catĆ”logo (UUID) + * + * **ValidaƧƵes:** + * - Provider deve existir + * - Provider deve oferecer o serviƧo + * - Provider nĆ£o pode estar deletado + */ +export const apiServicesDeleteMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await apiServicesDelete({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +/** + * Processa requisição de adição de serviƧo ao provider. + * + * ### Adiciona um serviƧo do catĆ”logo ao provider + * + * **Funcionalidades:** + * - āœ… Valida existĆŖncia e status do serviƧo via IServiceCatalogsModuleApi + * - āœ… Verifica se o serviƧo estĆ” ativo + * - āœ… Previne duplicação de serviƧos + * - āœ… Emite evento de domĆ­nio ProviderServiceAddedDomainEvent + * + * **Campos obrigatórios:** + * - providerId: ID do provider (UUID) + * - serviceId: ID do serviƧo do catĆ”logo (UUID) + * + * **ValidaƧƵes:** + * - ServiƧo deve existir no catĆ”logo + * - ServiƧo deve estar ativo + * - Provider nĆ£o pode jĆ” oferecer o serviƧo + * - Provider nĆ£o pode estar deletado + */ +export const apiServicesPostMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await apiServicesPost({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +export const apiProvidersGet4QueryKey = (options: Options) => createQueryKey('apiProvidersGet4', options); + +/** + * Buscar prestadores de serviƧo + * + * Busca prestadores de serviƧo ativos com base em geolocalização e filtros. + * + * **Algoritmo de Busca:** + * 1. Filtrar por raio a partir da localização de busca + * 2. Aplicar filtro textual (nome, descrição) se fornecido + * 3. Aplicar filtros opcionais (serviƧos, avaliação, nĆ­vel de assinatura) + * 4. Classificar resultados por: + * - NĆ­vel de assinatura (Platinum > Gold > Standard > Free) + * - Avaliação mĆ©dia (maior primeiro) + * - DistĆ¢ncia (mais próximo primeiro) + * + * **Casos de Uso:** + * - Encontrar prestadores próximos a uma localização especĆ­fica + * - Buscar prestadores por nome ou termo (ex: "Eletricista", "JoĆ£o") + * - Buscar prestadores que oferecem serviƧos especĆ­ficos + * - Filtrar por avaliação mĆ­nima ou nĆ­vel de assinatura + */ +export const apiProvidersGet4Options = (options: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await apiProvidersGet4({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: apiProvidersGet4QueryKey(options) +}); + +const createInfiniteParams = [0], 'body' | 'headers' | 'path' | 'query'>>(queryKey: QueryKey, page: K) => { + const params = { ...queryKey[0] }; + if (page.body) { + params.body = { + ...queryKey[0].body as any, + ...page.body as any + }; + } + if (page.headers) { + params.headers = { + ...queryKey[0].headers, + ...page.headers + }; + } + if (page.path) { + params.path = { + ...queryKey[0].path as any, + ...page.path as any + }; + } + if (page.query) { + params.query = { + ...queryKey[0].query as any, + ...page.query as any + }; + } + return params as unknown as typeof page; +}; + +export const apiProvidersGet4InfiniteQueryKey = (options: Options): QueryKey> => createQueryKey('apiProvidersGet4', options, true); + +/** + * Buscar prestadores de serviƧo + * + * Busca prestadores de serviƧo ativos com base em geolocalização e filtros. + * + * **Algoritmo de Busca:** + * 1. Filtrar por raio a partir da localização de busca + * 2. Aplicar filtro textual (nome, descrição) se fornecido + * 3. Aplicar filtros opcionais (serviƧos, avaliação, nĆ­vel de assinatura) + * 4. Classificar resultados por: + * - NĆ­vel de assinatura (Platinum > Gold > Standard > Free) + * - Avaliação mĆ©dia (maior primeiro) + * - DistĆ¢ncia (mais próximo primeiro) + * + * **Casos de Uso:** + * - Encontrar prestadores próximos a uma localização especĆ­fica + * - Buscar prestadores por nome ou termo (ex: "Eletricista", "JoĆ£o") + * - Buscar prestadores que oferecem serviƧos especĆ­ficos + * - Filtrar por avaliação mĆ­nima ou nĆ­vel de assinatura + */ +export const apiProvidersGet4InfiniteOptions = (options: Options) => infiniteQueryOptions, QueryKey>, number | Pick>[0], 'body' | 'headers' | 'path' | 'query'>>( +// @ts-ignore +{ + queryFn: async ({ pageParam, queryKey, signal }) => { + // @ts-ignore + const page: Pick>[0], 'body' | 'headers' | 'path' | 'query'> = typeof pageParam === 'object' ? pageParam : { + query: { + page: pageParam + } + }; + const params = createInfiniteParams(queryKey, page); + const { data } = await apiProvidersGet4({ + ...options, + ...params, + signal, + throwOnError: true + }); + return data; + }, + queryKey: apiProvidersGet4InfiniteQueryKey(options) +}); + +/** + * Recebe e registra violaƧƵes de CSP. + */ +export const apiCspReportPostMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await apiCspReportPost({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +export const apiCategoriesGetQueryKey = (options?: Options) => createQueryKey('apiCategoriesGet', options); + +/** + * Listar todas as categorias + * + * Retorna todas as categorias de serviƧos do catĆ”logo. + * + * **Filtros Opcionais:** + * - `activeOnly` (bool): Filtra apenas categorias ativas (padrĆ£o: false) + * + * **Ordenação:** + * - Categorias sĆ£o ordenadas por DisplayOrder (crescente) + * + * **Casos de Uso:** + * - Exibir menu de categorias para usuĆ”rios + * - Administração do catĆ”logo de categorias + * - Seleção de categoria ao criar serviƧo + */ +export const apiCategoriesGetOptions = (options?: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await apiCategoriesGet({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: apiCategoriesGetQueryKey(options) +}); + +/** + * Criar categoria de serviƧo + * + * Cria uma nova categoria de serviƧos no catĆ”logo. + * + * **ValidaƧƵes:** + * - Nome Ć© obrigatório (mĆ”ximo 100 caracteres) + * - Descrição opcional (mĆ”ximo 500 caracteres) + * - DisplayOrder deve ser >= 0 + * - Nome deve ser Ćŗnico no sistema + * + * **Efeitos:** + * - Categoria criada como ativa por padrĆ£o + * - Pode receber serviƧos imediatamente + * + * **PermissƵes:** Requer privilĆ©gios de administrador + */ +export const apiCategoriesPostMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await apiCategoriesPost({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +/** + * Deletar categoria de serviƧo + * + * Deleta uma categoria de serviƧos permanentemente. + * + * **ValidaƧƵes:** + * - ID nĆ£o pode ser vazio + * - Categoria deve existir + * - Categoria nĆ£o pode ter serviƧos associados + * + * **Importante:** Operação destrutiva. Categorias com serviƧos nĆ£o podem + * ser deletadas. Use desativação ou mova os serviƧos primeiro. + * + * **PermissƵes:** Requer privilĆ©gios de administrador + */ +export const apiCategoriesDeleteMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await apiCategoriesDelete({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +export const apiCategoriesGet2QueryKey = (options: Options) => createQueryKey('apiCategoriesGet2', options); + +/** + * Buscar categoria por ID + * + * Retorna os detalhes completos de uma categoria especĆ­fica. + * + * **Retorno:** + * - InformaƧƵes completas da categoria + * - Status de ativação + * - DisplayOrder para ordenação + * - Datas de criação e atualização + * + * **Casos de Uso:** + * - Exibir detalhes da categoria para edição + * - Validar existĆŖncia de categoria + * - Visualizar informaƧƵes completas + */ +export const apiCategoriesGet2Options = (options: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await apiCategoriesGet2({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: apiCategoriesGet2QueryKey(options) +}); + +/** + * Atualizar categoria de serviƧo + * + * Atualiza as informaƧƵes de uma categoria existente. + * + * **ValidaƧƵes:** + * - ID nĆ£o pode ser vazio + * - Categoria deve existir + * - Nome Ć© obrigatório (mĆ”ximo 100 caracteres) + * - Descrição opcional (mĆ”ximo 500 caracteres) + * - DisplayOrder deve ser >= 0 + * + * **Nota:** Requer atualização completa (full-update pattern). + * Todos os campos devem ser fornecidos. + * + * **PermissƵes:** Requer privilĆ©gios de administrador + */ +export const apiCategoriesPutMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await apiCategoriesPut({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +/** + * Ativar categoria de serviƧo + * + * Ativa uma categoria de serviƧos. + * + * **Efeitos:** + * - Categoria fica visĆ­vel em listagens pĆŗblicas + * - Permite criação de novos serviƧos nesta categoria + * - ServiƧos existentes na categoria voltam a ser acessĆ­veis + * + * **PermissƵes:** Requer privilĆ©gios de administrador + */ +export const apiActivatePost2Mutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await apiActivatePost2({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +/** + * Desativar categoria de serviƧo + * + * Desativa uma categoria de serviƧos. + * + * **Efeitos:** + * - Categoria nĆ£o aparece em listagens pĆŗblicas + * - Impede criação de novos serviƧos nesta categoria + * - ServiƧos existentes permanecem no sistema (soft-delete) + * + * **Nota:** PreferĆ­vel Ć  deleção quando hĆ” serviƧos associados. + * + * **PermissƵes:** Requer privilĆ©gios de administrador + */ +export const apiDeactivatePost2Mutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await apiDeactivatePost2({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +export const apiServicesGetQueryKey = (options?: Options) => createQueryKey('apiServicesGet', options); + +/** + * Listar todos os serviƧos + * + * Retorna todos os serviƧos do catĆ”logo. + * + * **Filtros Opcionais:** + * - `activeOnly` (bool): Filtra apenas serviƧos ativos (padrĆ£o: false) + * + * **Casos de Uso:** + * - Listar todo o catĆ”logo de serviƧos + * - Obter apenas serviƧos ativos para exibição pĆŗblica + * - Administração do catĆ”logo completo + */ +export const apiServicesGetOptions = (options?: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await apiServicesGet({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: apiServicesGetQueryKey(options) +}); + +/** + * Criar serviƧo + * + * Cria um novo serviƧo no catĆ”logo. + * + * **ValidaƧƵes:** + * - Nome Ć© obrigatório (mĆ”ximo 150 caracteres) + * - Descrição opcional (mĆ”ximo 1000 caracteres) + * - DisplayOrder deve ser >= 0 + * - Categoria deve existir e estar ativa + * + * **PermissƵes:** Requer privilĆ©gios de administrador + */ +export const apiServicesPost2Mutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await apiServicesPost2({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +/** + * Deletar serviƧo + * + * Deleta um serviƧo do catĆ”logo permanentemente. + * + * **ValidaƧƵes:** + * - ID nĆ£o pode ser vazio + * - ServiƧo deve existir + * - Nenhum provedor pode estar oferecendo este serviƧo + * + * **Importante:** Operação destrutiva. Se provedores oferecem o serviƧo, + * use desativação em vez de deleção para preservar dados históricos. + * + * **PermissƵes:** Requer privilĆ©gios de administrador + */ +export const apiServicesDelete2Mutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await apiServicesDelete2({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +export const apiServicesGet2QueryKey = (options: Options) => createQueryKey('apiServicesGet2', options); + +/** + * Buscar serviƧo por ID + * + * Retorna os detalhes completos de um serviƧo especĆ­fico. + * + * **Retorno:** + * - InformaƧƵes completas do serviƧo incluindo categoria + * - Status de ativação + * - Datas de criação e atualização + * + * **Casos de Uso:** + * - Exibir detalhes do serviƧo para edição + * - Visualizar informaƧƵes completas do serviƧo + * - Validar existĆŖncia do serviƧo + */ +export const apiServicesGet2Options = (options: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await apiServicesGet2({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: apiServicesGet2QueryKey(options) +}); + +/** + * Atualizar serviƧo + * + * Atualiza as informaƧƵes de um serviƧo existente. + * + * **ValidaƧƵes:** + * - ID nĆ£o pode ser vazio + * - ServiƧo deve existir + * - Nome Ć© obrigatório (mĆ”ximo 150 caracteres) + * - Descrição opcional (mĆ”ximo 1000 caracteres) + * - DisplayOrder deve ser >= 0 + * + * **Nota:** NĆ£o altera a categoria do serviƧo. Use ChangeServiceCategory para isso. + * + * **PermissƵes:** Requer privilĆ©gios de administrador + */ +export const apiServicesPutMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await apiServicesPut({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +export const apiCategoryGetQueryKey = (options: Options) => createQueryKey('apiCategoryGet', options); + +/** + * Listar serviƧos por categoria + * + * Retorna todos os serviƧos de uma categoria especĆ­fica. + * + * **ParĆ¢metros:** + * - `categoryId` (route): ID da categoria + * - `activeOnly` (query, opcional): Filtrar apenas serviƧos ativos (padrĆ£o: false) + * + * **Casos de Uso:** + * - Exibir serviƧos disponĆ­veis em uma categoria + * - Listar ofertas por categoria para provedores + * - GestĆ£o de catĆ”logo segmentado por categoria + */ +export const apiCategoryGetOptions = (options: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await apiCategoryGet({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: apiCategoryGetQueryKey(options) +}); + +/** + * Alterar categoria do serviƧo + * + * Move um serviƧo para uma categoria diferente. + * + * **ValidaƧƵes:** + * - ServiƧo deve existir + * - Nova categoria deve existir e estar ativa + * - Nova categoria nĆ£o pode ser a mesma que a atual + * + * **Casos de Uso:** + * - Reorganizar catĆ”logo de serviƧos + * - Corrigir categorização incorreta + * - Adaptar estrutura de categorias + * + * **PermissƵes:** Requer privilĆ©gios de administrador + */ +export const apiChangeCategoryPostMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await apiChangeCategoryPost({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +/** + * Ativar serviƧo + * + * Ativa um serviƧo, tornando-o disponĆ­vel no catĆ”logo. + * + * **Efeitos:** + * - ServiƧo fica visĆ­vel em listagens pĆŗblicas + * - Provedores podem adicionar este serviƧo Ć s suas ofertas + * - ServiƧo aparece em buscas de serviƧos ativos + * + * **PermissƵes:** Requer privilĆ©gios de administrador + */ +export const apiActivatePost3Mutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await apiActivatePost3({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +/** + * Desativar serviƧo + * + * Desativa um serviƧo, removendo-o do catĆ”logo ativo. + * + * **Efeitos:** + * - ServiƧo nĆ£o aparece em listagens pĆŗblicas + * - Provedores nĆ£o podem adicionar este serviƧo a novas ofertas + * - ServiƧo preserva dados históricos (soft-delete) + * + * **Nota:** PreferĆ­vel Ć  deleção quando provedores jĆ” oferecem o serviƧo. + * + * **PermissƵes:** Requer privilĆ©gios de administrador + */ +export const apiDeactivatePost3Mutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await apiDeactivatePost3({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +/** + * Validar mĆŗltiplos serviƧos + * + * Valida a existĆŖncia e status de uma lista de serviƧos. + * + * **Funcionalidade:** + * - Verifica se todos os IDs existem no catĆ”logo + * - Retorna quais serviƧos sĆ£o vĆ”lidos e quais sĆ£o invĆ”lidos + * - Indica serviƧos inativos separadamente + * + * **Casos de Uso:** + * - Validar serviƧos antes de adicionar a um provedor + * - Verificação em lote para importação de dados + * - Garantir integridade referencial entre módulos + * + * **PermissƵes:** Requer privilĆ©gios de administrador + */ +export const apiValidatePostMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await apiValidatePost({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +export const apiUsersGetQueryKey = (options?: Options) => createQueryKey('apiUsersGet', options); + +/** + * Processa requisição de consulta de usuĆ”rios de forma assĆ­ncrona. + * + * Fluxo de execução: + * 1. Extrai parĆ¢metros de paginação da query string + * 2. Cria query CQRS com parĆ¢metros validados + * 3. Envia query atravĆ©s do dispatcher + * 4. Retorna resposta paginada estruturada com metadados + * + * Suporta parĆ¢metros: PageNumber, PageSize, SearchTerm + */ +export const apiUsersGetOptions = (options?: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await apiUsersGet({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: apiUsersGetQueryKey(options) +}); + +/** + * Processa requisição de criação de usuĆ”rio de forma assĆ­ncrona. + * + * Fluxo de execução: + * 1. Converte request em comando CQRS + * 2. Envia comando atravĆ©s do dispatcher + * 3. Processa resultado e retorna resposta HTTP apropriada + * 4. Inclui localização do recurso criado no header + */ +export const apiUsersPostMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await apiUsersPost({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +/** + * Implementa a lógica de exclusĆ£o de usuĆ”rio. + * + * Processo de exclusĆ£o: + * 1. Valida ID do usuĆ”rio no formato GUID + * 2. Cria command usando mapper ToDeleteCommand + * 3. Envia command atravĆ©s do dispatcher CQRS + * 4. Retorna resposta HTTP 204 No Content + */ +export const apiUsersDeleteMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await apiUsersDelete({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +export const apiUsersGet2QueryKey = (options: Options) => createQueryKey('apiUsersGet2', options); + +/** + * Implementa a lógica de consulta de usuĆ”rio por ID. + * + * Processo da consulta: + * 1. Valida ID do usuĆ”rio no formato GUID + * 2. Cria query usando mapper ToQuery + * 3. Envia query atravĆ©s do dispatcher CQRS + * 4. Retorna resposta HTTP com dados do usuĆ”rio + */ +export const apiUsersGet2Options = (options: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await apiUsersGet2({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: apiUsersGet2QueryKey(options) +}); + +export const apiByEmailGetQueryKey = (options: Options) => createQueryKey('apiByEmailGet', options); + +/** + * Implementa a lógica de consulta de usuĆ”rio por email. + * + * Processo da consulta: + * 1. Valida formato do email + * 2. Cria query usando mapper ToEmailQuery + * 3. Envia query atravĆ©s do dispatcher CQRS + * 4. Retorna resposta HTTP com dados do usuĆ”rio + */ +export const apiByEmailGetOptions = (options: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await apiByEmailGet({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: apiByEmailGetQueryKey(options) +}); + +/** + * Processa requisição de atualização de perfil de usuĆ”rio de forma assĆ­ncrona. + * + * Fluxo de execução: + * 1. Valida ID do usuĆ”rio no formato GUID + * 2. Cria comando de atualização com dados da requisição + * 3. Envia comando atravĆ©s do dispatcher CQRS + * 4. Retorna resposta HTTP com dados atualizados + * + * Dados atualizĆ”veis: FirstName, LastName, Email, PhoneNumber + */ +export const apiProfilePutMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await apiProfilePut({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +/** + * Registers a new customer + * + * Creates a new user account with 'customer' role. + */ +export const apiRegisterPost2Mutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await apiRegisterPost2({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; diff --git a/src/Web/MeAjudaAi.Web.Admin-React/src/lib/api/generated/client.gen.ts b/src/Web/MeAjudaAi.Web.Admin-React/src/lib/api/generated/client.gen.ts new file mode 100644 index 000000000..7d4f73ab9 --- /dev/null +++ b/src/Web/MeAjudaAi.Web.Admin-React/src/lib/api/generated/client.gen.ts @@ -0,0 +1,16 @@ +// This file is auto-generated by @hey-api/openapi-ts + +import { type ClientOptions, type Config, createClient, createConfig } from './client'; +import type { ClientOptions as ClientOptions2 } from './types.gen'; + +/** + * The `createClientConfig()` function will be called on client initialization + * and the returned object will become the client's initial configuration. + * + * You may want to initialize your client this way instead of calling + * `setConfig()`. This is useful for example if you're using Next.js + * to ensure your client always has the correct values. + */ +export type CreateClientConfig = (override?: Config) => Config & T>; + +export const client = createClient(createConfig({ baseUrl: process.env.NEXT_PUBLIC_API_BASE_URL ?? 'http://localhost:7002' })); diff --git a/src/Web/MeAjudaAi.Web.Admin-React/src/lib/api/generated/client/client.gen.ts b/src/Web/MeAjudaAi.Web.Admin-React/src/lib/api/generated/client/client.gen.ts new file mode 100644 index 000000000..14dc0a0ec --- /dev/null +++ b/src/Web/MeAjudaAi.Web.Admin-React/src/lib/api/generated/client/client.gen.ts @@ -0,0 +1,290 @@ +// This file is auto-generated by @hey-api/openapi-ts + +import { createSseClient } from '../core/serverSentEvents.gen'; +import type { HttpMethod } from '../core/types.gen'; +import { getValidRequestBody } from '../core/utils.gen'; +import type { Client, Config, RequestOptions, ResolvedRequestOptions } from './types.gen'; +import { + buildUrl, + createConfig, + createInterceptors, + getParseAs, + mergeConfigs, + mergeHeaders, + setAuthParams, +} from './utils.gen'; + +type ReqInit = Omit & { + body?: any; + headers: ReturnType; +}; + +export const createClient = (config: Config = {}): Client => { + let _config = mergeConfigs(createConfig(), config); + + const getConfig = (): Config => ({ ..._config }); + + const setConfig = (config: Config): Config => { + _config = mergeConfigs(_config, config); + return getConfig(); + }; + + const interceptors = createInterceptors(); + + const beforeRequest = async (options: RequestOptions) => { + const opts = { + ..._config, + ...options, + fetch: options.fetch ?? _config.fetch ?? globalThis.fetch, + headers: mergeHeaders(_config.headers, options.headers), + serializedBody: undefined as string | undefined, + }; + + if (opts.security) { + await setAuthParams({ + ...opts, + security: opts.security, + }); + } + + if (opts.requestValidator) { + await opts.requestValidator(opts); + } + + if (opts.body !== undefined && opts.bodySerializer) { + opts.serializedBody = opts.bodySerializer(opts.body) as string | undefined; + } + + // remove Content-Type header if body is empty to avoid sending invalid requests + if (opts.body === undefined || opts.serializedBody === '') { + opts.headers.delete('Content-Type'); + } + + const url = buildUrl(opts); + + return { opts, url }; + }; + + const request: Client['request'] = async (options) => { + // @ts-expect-error + const { opts, url } = await beforeRequest(options); + const requestInit: ReqInit = { + redirect: 'follow', + ...opts, + body: getValidRequestBody(opts), + }; + + let request = new Request(url, requestInit); + + for (const fn of interceptors.request.fns) { + if (fn) { + request = await fn(request, opts); + } + } + + // fetch must be assigned here, otherwise it would throw the error: + // TypeError: Failed to execute 'fetch' on 'Window': Illegal invocation + const _fetch = opts.fetch!; + let response: Response; + + try { + response = await _fetch(request); + } catch (error) { + // Handle fetch exceptions (AbortError, network errors, etc.) + let finalError = error; + + for (const fn of interceptors.error.fns) { + if (fn) { + finalError = (await fn(error, undefined as any, request, opts)) as unknown; + } + } + + finalError = finalError || ({} as unknown); + + if (opts.throwOnError) { + throw finalError; + } + + // Return error response + return opts.responseStyle === 'data' + ? undefined + : { + error: finalError, + request, + response: undefined as any, + }; + } + + for (const fn of interceptors.response.fns) { + if (fn) { + response = await fn(response, request, opts); + } + } + + const result = { + request, + response, + }; + + if (response.ok) { + const parseAs = + (opts.parseAs === 'auto' + ? getParseAs(response.headers.get('Content-Type')) + : opts.parseAs) ?? 'json'; + + if (response.status === 204 || response.headers.get('Content-Length') === '0') { + let emptyData: any; + switch (parseAs) { + case 'arrayBuffer': + case 'blob': + case 'text': + emptyData = await response[parseAs](); + break; + case 'formData': + emptyData = new FormData(); + break; + case 'stream': + emptyData = response.body; + break; + case 'json': + default: + emptyData = {}; + break; + } + return opts.responseStyle === 'data' + ? emptyData + : { + data: emptyData, + ...result, + }; + } + + let data: any; + switch (parseAs) { + case 'arrayBuffer': + case 'blob': + case 'formData': + case 'text': + data = await response[parseAs](); + break; + case 'json': { + // Some servers return 200 with no Content-Length and empty body. + // response.json() would throw; read as text and parse if non-empty. + const text = await response.text(); + data = text ? JSON.parse(text) : {}; + break; + } + case 'stream': + return opts.responseStyle === 'data' + ? response.body + : { + data: response.body, + ...result, + }; + } + + if (parseAs === 'json') { + if (opts.responseValidator) { + await opts.responseValidator(data); + } + + if (opts.responseTransformer) { + data = await opts.responseTransformer(data); + } + } + + return opts.responseStyle === 'data' + ? data + : { + data, + ...result, + }; + } + + const textError = await response.text(); + let jsonError: unknown; + + try { + jsonError = JSON.parse(textError); + } catch { + // noop + } + + const error = jsonError ?? textError; + let finalError = error; + + for (const fn of interceptors.error.fns) { + if (fn) { + finalError = (await fn(error, response, request, opts)) as string; + } + } + + finalError = finalError || ({} as string); + + if (opts.throwOnError) { + throw finalError; + } + + // TODO: we probably want to return error and improve types + return opts.responseStyle === 'data' + ? undefined + : { + error: finalError, + ...result, + }; + }; + + const makeMethodFn = (method: Uppercase) => (options: RequestOptions) => + request({ ...options, method }); + + const makeSseFn = (method: Uppercase) => async (options: RequestOptions) => { + const { opts, url } = await beforeRequest(options); + return createSseClient({ + ...opts, + body: opts.body as BodyInit | null | undefined, + headers: opts.headers as unknown as Record, + method, + onRequest: async (url, init) => { + let request = new Request(url, init); + for (const fn of interceptors.request.fns) { + if (fn) { + request = await fn(request, opts); + } + } + return request; + }, + serializedBody: getValidRequestBody(opts) as BodyInit | null | undefined, + url, + }); + }; + + const _buildUrl: Client['buildUrl'] = (options) => buildUrl({ ..._config, ...options }); + + return { + buildUrl: _buildUrl, + connect: makeMethodFn('CONNECT'), + delete: makeMethodFn('DELETE'), + get: makeMethodFn('GET'), + getConfig, + head: makeMethodFn('HEAD'), + interceptors, + options: makeMethodFn('OPTIONS'), + patch: makeMethodFn('PATCH'), + post: makeMethodFn('POST'), + put: makeMethodFn('PUT'), + request, + setConfig, + sse: { + connect: makeSseFn('CONNECT'), + delete: makeSseFn('DELETE'), + get: makeSseFn('GET'), + head: makeSseFn('HEAD'), + options: makeSseFn('OPTIONS'), + patch: makeSseFn('PATCH'), + post: makeSseFn('POST'), + put: makeSseFn('PUT'), + trace: makeSseFn('TRACE'), + }, + trace: makeMethodFn('TRACE'), + } as Client; +}; diff --git a/src/Web/MeAjudaAi.Web.Admin-React/src/lib/api/generated/client/index.ts b/src/Web/MeAjudaAi.Web.Admin-React/src/lib/api/generated/client/index.ts new file mode 100644 index 000000000..b295edeca --- /dev/null +++ b/src/Web/MeAjudaAi.Web.Admin-React/src/lib/api/generated/client/index.ts @@ -0,0 +1,25 @@ +// This file is auto-generated by @hey-api/openapi-ts + +export type { Auth } from '../core/auth.gen'; +export type { QuerySerializerOptions } from '../core/bodySerializer.gen'; +export { + formDataBodySerializer, + jsonBodySerializer, + urlSearchParamsBodySerializer, +} from '../core/bodySerializer.gen'; +export { buildClientParams } from '../core/params.gen'; +export { serializeQueryKeyValue } from '../core/queryKeySerializer.gen'; +export { createClient } from './client.gen'; +export type { + Client, + ClientOptions, + Config, + CreateClientConfig, + Options, + RequestOptions, + RequestResult, + ResolvedRequestOptions, + ResponseStyle, + TDataShape, +} from './types.gen'; +export { createConfig, mergeHeaders } from './utils.gen'; diff --git a/src/Web/MeAjudaAi.Web.Admin-React/src/lib/api/generated/client/types.gen.ts b/src/Web/MeAjudaAi.Web.Admin-React/src/lib/api/generated/client/types.gen.ts new file mode 100644 index 000000000..a3f861651 --- /dev/null +++ b/src/Web/MeAjudaAi.Web.Admin-React/src/lib/api/generated/client/types.gen.ts @@ -0,0 +1,214 @@ +// This file is auto-generated by @hey-api/openapi-ts + +import type { Auth } from '../core/auth.gen'; +import type { + ServerSentEventsOptions, + ServerSentEventsResult, +} from '../core/serverSentEvents.gen'; +import type { Client as CoreClient, Config as CoreConfig } from '../core/types.gen'; +import type { Middleware } from './utils.gen'; + +export type ResponseStyle = 'data' | 'fields'; + +export interface Config + extends Omit, CoreConfig { + /** + * Base URL for all requests made by this client. + */ + baseUrl?: T['baseUrl']; + /** + * Fetch API implementation. You can use this option to provide a custom + * fetch instance. + * + * @default globalThis.fetch + */ + fetch?: typeof fetch; + /** + * Please don't use the Fetch client for Next.js applications. The `next` + * options won't have any effect. + * + * Install {@link https://www.npmjs.com/package/@hey-api/client-next `@hey-api/client-next`} instead. + */ + next?: never; + /** + * Return the response data parsed in a specified format. By default, `auto` + * will infer the appropriate method from the `Content-Type` response header. + * You can override this behavior with any of the {@link Body} methods. + * Select `stream` if you don't want to parse response data at all. + * + * @default 'auto' + */ + parseAs?: 'arrayBuffer' | 'auto' | 'blob' | 'formData' | 'json' | 'stream' | 'text'; + /** + * Should we return only data or multiple fields (data, error, response, etc.)? + * + * @default 'fields' + */ + responseStyle?: ResponseStyle; + /** + * Throw an error instead of returning it in the response? + * + * @default false + */ + throwOnError?: T['throwOnError']; +} + +export interface RequestOptions< + TData = unknown, + TResponseStyle extends ResponseStyle = 'fields', + ThrowOnError extends boolean = boolean, + Url extends string = string, +> + extends + Config<{ + responseStyle: TResponseStyle; + throwOnError: ThrowOnError; + }>, + Pick< + ServerSentEventsOptions, + | 'onRequest' + | 'onSseError' + | 'onSseEvent' + | 'sseDefaultRetryDelay' + | 'sseMaxRetryAttempts' + | 'sseMaxRetryDelay' + > { + /** + * Any body that you want to add to your request. + * + * {@link https://developer.mozilla.org/docs/Web/API/fetch#body} + */ + body?: unknown; + path?: Record; + query?: Record; + /** + * Security mechanism(s) to use for the request. + */ + security?: ReadonlyArray; + url: Url; +} + +export interface ResolvedRequestOptions< + TResponseStyle extends ResponseStyle = 'fields', + ThrowOnError extends boolean = boolean, + Url extends string = string, +> extends RequestOptions { + serializedBody?: string; +} + +export type RequestResult< + TData = unknown, + TError = unknown, + ThrowOnError extends boolean = boolean, + TResponseStyle extends ResponseStyle = 'fields', +> = ThrowOnError extends true + ? Promise< + TResponseStyle extends 'data' + ? TData extends Record + ? TData[keyof TData] + : TData + : { + data: TData extends Record ? TData[keyof TData] : TData; + request: Request; + response: Response; + } + > + : Promise< + TResponseStyle extends 'data' + ? (TData extends Record ? TData[keyof TData] : TData) | undefined + : ( + | { + data: TData extends Record ? TData[keyof TData] : TData; + error: undefined; + } + | { + data: undefined; + error: TError extends Record ? TError[keyof TError] : TError; + } + ) & { + request: Request; + response: Response; + } + >; + +export interface ClientOptions { + baseUrl?: string; + responseStyle?: ResponseStyle; + throwOnError?: boolean; +} + +type MethodFn = < + TData = unknown, + TError = unknown, + ThrowOnError extends boolean = false, + TResponseStyle extends ResponseStyle = 'fields', +>( + options: Omit, 'method'>, +) => RequestResult; + +type SseFn = < + TData = unknown, + TError = unknown, + ThrowOnError extends boolean = false, + TResponseStyle extends ResponseStyle = 'fields', +>( + options: Omit, 'method'>, +) => Promise>; + +type RequestFn = < + TData = unknown, + TError = unknown, + ThrowOnError extends boolean = false, + TResponseStyle extends ResponseStyle = 'fields', +>( + options: Omit, 'method'> & + Pick>, 'method'>, +) => RequestResult; + +type BuildUrlFn = < + TData extends { + body?: unknown; + path?: Record; + query?: Record; + url: string; + }, +>( + options: TData & Options, +) => string; + +export type Client = CoreClient & { + interceptors: Middleware; +}; + +/** + * The `createClientConfig()` function will be called on client initialization + * and the returned object will become the client's initial configuration. + * + * You may want to initialize your client this way instead of calling + * `setConfig()`. This is useful for example if you're using Next.js + * to ensure your client always has the correct values. + */ +export type CreateClientConfig = ( + override?: Config, +) => Config & T>; + +export interface TDataShape { + body?: unknown; + headers?: unknown; + path?: unknown; + query?: unknown; + url: string; +} + +type OmitKeys = Pick>; + +export type Options< + TData extends TDataShape = TDataShape, + ThrowOnError extends boolean = boolean, + TResponse = unknown, + TResponseStyle extends ResponseStyle = 'fields', +> = OmitKeys< + RequestOptions, + 'body' | 'path' | 'query' | 'url' +> & + ([TData] extends [never] ? unknown : Omit); diff --git a/src/Web/MeAjudaAi.Web.Admin-React/src/lib/api/generated/client/utils.gen.ts b/src/Web/MeAjudaAi.Web.Admin-React/src/lib/api/generated/client/utils.gen.ts new file mode 100644 index 000000000..b4bd2435c --- /dev/null +++ b/src/Web/MeAjudaAi.Web.Admin-React/src/lib/api/generated/client/utils.gen.ts @@ -0,0 +1,316 @@ +// This file is auto-generated by @hey-api/openapi-ts + +import { getAuthToken } from '../core/auth.gen'; +import type { QuerySerializerOptions } from '../core/bodySerializer.gen'; +import { jsonBodySerializer } from '../core/bodySerializer.gen'; +import { + serializeArrayParam, + serializeObjectParam, + serializePrimitiveParam, +} from '../core/pathSerializer.gen'; +import { getUrl } from '../core/utils.gen'; +import type { Client, ClientOptions, Config, RequestOptions } from './types.gen'; + +export const createQuerySerializer = ({ + parameters = {}, + ...args +}: QuerySerializerOptions = {}) => { + const querySerializer = (queryParams: T) => { + const search: string[] = []; + if (queryParams && typeof queryParams === 'object') { + for (const name in queryParams) { + const value = queryParams[name]; + + if (value === undefined || value === null) { + continue; + } + + const options = parameters[name] || args; + + if (Array.isArray(value)) { + const serializedArray = serializeArrayParam({ + allowReserved: options.allowReserved, + explode: true, + name, + style: 'form', + value, + ...options.array, + }); + if (serializedArray) search.push(serializedArray); + } else if (typeof value === 'object') { + const serializedObject = serializeObjectParam({ + allowReserved: options.allowReserved, + explode: true, + name, + style: 'deepObject', + value: value as Record, + ...options.object, + }); + if (serializedObject) search.push(serializedObject); + } else { + const serializedPrimitive = serializePrimitiveParam({ + allowReserved: options.allowReserved, + name, + value: value as string, + }); + if (serializedPrimitive) search.push(serializedPrimitive); + } + } + } + return search.join('&'); + }; + return querySerializer; +}; + +/** + * Infers parseAs value from provided Content-Type header. + */ +export const getParseAs = (contentType: string | null): Exclude => { + if (!contentType) { + // If no Content-Type header is provided, the best we can do is return the raw response body, + // which is effectively the same as the 'stream' option. + return 'stream'; + } + + const cleanContent = contentType.split(';')[0]?.trim(); + + if (!cleanContent) { + return; + } + + if (cleanContent.startsWith('application/json') || cleanContent.endsWith('+json')) { + return 'json'; + } + + if (cleanContent === 'multipart/form-data') { + return 'formData'; + } + + if ( + ['application/', 'audio/', 'image/', 'video/'].some((type) => cleanContent.startsWith(type)) + ) { + return 'blob'; + } + + if (cleanContent.startsWith('text/')) { + return 'text'; + } + + return; +}; + +const checkForExistence = ( + options: Pick & { + headers: Headers; + }, + name?: string, +): boolean => { + if (!name) { + return false; + } + if ( + options.headers.has(name) || + options.query?.[name] || + options.headers.get('Cookie')?.includes(`${name}=`) + ) { + return true; + } + return false; +}; + +export const setAuthParams = async ({ + security, + ...options +}: Pick, 'security'> & + Pick & { + headers: Headers; + }) => { + for (const auth of security) { + if (checkForExistence(options, auth.name)) { + continue; + } + + const token = await getAuthToken(auth, options.auth); + + if (!token) { + continue; + } + + const name = auth.name ?? 'Authorization'; + + switch (auth.in) { + case 'query': + if (!options.query) { + options.query = {}; + } + options.query[name] = token; + break; + case 'cookie': + options.headers.append('Cookie', `${name}=${token}`); + break; + case 'header': + default: + options.headers.set(name, token); + break; + } + } +}; + +export const buildUrl: Client['buildUrl'] = (options) => + getUrl({ + baseUrl: options.baseUrl as string, + path: options.path, + query: options.query, + querySerializer: + typeof options.querySerializer === 'function' + ? options.querySerializer + : createQuerySerializer(options.querySerializer), + url: options.url, + }); + +export const mergeConfigs = (a: Config, b: Config): Config => { + const config = { ...a, ...b }; + if (config.baseUrl?.endsWith('/')) { + config.baseUrl = config.baseUrl.substring(0, config.baseUrl.length - 1); + } + config.headers = mergeHeaders(a.headers, b.headers); + return config; +}; + +const headersEntries = (headers: Headers): Array<[string, string]> => { + const entries: Array<[string, string]> = []; + headers.forEach((value, key) => { + entries.push([key, value]); + }); + return entries; +}; + +export const mergeHeaders = ( + ...headers: Array['headers'] | undefined> +): Headers => { + const mergedHeaders = new Headers(); + for (const header of headers) { + if (!header) { + continue; + } + + const iterator = header instanceof Headers ? headersEntries(header) : Object.entries(header); + + for (const [key, value] of iterator) { + if (value === null) { + mergedHeaders.delete(key); + } else if (Array.isArray(value)) { + for (const v of value) { + mergedHeaders.append(key, v as string); + } + } else if (value !== undefined) { + // assume object headers are meant to be JSON stringified, i.e. their + // content value in OpenAPI specification is 'application/json' + mergedHeaders.set( + key, + typeof value === 'object' ? JSON.stringify(value) : (value as string), + ); + } + } + } + return mergedHeaders; +}; + +type ErrInterceptor = ( + error: Err, + response: Res, + request: Req, + options: Options, +) => Err | Promise; + +type ReqInterceptor = (request: Req, options: Options) => Req | Promise; + +type ResInterceptor = ( + response: Res, + request: Req, + options: Options, +) => Res | Promise; + +class Interceptors { + fns: Array = []; + + clear(): void { + this.fns = []; + } + + eject(id: number | Interceptor): void { + const index = this.getInterceptorIndex(id); + if (this.fns[index]) { + this.fns[index] = null; + } + } + + exists(id: number | Interceptor): boolean { + const index = this.getInterceptorIndex(id); + return Boolean(this.fns[index]); + } + + getInterceptorIndex(id: number | Interceptor): number { + if (typeof id === 'number') { + return this.fns[id] ? id : -1; + } + return this.fns.indexOf(id); + } + + update(id: number | Interceptor, fn: Interceptor): number | Interceptor | false { + const index = this.getInterceptorIndex(id); + if (this.fns[index]) { + this.fns[index] = fn; + return id; + } + return false; + } + + use(fn: Interceptor): number { + this.fns.push(fn); + return this.fns.length - 1; + } +} + +export interface Middleware { + error: Interceptors>; + request: Interceptors>; + response: Interceptors>; +} + +export const createInterceptors = (): Middleware< + Req, + Res, + Err, + Options +> => ({ + error: new Interceptors>(), + request: new Interceptors>(), + response: new Interceptors>(), +}); + +const defaultQuerySerializer = createQuerySerializer({ + allowReserved: false, + array: { + explode: true, + style: 'form', + }, + object: { + explode: true, + style: 'deepObject', + }, +}); + +const defaultHeaders = { + 'Content-Type': 'application/json', +}; + +export const createConfig = ( + override: Config & T> = {}, +): Config & T> => ({ + ...jsonBodySerializer, + headers: defaultHeaders, + parseAs: 'auto', + querySerializer: defaultQuerySerializer, + ...override, +}); diff --git a/src/Web/MeAjudaAi.Web.Admin-React/src/lib/api/generated/core/auth.gen.ts b/src/Web/MeAjudaAi.Web.Admin-React/src/lib/api/generated/core/auth.gen.ts new file mode 100644 index 000000000..3ebf99478 --- /dev/null +++ b/src/Web/MeAjudaAi.Web.Admin-React/src/lib/api/generated/core/auth.gen.ts @@ -0,0 +1,41 @@ +// This file is auto-generated by @hey-api/openapi-ts + +export type AuthToken = string | undefined; + +export interface Auth { + /** + * Which part of the request do we use to send the auth? + * + * @default 'header' + */ + in?: 'header' | 'query' | 'cookie'; + /** + * Header or query parameter name. + * + * @default 'Authorization' + */ + name?: string; + scheme?: 'basic' | 'bearer'; + type: 'apiKey' | 'http'; +} + +export const getAuthToken = async ( + auth: Auth, + callback: ((auth: Auth) => Promise | AuthToken) | AuthToken, +): Promise => { + const token = typeof callback === 'function' ? await callback(auth) : callback; + + if (!token) { + return; + } + + if (auth.scheme === 'bearer') { + return `Bearer ${token}`; + } + + if (auth.scheme === 'basic') { + return `Basic ${btoa(token)}`; + } + + return token; +}; diff --git a/src/Web/MeAjudaAi.Web.Admin-React/src/lib/api/generated/core/bodySerializer.gen.ts b/src/Web/MeAjudaAi.Web.Admin-React/src/lib/api/generated/core/bodySerializer.gen.ts new file mode 100644 index 000000000..67daca60f --- /dev/null +++ b/src/Web/MeAjudaAi.Web.Admin-React/src/lib/api/generated/core/bodySerializer.gen.ts @@ -0,0 +1,82 @@ +// This file is auto-generated by @hey-api/openapi-ts + +import type { ArrayStyle, ObjectStyle, SerializerOptions } from './pathSerializer.gen'; + +export type QuerySerializer = (query: Record) => string; + +export type BodySerializer = (body: unknown) => unknown; + +type QuerySerializerOptionsObject = { + allowReserved?: boolean; + array?: Partial>; + object?: Partial>; +}; + +export type QuerySerializerOptions = QuerySerializerOptionsObject & { + /** + * Per-parameter serialization overrides. When provided, these settings + * override the global array/object settings for specific parameter names. + */ + parameters?: Record; +}; + +const serializeFormDataPair = (data: FormData, key: string, value: unknown): void => { + if (typeof value === 'string' || value instanceof Blob) { + data.append(key, value); + } else if (value instanceof Date) { + data.append(key, value.toISOString()); + } else { + data.append(key, JSON.stringify(value)); + } +}; + +const serializeUrlSearchParamsPair = (data: URLSearchParams, key: string, value: unknown): void => { + if (typeof value === 'string') { + data.append(key, value); + } else { + data.append(key, JSON.stringify(value)); + } +}; + +export const formDataBodySerializer = { + bodySerializer: (body: unknown): FormData => { + const data = new FormData(); + + Object.entries(body as Record).forEach(([key, value]) => { + if (value === undefined || value === null) { + return; + } + if (Array.isArray(value)) { + value.forEach((v) => serializeFormDataPair(data, key, v)); + } else { + serializeFormDataPair(data, key, value); + } + }); + + return data; + }, +}; + +export const jsonBodySerializer = { + bodySerializer: (body: unknown): string => + JSON.stringify(body, (_key, value) => (typeof value === 'bigint' ? value.toString() : value)), +}; + +export const urlSearchParamsBodySerializer = { + bodySerializer: (body: unknown): string => { + const data = new URLSearchParams(); + + Object.entries(body as Record).forEach(([key, value]) => { + if (value === undefined || value === null) { + return; + } + if (Array.isArray(value)) { + value.forEach((v) => serializeUrlSearchParamsPair(data, key, v)); + } else { + serializeUrlSearchParamsPair(data, key, value); + } + }); + + return data.toString(); + }, +}; diff --git a/src/Web/MeAjudaAi.Web.Admin-React/src/lib/api/generated/core/params.gen.ts b/src/Web/MeAjudaAi.Web.Admin-React/src/lib/api/generated/core/params.gen.ts new file mode 100644 index 000000000..7955601a5 --- /dev/null +++ b/src/Web/MeAjudaAi.Web.Admin-React/src/lib/api/generated/core/params.gen.ts @@ -0,0 +1,169 @@ +// This file is auto-generated by @hey-api/openapi-ts + +type Slot = 'body' | 'headers' | 'path' | 'query'; + +export type Field = + | { + in: Exclude; + /** + * Field name. This is the name we want the user to see and use. + */ + key: string; + /** + * Field mapped name. This is the name we want to use in the request. + * If omitted, we use the same value as `key`. + */ + map?: string; + } + | { + in: Extract; + /** + * Key isn't required for bodies. + */ + key?: string; + map?: string; + } + | { + /** + * Field name. This is the name we want the user to see and use. + */ + key: string; + /** + * Field mapped name. This is the name we want to use in the request. + * If `in` is omitted, `map` aliases `key` to the transport layer. + */ + map: Slot; + }; + +export interface Fields { + allowExtra?: Partial>; + args?: ReadonlyArray; +} + +export type FieldsConfig = ReadonlyArray; + +const extraPrefixesMap: Record = { + $body_: 'body', + $headers_: 'headers', + $path_: 'path', + $query_: 'query', +}; +const extraPrefixes = Object.entries(extraPrefixesMap); + +type KeyMap = Map< + string, + | { + in: Slot; + map?: string; + } + | { + in?: never; + map: Slot; + } +>; + +const buildKeyMap = (fields: FieldsConfig, map?: KeyMap): KeyMap => { + if (!map) { + map = new Map(); + } + + for (const config of fields) { + if ('in' in config) { + if (config.key) { + map.set(config.key, { + in: config.in, + map: config.map, + }); + } + } else if ('key' in config) { + map.set(config.key, { + map: config.map, + }); + } else if (config.args) { + buildKeyMap(config.args, map); + } + } + + return map; +}; + +interface Params { + body: unknown; + headers: Record; + path: Record; + query: Record; +} + +const stripEmptySlots = (params: Params) => { + for (const [slot, value] of Object.entries(params)) { + if (value && typeof value === 'object' && !Array.isArray(value) && !Object.keys(value).length) { + delete params[slot as Slot]; + } + } +}; + +export const buildClientParams = (args: ReadonlyArray, fields: FieldsConfig) => { + const params: Params = { + body: {}, + headers: {}, + path: {}, + query: {}, + }; + + const map = buildKeyMap(fields); + + let config: FieldsConfig[number] | undefined; + + for (const [index, arg] of args.entries()) { + if (fields[index]) { + config = fields[index]; + } + + if (!config) { + continue; + } + + if ('in' in config) { + if (config.key) { + const field = map.get(config.key)!; + const name = field.map || config.key; + if (field.in) { + (params[field.in] as Record)[name] = arg; + } + } else { + params.body = arg; + } + } else { + for (const [key, value] of Object.entries(arg ?? {})) { + const field = map.get(key); + + if (field) { + if (field.in) { + const name = field.map || key; + (params[field.in] as Record)[name] = value; + } else { + params[field.map] = value; + } + } else { + const extra = extraPrefixes.find(([prefix]) => key.startsWith(prefix)); + + if (extra) { + const [prefix, slot] = extra; + (params[slot] as Record)[key.slice(prefix.length)] = value; + } else if ('allowExtra' in config && config.allowExtra) { + for (const [slot, allowed] of Object.entries(config.allowExtra)) { + if (allowed) { + (params[slot as Slot] as Record)[key] = value; + break; + } + } + } + } + } + } + } + + stripEmptySlots(params); + + return params; +}; diff --git a/src/Web/MeAjudaAi.Web.Admin-React/src/lib/api/generated/core/pathSerializer.gen.ts b/src/Web/MeAjudaAi.Web.Admin-React/src/lib/api/generated/core/pathSerializer.gen.ts new file mode 100644 index 000000000..994b2848c --- /dev/null +++ b/src/Web/MeAjudaAi.Web.Admin-React/src/lib/api/generated/core/pathSerializer.gen.ts @@ -0,0 +1,171 @@ +// This file is auto-generated by @hey-api/openapi-ts + +interface SerializeOptions extends SerializePrimitiveOptions, SerializerOptions {} + +interface SerializePrimitiveOptions { + allowReserved?: boolean; + name: string; +} + +export interface SerializerOptions { + /** + * @default true + */ + explode: boolean; + style: T; +} + +export type ArrayStyle = 'form' | 'spaceDelimited' | 'pipeDelimited'; +export type ArraySeparatorStyle = ArrayStyle | MatrixStyle; +type MatrixStyle = 'label' | 'matrix' | 'simple'; +export type ObjectStyle = 'form' | 'deepObject'; +type ObjectSeparatorStyle = ObjectStyle | MatrixStyle; + +interface SerializePrimitiveParam extends SerializePrimitiveOptions { + value: string; +} + +export const separatorArrayExplode = (style: ArraySeparatorStyle) => { + switch (style) { + case 'label': + return '.'; + case 'matrix': + return ';'; + case 'simple': + return ','; + default: + return '&'; + } +}; + +export const separatorArrayNoExplode = (style: ArraySeparatorStyle) => { + switch (style) { + case 'form': + return ','; + case 'pipeDelimited': + return '|'; + case 'spaceDelimited': + return '%20'; + default: + return ','; + } +}; + +export const separatorObjectExplode = (style: ObjectSeparatorStyle) => { + switch (style) { + case 'label': + return '.'; + case 'matrix': + return ';'; + case 'simple': + return ','; + default: + return '&'; + } +}; + +export const serializeArrayParam = ({ + allowReserved, + explode, + name, + style, + value, +}: SerializeOptions & { + value: unknown[]; +}) => { + if (!explode) { + const joinedValues = ( + allowReserved ? value : value.map((v) => encodeURIComponent(v as string)) + ).join(separatorArrayNoExplode(style)); + switch (style) { + case 'label': + return `.${joinedValues}`; + case 'matrix': + return `;${name}=${joinedValues}`; + case 'simple': + return joinedValues; + default: + return `${name}=${joinedValues}`; + } + } + + const separator = separatorArrayExplode(style); + const joinedValues = value + .map((v) => { + if (style === 'label' || style === 'simple') { + return allowReserved ? v : encodeURIComponent(v as string); + } + + return serializePrimitiveParam({ + allowReserved, + name, + value: v as string, + }); + }) + .join(separator); + return style === 'label' || style === 'matrix' ? separator + joinedValues : joinedValues; +}; + +export const serializePrimitiveParam = ({ + allowReserved, + name, + value, +}: SerializePrimitiveParam) => { + if (value === undefined || value === null) { + return ''; + } + + if (typeof value === 'object') { + throw new Error( + 'Deeply-nested arrays/objects aren’t supported. Provide your own `querySerializer()` to handle these.', + ); + } + + return `${name}=${allowReserved ? value : encodeURIComponent(value)}`; +}; + +export const serializeObjectParam = ({ + allowReserved, + explode, + name, + style, + value, + valueOnly, +}: SerializeOptions & { + value: Record | Date; + valueOnly?: boolean; +}) => { + if (value instanceof Date) { + return valueOnly ? value.toISOString() : `${name}=${value.toISOString()}`; + } + + if (style !== 'deepObject' && !explode) { + let values: string[] = []; + Object.entries(value).forEach(([key, v]) => { + values = [...values, key, allowReserved ? (v as string) : encodeURIComponent(v as string)]; + }); + const joinedValues = values.join(','); + switch (style) { + case 'form': + return `${name}=${joinedValues}`; + case 'label': + return `.${joinedValues}`; + case 'matrix': + return `;${name}=${joinedValues}`; + default: + return joinedValues; + } + } + + const separator = separatorObjectExplode(style); + const joinedValues = Object.entries(value) + .map(([key, v]) => + serializePrimitiveParam({ + allowReserved, + name: style === 'deepObject' ? `${name}[${key}]` : key, + value: v as string, + }), + ) + .join(separator); + return style === 'label' || style === 'matrix' ? separator + joinedValues : joinedValues; +}; diff --git a/src/Web/MeAjudaAi.Web.Admin-React/src/lib/api/generated/core/queryKeySerializer.gen.ts b/src/Web/MeAjudaAi.Web.Admin-React/src/lib/api/generated/core/queryKeySerializer.gen.ts new file mode 100644 index 000000000..5000df606 --- /dev/null +++ b/src/Web/MeAjudaAi.Web.Admin-React/src/lib/api/generated/core/queryKeySerializer.gen.ts @@ -0,0 +1,117 @@ +// This file is auto-generated by @hey-api/openapi-ts + +/** + * JSON-friendly union that mirrors what Pinia Colada can hash. + */ +export type JsonValue = + | null + | string + | number + | boolean + | JsonValue[] + | { [key: string]: JsonValue }; + +/** + * Replacer that converts non-JSON values (bigint, Date, etc.) to safe substitutes. + */ +export const queryKeyJsonReplacer = (_key: string, value: unknown) => { + if (value === undefined || typeof value === 'function' || typeof value === 'symbol') { + return undefined; + } + if (typeof value === 'bigint') { + return value.toString(); + } + if (value instanceof Date) { + return value.toISOString(); + } + return value; +}; + +/** + * Safely stringifies a value and parses it back into a JsonValue. + */ +export const stringifyToJsonValue = (input: unknown): JsonValue | undefined => { + try { + const json = JSON.stringify(input, queryKeyJsonReplacer); + if (json === undefined) { + return undefined; + } + return JSON.parse(json) as JsonValue; + } catch { + return undefined; + } +}; + +/** + * Detects plain objects (including objects with a null prototype). + */ +const isPlainObject = (value: unknown): value is Record => { + if (value === null || typeof value !== 'object') { + return false; + } + const prototype = Object.getPrototypeOf(value as object); + return prototype === Object.prototype || prototype === null; +}; + +/** + * Turns URLSearchParams into a sorted JSON object for deterministic keys. + */ +const serializeSearchParams = (params: URLSearchParams): JsonValue => { + const entries = Array.from(params.entries()).sort(([a], [b]) => a.localeCompare(b)); + const result: Record = {}; + + for (const [key, value] of entries) { + const existing = result[key]; + if (existing === undefined) { + result[key] = value; + continue; + } + + if (Array.isArray(existing)) { + (existing as string[]).push(value); + } else { + result[key] = [existing, value]; + } + } + + return result; +}; + +/** + * Normalizes any accepted value into a JSON-friendly shape for query keys. + */ +export const serializeQueryKeyValue = (value: unknown): JsonValue | undefined => { + if (value === null) { + return null; + } + + if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') { + return value; + } + + if (value === undefined || typeof value === 'function' || typeof value === 'symbol') { + return undefined; + } + + if (typeof value === 'bigint') { + return value.toString(); + } + + if (value instanceof Date) { + return value.toISOString(); + } + + if (Array.isArray(value)) { + return stringifyToJsonValue(value); + } + + if (typeof URLSearchParams !== 'undefined' && value instanceof URLSearchParams) { + return serializeSearchParams(value); + } + + if (isPlainObject(value)) { + return stringifyToJsonValue(value); + } + + return undefined; +}; diff --git a/src/Web/MeAjudaAi.Web.Admin-React/src/lib/api/generated/core/serverSentEvents.gen.ts b/src/Web/MeAjudaAi.Web.Admin-React/src/lib/api/generated/core/serverSentEvents.gen.ts new file mode 100644 index 000000000..6aa6cf02a --- /dev/null +++ b/src/Web/MeAjudaAi.Web.Admin-React/src/lib/api/generated/core/serverSentEvents.gen.ts @@ -0,0 +1,243 @@ +// This file is auto-generated by @hey-api/openapi-ts + +import type { Config } from './types.gen'; + +export type ServerSentEventsOptions = Omit & + Pick & { + /** + * Fetch API implementation. You can use this option to provide a custom + * fetch instance. + * + * @default globalThis.fetch + */ + fetch?: typeof fetch; + /** + * Implementing clients can call request interceptors inside this hook. + */ + onRequest?: (url: string, init: RequestInit) => Promise; + /** + * Callback invoked when a network or parsing error occurs during streaming. + * + * This option applies only if the endpoint returns a stream of events. + * + * @param error The error that occurred. + */ + onSseError?: (error: unknown) => void; + /** + * Callback invoked when an event is streamed from the server. + * + * This option applies only if the endpoint returns a stream of events. + * + * @param event Event streamed from the server. + * @returns Nothing (void). + */ + onSseEvent?: (event: StreamEvent) => void; + serializedBody?: RequestInit['body']; + /** + * Default retry delay in milliseconds. + * + * This option applies only if the endpoint returns a stream of events. + * + * @default 3000 + */ + sseDefaultRetryDelay?: number; + /** + * Maximum number of retry attempts before giving up. + */ + sseMaxRetryAttempts?: number; + /** + * Maximum retry delay in milliseconds. + * + * Applies only when exponential backoff is used. + * + * This option applies only if the endpoint returns a stream of events. + * + * @default 30000 + */ + sseMaxRetryDelay?: number; + /** + * Optional sleep function for retry backoff. + * + * Defaults to using `setTimeout`. + */ + sseSleepFn?: (ms: number) => Promise; + url: string; + }; + +export interface StreamEvent { + data: TData; + event?: string; + id?: string; + retry?: number; +} + +export type ServerSentEventsResult = { + stream: AsyncGenerator< + TData extends Record ? TData[keyof TData] : TData, + TReturn, + TNext + >; +}; + +export const createSseClient = ({ + onRequest, + onSseError, + onSseEvent, + responseTransformer, + responseValidator, + sseDefaultRetryDelay, + sseMaxRetryAttempts, + sseMaxRetryDelay, + sseSleepFn, + url, + ...options +}: ServerSentEventsOptions): ServerSentEventsResult => { + let lastEventId: string | undefined; + + const sleep = sseSleepFn ?? ((ms: number) => new Promise((resolve) => setTimeout(resolve, ms))); + + const createStream = async function* () { + let retryDelay: number = sseDefaultRetryDelay ?? 3000; + let attempt = 0; + const signal = options.signal ?? new AbortController().signal; + + while (true) { + if (signal.aborted) break; + + attempt++; + + const headers = + options.headers instanceof Headers + ? options.headers + : new Headers(options.headers as Record | undefined); + + if (lastEventId !== undefined) { + headers.set('Last-Event-ID', lastEventId); + } + + try { + const requestInit: RequestInit = { + redirect: 'follow', + ...options, + body: options.serializedBody, + headers, + signal, + }; + let request = new Request(url, requestInit); + if (onRequest) { + request = await onRequest(url, requestInit); + } + // fetch must be assigned here, otherwise it would throw the error: + // TypeError: Failed to execute 'fetch' on 'Window': Illegal invocation + const _fetch = options.fetch ?? globalThis.fetch; + const response = await _fetch(request); + + if (!response.ok) throw new Error(`SSE failed: ${response.status} ${response.statusText}`); + + if (!response.body) throw new Error('No body in SSE response'); + + const reader = response.body.pipeThrough(new TextDecoderStream()).getReader(); + + let buffer = ''; + + const abortHandler = () => { + try { + reader.cancel(); + } catch { + // noop + } + }; + + signal.addEventListener('abort', abortHandler); + + try { + while (true) { + const { done, value } = await reader.read(); + if (done) break; + buffer += value; + // Normalize line endings: CRLF -> LF, then CR -> LF + buffer = buffer.replace(/\r\n/g, '\n').replace(/\r/g, '\n'); + + const chunks = buffer.split('\n\n'); + buffer = chunks.pop() ?? ''; + + for (const chunk of chunks) { + const lines = chunk.split('\n'); + const dataLines: Array = []; + let eventName: string | undefined; + + for (const line of lines) { + if (line.startsWith('data:')) { + dataLines.push(line.replace(/^data:\s*/, '')); + } else if (line.startsWith('event:')) { + eventName = line.replace(/^event:\s*/, ''); + } else if (line.startsWith('id:')) { + lastEventId = line.replace(/^id:\s*/, ''); + } else if (line.startsWith('retry:')) { + const parsed = Number.parseInt(line.replace(/^retry:\s*/, ''), 10); + if (!Number.isNaN(parsed)) { + retryDelay = parsed; + } + } + } + + let data: unknown; + let parsedJson = false; + + if (dataLines.length) { + const rawData = dataLines.join('\n'); + try { + data = JSON.parse(rawData); + parsedJson = true; + } catch { + data = rawData; + } + } + + if (parsedJson) { + if (responseValidator) { + await responseValidator(data); + } + + if (responseTransformer) { + data = await responseTransformer(data); + } + } + + onSseEvent?.({ + data, + event: eventName, + id: lastEventId, + retry: retryDelay, + }); + + if (dataLines.length) { + yield data as any; + } + } + } + } finally { + signal.removeEventListener('abort', abortHandler); + reader.releaseLock(); + } + + break; // exit loop on normal completion + } catch (error) { + // connection failed or aborted; retry after delay + onSseError?.(error); + + if (sseMaxRetryAttempts !== undefined && attempt >= sseMaxRetryAttempts) { + break; // stop after firing error + } + + // exponential backoff: double retry each attempt, cap at 30s + const backoff = Math.min(retryDelay * 2 ** (attempt - 1), sseMaxRetryDelay ?? 30000); + await sleep(backoff); + } + } + }; + + const stream = createStream(); + + return { stream }; +}; diff --git a/src/Web/MeAjudaAi.Web.Admin-React/src/lib/api/generated/core/types.gen.ts b/src/Web/MeAjudaAi.Web.Admin-React/src/lib/api/generated/core/types.gen.ts new file mode 100644 index 000000000..97463257e --- /dev/null +++ b/src/Web/MeAjudaAi.Web.Admin-React/src/lib/api/generated/core/types.gen.ts @@ -0,0 +1,104 @@ +// This file is auto-generated by @hey-api/openapi-ts + +import type { Auth, AuthToken } from './auth.gen'; +import type { BodySerializer, QuerySerializer, QuerySerializerOptions } from './bodySerializer.gen'; + +export type HttpMethod = + | 'connect' + | 'delete' + | 'get' + | 'head' + | 'options' + | 'patch' + | 'post' + | 'put' + | 'trace'; + +export type Client< + RequestFn = never, + Config = unknown, + MethodFn = never, + BuildUrlFn = never, + SseFn = never, +> = { + /** + * Returns the final request URL. + */ + buildUrl: BuildUrlFn; + getConfig: () => Config; + request: RequestFn; + setConfig: (config: Config) => Config; +} & { + [K in HttpMethod]: MethodFn; +} & ([SseFn] extends [never] ? { sse?: never } : { sse: { [K in HttpMethod]: SseFn } }); + +export interface Config { + /** + * Auth token or a function returning auth token. The resolved value will be + * added to the request payload as defined by its `security` array. + */ + auth?: ((auth: Auth) => Promise | AuthToken) | AuthToken; + /** + * A function for serializing request body parameter. By default, + * {@link JSON.stringify()} will be used. + */ + bodySerializer?: BodySerializer | null; + /** + * An object containing any HTTP headers that you want to pre-populate your + * `Headers` object with. + * + * {@link https://developer.mozilla.org/docs/Web/API/Headers/Headers#init See more} + */ + headers?: + | RequestInit['headers'] + | Record< + string, + string | number | boolean | (string | number | boolean)[] | null | undefined | unknown + >; + /** + * The request method. + * + * {@link https://developer.mozilla.org/docs/Web/API/fetch#method See more} + */ + method?: Uppercase; + /** + * A function for serializing request query parameters. By default, arrays + * will be exploded in form style, objects will be exploded in deepObject + * style, and reserved characters are percent-encoded. + * + * This method will have no effect if the native `paramsSerializer()` Axios + * API function is used. + * + * {@link https://swagger.io/docs/specification/serialization/#query View examples} + */ + querySerializer?: QuerySerializer | QuerySerializerOptions; + /** + * A function validating request data. This is useful if you want to ensure + * the request conforms to the desired shape, so it can be safely sent to + * the server. + */ + requestValidator?: (data: unknown) => Promise; + /** + * A function transforming response data before it's returned. This is useful + * for post-processing data, e.g. converting ISO strings into Date objects. + */ + responseTransformer?: (data: unknown) => Promise; + /** + * A function validating response data. This is useful if you want to ensure + * the response conforms to the desired shape, so it can be safely passed to + * the transformers and returned to the user. + */ + responseValidator?: (data: unknown) => Promise; +} + +type IsExactlyNeverOrNeverUndefined = [T] extends [never] + ? true + : [T] extends [never | undefined] + ? [undefined] extends [T] + ? false + : true + : false; + +export type OmitNever> = { + [K in keyof T as IsExactlyNeverOrNeverUndefined extends true ? never : K]: T[K]; +}; diff --git a/src/Web/MeAjudaAi.Web.Admin-React/src/lib/api/generated/core/utils.gen.ts b/src/Web/MeAjudaAi.Web.Admin-React/src/lib/api/generated/core/utils.gen.ts new file mode 100644 index 000000000..e7ddbe354 --- /dev/null +++ b/src/Web/MeAjudaAi.Web.Admin-React/src/lib/api/generated/core/utils.gen.ts @@ -0,0 +1,140 @@ +// This file is auto-generated by @hey-api/openapi-ts + +import type { BodySerializer, QuerySerializer } from './bodySerializer.gen'; +import { + type ArraySeparatorStyle, + serializeArrayParam, + serializeObjectParam, + serializePrimitiveParam, +} from './pathSerializer.gen'; + +export interface PathSerializer { + path: Record; + url: string; +} + +export const PATH_PARAM_RE = /\{[^{}]+\}/g; + +export const defaultPathSerializer = ({ path, url: _url }: PathSerializer) => { + let url = _url; + const matches = _url.match(PATH_PARAM_RE); + if (matches) { + for (const match of matches) { + let explode = false; + let name = match.substring(1, match.length - 1); + let style: ArraySeparatorStyle = 'simple'; + + if (name.endsWith('*')) { + explode = true; + name = name.substring(0, name.length - 1); + } + + if (name.startsWith('.')) { + name = name.substring(1); + style = 'label'; + } else if (name.startsWith(';')) { + name = name.substring(1); + style = 'matrix'; + } + + const value = path[name]; + + if (value === undefined || value === null) { + continue; + } + + if (Array.isArray(value)) { + url = url.replace(match, serializeArrayParam({ explode, name, style, value })); + continue; + } + + if (typeof value === 'object') { + url = url.replace( + match, + serializeObjectParam({ + explode, + name, + style, + value: value as Record, + valueOnly: true, + }), + ); + continue; + } + + if (style === 'matrix') { + url = url.replace( + match, + `;${serializePrimitiveParam({ + name, + value: value as string, + })}`, + ); + continue; + } + + const replaceValue = encodeURIComponent( + style === 'label' ? `.${value as string}` : (value as string), + ); + url = url.replace(match, replaceValue); + } + } + return url; +}; + +export const getUrl = ({ + baseUrl, + path, + query, + querySerializer, + url: _url, +}: { + baseUrl?: string; + path?: Record; + query?: Record; + querySerializer: QuerySerializer; + url: string; +}) => { + const pathUrl = _url.startsWith('/') ? _url : `/${_url}`; + let url = (baseUrl ?? '') + pathUrl; + if (path) { + url = defaultPathSerializer({ path, url }); + } + let search = query ? querySerializer(query) : ''; + if (search.startsWith('?')) { + search = search.substring(1); + } + if (search) { + url += `?${search}`; + } + return url; +}; + +export function getValidRequestBody(options: { + body?: unknown; + bodySerializer?: BodySerializer | null; + serializedBody?: unknown; +}) { + const hasBody = options.body !== undefined; + const isSerializedBody = hasBody && options.bodySerializer; + + if (isSerializedBody) { + if ('serializedBody' in options) { + const hasSerializedBody = + options.serializedBody !== undefined && options.serializedBody !== ''; + + return hasSerializedBody ? options.serializedBody : null; + } + + // not all clients implement a serializedBody property (i.e. client-axios) + return options.body !== '' ? options.body : null; + } + + // plain/text body + if (hasBody) { + return options.body; + } + + // no body was provided + return undefined; +} diff --git a/src/Web/MeAjudaAi.Web.Admin-React/src/lib/api/generated/index.ts b/src/Web/MeAjudaAi.Web.Admin-React/src/lib/api/generated/index.ts new file mode 100644 index 000000000..7c947e55d --- /dev/null +++ b/src/Web/MeAjudaAi.Web.Admin-React/src/lib/api/generated/index.ts @@ -0,0 +1,4 @@ +// This file is auto-generated by @hey-api/openapi-ts + +export { apiActivatePost, apiActivatePost2, apiActivatePost3, apiAllowedCitiesDelete, apiAllowedCitiesGet, apiAllowedCitiesGet2, apiAllowedCitiesPatch, apiAllowedCitiesPost, apiAllowedCitiesPut, apiBecomePost, apiByCityGet, apiByEmailGet, apiByStateGet, apiByTypeGet, apiByUserGet, apiCategoriesDelete, apiCategoriesGet, apiCategoriesGet2, apiCategoriesPost, apiCategoriesPut, apiCategoryGet, apiChangeCategoryPost, apiClientGet, apiCspReportPost, apiDeactivatePost, apiDeactivatePost2, apiDeactivatePost3, apiDocumentsDelete, apiDocumentsPost, apiDocumentsPost2, apiMeGet, apiMePut, apiProfilePut, apiProviderGet, apiProvidersDelete, apiProvidersGet, apiProvidersGet2, apiProvidersGet3, apiProvidersGet4, apiProvidersPost, apiProvidersPut, apiPublicGet, apiRegisterPost, apiRegisterPost2, apiRequestVerificationPost, apiRequireBasicInfoCorrectionPost, apiSearchGet, apiServicesDelete, apiServicesDelete2, apiServicesGet, apiServicesGet2, apiServicesPost, apiServicesPost2, apiServicesPut, apiStatusGet, apiStatusGet2, apiUploadPost, apiUsersDelete, apiUsersGet, apiUsersGet2, apiUsersPost, apiValidatePost, apiVerificationStatusGet, apiVerificationStatusPut, apiVerifyPost, type Options } from './sdk.gen'; +export type { ApiActivatePost2Data, ApiActivatePost2Response, ApiActivatePost2Responses, ApiActivatePost3Data, ApiActivatePost3Response, ApiActivatePost3Responses, ApiActivatePostData, ApiActivatePostErrors, ApiActivatePostResponse, ApiActivatePostResponses, ApiAllowedCitiesDeleteData, ApiAllowedCitiesDeleteErrors, ApiAllowedCitiesDeleteResponse, ApiAllowedCitiesDeleteResponses, ApiAllowedCitiesGet2Data, ApiAllowedCitiesGet2Errors, ApiAllowedCitiesGet2Response, ApiAllowedCitiesGet2Responses, ApiAllowedCitiesGetData, ApiAllowedCitiesGetResponse, ApiAllowedCitiesGetResponses, ApiAllowedCitiesPatchData, ApiAllowedCitiesPatchError, ApiAllowedCitiesPatchErrors, ApiAllowedCitiesPatchResponse, ApiAllowedCitiesPatchResponses, ApiAllowedCitiesPostData, ApiAllowedCitiesPostError, ApiAllowedCitiesPostErrors, ApiAllowedCitiesPostResponse, ApiAllowedCitiesPostResponses, ApiAllowedCitiesPutData, ApiAllowedCitiesPutErrors, ApiAllowedCitiesPutResponse, ApiAllowedCitiesPutResponses, ApiBecomePostData, ApiBecomePostError, ApiBecomePostErrors, ApiBecomePostResponse, ApiBecomePostResponses, ApiByCityGetData, ApiByCityGetErrors, ApiByCityGetResponse, ApiByCityGetResponses, ApiByEmailGetData, ApiByEmailGetErrors, ApiByEmailGetResponse, ApiByEmailGetResponses, ApiByStateGetData, ApiByStateGetErrors, ApiByStateGetResponse, ApiByStateGetResponses, ApiByTypeGetData, ApiByTypeGetErrors, ApiByTypeGetResponse, ApiByTypeGetResponses, ApiByUserGetData, ApiByUserGetErrors, ApiByUserGetResponse, ApiByUserGetResponses, ApiCategoriesDeleteData, ApiCategoriesDeleteResponse, ApiCategoriesDeleteResponses, ApiCategoriesGet2Data, ApiCategoriesGet2Errors, ApiCategoriesGet2Response, ApiCategoriesGet2Responses, ApiCategoriesGetData, ApiCategoriesGetResponse, ApiCategoriesGetResponses, ApiCategoriesPostData, ApiCategoriesPostResponse, ApiCategoriesPostResponses, ApiCategoriesPutData, ApiCategoriesPutResponse, ApiCategoriesPutResponses, ApiCategoryGetData, ApiCategoryGetResponse, ApiCategoryGetResponses, ApiChangeCategoryPostData, ApiChangeCategoryPostResponse, ApiChangeCategoryPostResponses, ApiClientGetData, ApiClientGetResponse, ApiClientGetResponses, ApiCspReportPostData, ApiCspReportPostResponses, ApiDeactivatePost2Data, ApiDeactivatePost2Response, ApiDeactivatePost2Responses, ApiDeactivatePost3Data, ApiDeactivatePost3Response, ApiDeactivatePost3Responses, ApiDeactivatePostData, ApiDeactivatePostErrors, ApiDeactivatePostResponse, ApiDeactivatePostResponses, ApiDocumentsDeleteData, ApiDocumentsDeleteErrors, ApiDocumentsDeleteResponse, ApiDocumentsDeleteResponses, ApiDocumentsPost2Data, ApiDocumentsPost2Errors, ApiDocumentsPost2Response, ApiDocumentsPost2Responses, ApiDocumentsPostData, ApiDocumentsPostErrors, ApiDocumentsPostResponse, ApiDocumentsPostResponses, ApiMeGetData, ApiMeGetErrors, ApiMeGetResponse, ApiMeGetResponses, ApiMePutData, ApiMePutErrors, ApiMePutResponse, ApiMePutResponses, ApiProfilePutData, ApiProfilePutErrors, ApiProfilePutResponse, ApiProfilePutResponses, ApiProviderGetData, ApiProviderGetResponse, ApiProviderGetResponses, ApiProvidersDeleteData, ApiProvidersDeleteErrors, ApiProvidersDeleteResponse, ApiProvidersDeleteResponses, ApiProvidersGet2Data, ApiProvidersGet2Error, ApiProvidersGet2Errors, ApiProvidersGet2Response, ApiProvidersGet2Responses, ApiProvidersGet3Data, ApiProvidersGet3Errors, ApiProvidersGet3Response, ApiProvidersGet3Responses, ApiProvidersGet4Data, ApiProvidersGet4Error, ApiProvidersGet4Errors, ApiProvidersGet4Response, ApiProvidersGet4Responses, ApiProvidersGetData, ApiProvidersGetResponses, ApiProvidersPostData, ApiProvidersPostErrors, ApiProvidersPostResponse, ApiProvidersPostResponses, ApiProvidersPutData, ApiProvidersPutErrors, ApiProvidersPutResponse, ApiProvidersPutResponses, ApiPublicGetData, ApiPublicGetErrors, ApiPublicGetResponse, ApiPublicGetResponses, ApiRegisterPost2Data, ApiRegisterPost2Responses, ApiRegisterPostData, ApiRegisterPostErrors, ApiRegisterPostResponse, ApiRegisterPostResponses, ApiRequestVerificationPostData, ApiRequestVerificationPostError, ApiRequestVerificationPostErrors, ApiRequestVerificationPostResponses, ApiRequireBasicInfoCorrectionPostData, ApiRequireBasicInfoCorrectionPostErrors, ApiRequireBasicInfoCorrectionPostResponses, ApiSearchGetData, ApiSearchGetResponse, ApiSearchGetResponses, ApiServicesDelete2Data, ApiServicesDelete2Response, ApiServicesDelete2Responses, ApiServicesDeleteData, ApiServicesDeleteErrors, ApiServicesDeleteResponse, ApiServicesDeleteResponses, ApiServicesGet2Data, ApiServicesGet2Errors, ApiServicesGet2Response, ApiServicesGet2Responses, ApiServicesGetData, ApiServicesGetResponse, ApiServicesGetResponses, ApiServicesPost2Data, ApiServicesPost2Response, ApiServicesPost2Responses, ApiServicesPostData, ApiServicesPostErrors, ApiServicesPostResponse, ApiServicesPostResponses, ApiServicesPutData, ApiServicesPutResponse, ApiServicesPutResponses, ApiStatusGet2Data, ApiStatusGet2Errors, ApiStatusGet2Response, ApiStatusGet2Responses, ApiStatusGetData, ApiStatusGetErrors, ApiStatusGetResponse, ApiStatusGetResponses, ApiUploadPostData, ApiUploadPostErrors, ApiUploadPostResponse, ApiUploadPostResponses, ApiUsersDeleteData, ApiUsersDeleteErrors, ApiUsersDeleteResponse, ApiUsersDeleteResponses, ApiUsersGet2Data, ApiUsersGet2Errors, ApiUsersGet2Response, ApiUsersGet2Responses, ApiUsersGetData, ApiUsersGetError, ApiUsersGetErrors, ApiUsersGetResponse, ApiUsersGetResponses, ApiUsersPostData, ApiUsersPostErrors, ApiUsersPostResponse, ApiUsersPostResponses, ApiValidatePostData, ApiValidatePostResponse, ApiValidatePostResponses, ApiVerificationStatusGetData, ApiVerificationStatusGetError, ApiVerificationStatusGetErrors, ApiVerificationStatusGetResponse, ApiVerificationStatusGetResponses, ApiVerificationStatusPutData, ApiVerificationStatusPutErrors, ApiVerificationStatusPutResponse, ApiVerificationStatusPutResponses, ApiVerifyPostData, ApiVerifyPostErrors, ApiVerifyPostResponses, ClientOptions, MeAjudaAiContractsConfigurationClientConfiguration, MeAjudaAiContractsConfigurationExternalResources, MeAjudaAiContractsConfigurationFeatureFlags, MeAjudaAiContractsConfigurationKeycloakConfiguration, MeAjudaAiContractsContractsModulesLocationsDtosCreateAllowedCityRequestDto, MeAjudaAiContractsContractsModulesLocationsDtosLocationCandidate, MeAjudaAiContractsContractsModulesLocationsDtosModuleAllowedCityDto, MeAjudaAiContractsContractsModulesLocationsDtosPatchAllowedCityRequestDto, MeAjudaAiContractsFunctionalError, MeAjudaAiContractsFunctionalResult, MeAjudaAiContractsFunctionalResult1MeAjudaAiContractsFunctionalUnit_MeAjudaAiContracts_Version_0000_Culture_neutral_PublicKeyToken_null, MeAjudaAiContractsFunctionalResult1MeAjudaAiContractsFunctionalUnit_MeAjudaAiContracts_Version_0000_Culture_neutral_PublicKeyToken_nullWritable, MeAjudaAiContractsFunctionalResult1SystemCollectionsGenericIReadOnlyList1MeAjudaAiContractsContractsModulesLocationsDtosModuleAllowedCityDto_MeAjudaAiContracts_Version_0000_Culture_neutral_PublicKeyToken_null___SystemPrivateCoreLib_Version_10000_Culture_neutral_PublicKeyToken_7Cec85D7Bea7798E, MeAjudaAiContractsFunctionalResult1SystemCollectionsGenericIReadOnlyList1MeAjudaAiContractsContractsModulesLocationsDtosModuleAllowedCityDto_MeAjudaAiContracts_Version_0000_Culture_neutral_PublicKeyToken_null___SystemPrivateCoreLib_Version_10000_Culture_neutral_PublicKeyToken_7Cec85D7Bea7798EWritable, MeAjudaAiContractsFunctionalResultWritable, MeAjudaAiContractsFunctionalUnit, MeAjudaAiContractsModelsAllowedCity, MeAjudaAiContractsModelsAuthenticationErrorResponse, MeAjudaAiContractsModelsAuthorizationErrorResponse, MeAjudaAiContractsModelsGeographicRestrictionErrorResponse, MeAjudaAiContractsModelsInternalServerErrorResponse, MeAjudaAiContractsModelsPagedResponse1SystemCollectionsGenericIEnumerable1MeAjudaAiModulesProvidersApplicationDtosProviderDto_MeAjudaAiModulesProvidersApplication_Version_0000_Culture_neutral_PublicKeyToken_null___SystemPrivateCoreLib_Version_10000_Culture_neutral_PublicKeyToken_7Cec85D7Bea7798E, MeAjudaAiContractsModelsPagedResponse1SystemCollectionsGenericIEnumerable1MeAjudaAiModulesProvidersApplicationDtosProviderDto_MeAjudaAiModulesProvidersApplication_Version_0000_Culture_neutral_PublicKeyToken_null___SystemPrivateCoreLib_Version_10000_Culture_neutral_PublicKeyToken_7Cec85D7Bea7798EWritable, MeAjudaAiContractsModelsPagedResponse1SystemCollectionsGenericIEnumerable1MeAjudaAiModulesUsersApplicationDtosUserDto_MeAjudaAiModulesUsersApplication_Version_0000_Culture_neutral_PublicKeyToken_null___SystemPrivateCoreLib_Version_10000_Culture_neutral_PublicKeyToken_7Cec85D7Bea7798E, MeAjudaAiContractsModelsPagedResponse1SystemCollectionsGenericIEnumerable1MeAjudaAiModulesUsersApplicationDtosUserDto_MeAjudaAiModulesUsersApplication_Version_0000_Culture_neutral_PublicKeyToken_null___SystemPrivateCoreLib_Version_10000_Culture_neutral_PublicKeyToken_7Cec85D7Bea7798EWritable, MeAjudaAiContractsModelsPagedResult1MeAjudaAiModulesSearchProvidersApplicationDtosSearchableProviderDto_MeAjudaAiModulesSearchProvidersApplication_Version_0000_Culture_neutral_PublicKeyToken_null, MeAjudaAiContractsModelsPagedResult1MeAjudaAiModulesSearchProvidersApplicationDtosSearchableProviderDto_MeAjudaAiModulesSearchProvidersApplication_Version_0000_Culture_neutral_PublicKeyToken_nullWritable, MeAjudaAiContractsModelsRateLimitErrorResponse, MeAjudaAiContractsModelsResponse1MeAjudaAiModulesLocationsApplicationDtosAllowedCityDto_MeAjudaAiModulesLocationsApplication_Version_0000_Culture_neutral_PublicKeyToken_null, MeAjudaAiContractsModelsResponse1MeAjudaAiModulesLocationsApplicationDtosAllowedCityDto_MeAjudaAiModulesLocationsApplication_Version_0000_Culture_neutral_PublicKeyToken_nullWritable, MeAjudaAiContractsModelsResponse1MeAjudaAiModulesProvidersApplicationDtosProviderDto_MeAjudaAiModulesProvidersApplication_Version_0000_Culture_neutral_PublicKeyToken_null, MeAjudaAiContractsModelsResponse1MeAjudaAiModulesProvidersApplicationDtosProviderDto_MeAjudaAiModulesProvidersApplication_Version_0000_Culture_neutral_PublicKeyToken_nullWritable, MeAjudaAiContractsModelsResponse1MeAjudaAiModulesProvidersApplicationDtosProviderStatusDto_MeAjudaAiModulesProvidersApplication_Version_0000_Culture_neutral_PublicKeyToken_null, MeAjudaAiContractsModelsResponse1MeAjudaAiModulesProvidersApplicationDtosProviderStatusDto_MeAjudaAiModulesProvidersApplication_Version_0000_Culture_neutral_PublicKeyToken_nullWritable, MeAjudaAiContractsModelsResponse1MeAjudaAiModulesProvidersApplicationDtosPublicProviderDto_MeAjudaAiModulesProvidersApplication_Version_0000_Culture_neutral_PublicKeyToken_null, MeAjudaAiContractsModelsResponse1MeAjudaAiModulesProvidersApplicationDtosPublicProviderDto_MeAjudaAiModulesProvidersApplication_Version_0000_Culture_neutral_PublicKeyToken_nullWritable, MeAjudaAiContractsModelsResponse1MeAjudaAiModulesServiceCatalogsApplicationDtosRequestsServiceValidateServicesResponse_MeAjudaAiModulesServiceCatalogsApplication_Version_0000_Culture_neutral_PublicKeyToken_null, MeAjudaAiContractsModelsResponse1MeAjudaAiModulesServiceCatalogsApplicationDtosRequestsServiceValidateServicesResponse_MeAjudaAiModulesServiceCatalogsApplication_Version_0000_Culture_neutral_PublicKeyToken_nullWritable, MeAjudaAiContractsModelsResponse1MeAjudaAiModulesServiceCatalogsApplicationDtosServiceCategoryDto_MeAjudaAiModulesServiceCatalogsApplication_Version_0000_Culture_neutral_PublicKeyToken_null, MeAjudaAiContractsModelsResponse1MeAjudaAiModulesServiceCatalogsApplicationDtosServiceCategoryDto_MeAjudaAiModulesServiceCatalogsApplication_Version_0000_Culture_neutral_PublicKeyToken_nullWritable, MeAjudaAiContractsModelsResponse1MeAjudaAiModulesServiceCatalogsApplicationDtosServiceDto_MeAjudaAiModulesServiceCatalogsApplication_Version_0000_Culture_neutral_PublicKeyToken_null, MeAjudaAiContractsModelsResponse1MeAjudaAiModulesServiceCatalogsApplicationDtosServiceDto_MeAjudaAiModulesServiceCatalogsApplication_Version_0000_Culture_neutral_PublicKeyToken_nullWritable, MeAjudaAiContractsModelsResponse1MeAjudaAiModulesUsersApplicationDtosUserDto_MeAjudaAiModulesUsersApplication_Version_0000_Culture_neutral_PublicKeyToken_null, MeAjudaAiContractsModelsResponse1MeAjudaAiModulesUsersApplicationDtosUserDto_MeAjudaAiModulesUsersApplication_Version_0000_Culture_neutral_PublicKeyToken_nullWritable, MeAjudaAiContractsModelsResponse1SystemCollectionsGenericIReadOnlyList1MeAjudaAiModulesProvidersApplicationDtosProviderDto_MeAjudaAiModulesProvidersApplication_Version_0000_Culture_neutral_PublicKeyToken_null___SystemPrivateCoreLib_Version_10000_Culture_neutral_PublicKeyToken_7Cec85D7Bea7798E, MeAjudaAiContractsModelsResponse1SystemCollectionsGenericIReadOnlyList1MeAjudaAiModulesProvidersApplicationDtosProviderDto_MeAjudaAiModulesProvidersApplication_Version_0000_Culture_neutral_PublicKeyToken_null___SystemPrivateCoreLib_Version_10000_Culture_neutral_PublicKeyToken_7Cec85D7Bea7798EWritable, MeAjudaAiContractsModelsResponse1SystemCollectionsGenericIReadOnlyList1MeAjudaAiModulesServiceCatalogsApplicationDtosServiceCategoryDto_MeAjudaAiModulesServiceCatalogsApplication_Version_0000_Culture_neutral_PublicKeyToken_null___SystemPrivateCoreLib_Version_10000_Culture_neutral_PublicKeyToken_7Cec85D7Bea7798E, MeAjudaAiContractsModelsResponse1SystemCollectionsGenericIReadOnlyList1MeAjudaAiModulesServiceCatalogsApplicationDtosServiceCategoryDto_MeAjudaAiModulesServiceCatalogsApplication_Version_0000_Culture_neutral_PublicKeyToken_null___SystemPrivateCoreLib_Version_10000_Culture_neutral_PublicKeyToken_7Cec85D7Bea7798EWritable, MeAjudaAiContractsModelsResponse1SystemCollectionsGenericIReadOnlyList1MeAjudaAiModulesServiceCatalogsApplicationDtosServiceListDto_MeAjudaAiModulesServiceCatalogsApplication_Version_0000_Culture_neutral_PublicKeyToken_null___SystemPrivateCoreLib_Version_10000_Culture_neutral_PublicKeyToken_7Cec85D7Bea7798E, MeAjudaAiContractsModelsResponse1SystemCollectionsGenericIReadOnlyList1MeAjudaAiModulesServiceCatalogsApplicationDtosServiceListDto_MeAjudaAiModulesServiceCatalogsApplication_Version_0000_Culture_neutral_PublicKeyToken_null___SystemPrivateCoreLib_Version_10000_Culture_neutral_PublicKeyToken_7Cec85D7Bea7798EWritable, MeAjudaAiContractsModelsResponse1SystemGuid_SystemPrivateCoreLib_Version_10000_Culture_neutral_PublicKeyToken_7Cec85D7Bea7798E, MeAjudaAiContractsModelsResponse1SystemGuid_SystemPrivateCoreLib_Version_10000_Culture_neutral_PublicKeyToken_7Cec85D7Bea7798EWritable, MeAjudaAiContractsModelsResponse1SystemObject_SystemPrivateCoreLib_Version_10000_Culture_neutral_PublicKeyToken_7Cec85D7Bea7798E, MeAjudaAiContractsModelsResponse1SystemObject_SystemPrivateCoreLib_Version_10000_Culture_neutral_PublicKeyToken_7Cec85D7Bea7798EWritable, MeAjudaAiContractsModelsUserLocation, MeAjudaAiModulesDocumentsApplicationDtosDocumentDto, MeAjudaAiModulesDocumentsApplicationDtosRequestsUploadDocumentRequest, MeAjudaAiModulesDocumentsApplicationDtosRequestsVerifyDocumentRequest, MeAjudaAiModulesDocumentsApplicationDtosUploadDocumentResponse, MeAjudaAiModulesLocationsApplicationDtosAllowedCityDto, MeAjudaAiModulesLocationsApplicationDtosRequestsUpdateAllowedCityRequest, MeAjudaAiModulesProvidersApiEndpointsPublicRegisterProviderApiRequest, MeAjudaAiModulesProvidersApplicationDtosAddressDto, MeAjudaAiModulesProvidersApplicationDtosBusinessProfileDto, MeAjudaAiModulesProvidersApplicationDtosContactInfoDto, MeAjudaAiModulesProvidersApplicationDtosDocumentDto, MeAjudaAiModulesProvidersApplicationDtosProviderDto, MeAjudaAiModulesProvidersApplicationDtosProviderServiceDto, MeAjudaAiModulesProvidersApplicationDtosProviderStatusDto, MeAjudaAiModulesProvidersApplicationDtosPublicProviderDto, MeAjudaAiModulesProvidersApplicationDtosQualificationDto, MeAjudaAiModulesProvidersApplicationDtosRequestsAddDocumentRequest, MeAjudaAiModulesProvidersApplicationDtosRequestsCreateProviderRequest, MeAjudaAiModulesProvidersApplicationDtosRequestsRegisterProviderRequest, MeAjudaAiModulesProvidersApplicationDtosRequestsRequireBasicInfoCorrectionRequest, MeAjudaAiModulesProvidersApplicationDtosRequestsUpdateProviderProfileRequest, MeAjudaAiModulesProvidersApplicationDtosRequestsUpdateVerificationStatusRequest, MeAjudaAiModulesSearchProvidersApplicationDtosLocationDto, MeAjudaAiModulesSearchProvidersApplicationDtosSearchableProviderDto, MeAjudaAiModulesServiceCatalogsApiEndpointsServiceCategoryCreateServiceCategoryRequest, MeAjudaAiModulesServiceCatalogsApiEndpointsServiceCategoryUpdateServiceCategoryRequest, MeAjudaAiModulesServiceCatalogsApplicationDtosRequestsServiceChangeServiceCategoryRequest, MeAjudaAiModulesServiceCatalogsApplicationDtosRequestsServiceCreateServiceRequest, MeAjudaAiModulesServiceCatalogsApplicationDtosRequestsServiceUpdateServiceRequest, MeAjudaAiModulesServiceCatalogsApplicationDtosRequestsServiceValidateServicesRequest, MeAjudaAiModulesServiceCatalogsApplicationDtosRequestsServiceValidateServicesResponse, MeAjudaAiModulesServiceCatalogsApplicationDtosServiceCategoryDto, MeAjudaAiModulesServiceCatalogsApplicationDtosServiceDto, MeAjudaAiModulesServiceCatalogsApplicationDtosServiceListDto, MeAjudaAiModulesUsersApiEndpointsPublicRegisterCustomerRequest, MeAjudaAiModulesUsersApplicationDtosRequestsCreateUserRequest, MeAjudaAiModulesUsersApplicationDtosRequestsUpdateUserProfileRequest, MeAjudaAiModulesUsersApplicationDtosUserDto, MicrosoftAspNetCoreHttpHttpValidationProblemDetails, MicrosoftAspNetCoreMvcProblemDetails } from './types.gen'; diff --git a/src/Web/MeAjudaAi.Web.Admin-React/src/lib/api/generated/sdk.gen.ts b/src/Web/MeAjudaAi.Web.Admin-React/src/lib/api/generated/sdk.gen.ts new file mode 100644 index 000000000..69591ded0 --- /dev/null +++ b/src/Web/MeAjudaAi.Web.Admin-React/src/lib/api/generated/sdk.gen.ts @@ -0,0 +1,1015 @@ +// This file is auto-generated by @hey-api/openapi-ts + +import type { Client, Options as Options2, TDataShape } from './client'; +import { client } from './client.gen'; +import type { ApiActivatePost2Data, ApiActivatePost2Responses, ApiActivatePost3Data, ApiActivatePost3Responses, ApiActivatePostData, ApiActivatePostErrors, ApiActivatePostResponses, ApiAllowedCitiesDeleteData, ApiAllowedCitiesDeleteErrors, ApiAllowedCitiesDeleteResponses, ApiAllowedCitiesGet2Data, ApiAllowedCitiesGet2Errors, ApiAllowedCitiesGet2Responses, ApiAllowedCitiesGetData, ApiAllowedCitiesGetResponses, ApiAllowedCitiesPatchData, ApiAllowedCitiesPatchErrors, ApiAllowedCitiesPatchResponses, ApiAllowedCitiesPostData, ApiAllowedCitiesPostErrors, ApiAllowedCitiesPostResponses, ApiAllowedCitiesPutData, ApiAllowedCitiesPutErrors, ApiAllowedCitiesPutResponses, ApiBecomePostData, ApiBecomePostErrors, ApiBecomePostResponses, ApiByCityGetData, ApiByCityGetErrors, ApiByCityGetResponses, ApiByEmailGetData, ApiByEmailGetErrors, ApiByEmailGetResponses, ApiByStateGetData, ApiByStateGetErrors, ApiByStateGetResponses, ApiByTypeGetData, ApiByTypeGetErrors, ApiByTypeGetResponses, ApiByUserGetData, ApiByUserGetErrors, ApiByUserGetResponses, ApiCategoriesDeleteData, ApiCategoriesDeleteResponses, ApiCategoriesGet2Data, ApiCategoriesGet2Errors, ApiCategoriesGet2Responses, ApiCategoriesGetData, ApiCategoriesGetResponses, ApiCategoriesPostData, ApiCategoriesPostResponses, ApiCategoriesPutData, ApiCategoriesPutResponses, ApiCategoryGetData, ApiCategoryGetResponses, ApiChangeCategoryPostData, ApiChangeCategoryPostResponses, ApiClientGetData, ApiClientGetResponses, ApiCspReportPostData, ApiCspReportPostResponses, ApiDeactivatePost2Data, ApiDeactivatePost2Responses, ApiDeactivatePost3Data, ApiDeactivatePost3Responses, ApiDeactivatePostData, ApiDeactivatePostErrors, ApiDeactivatePostResponses, ApiDocumentsDeleteData, ApiDocumentsDeleteErrors, ApiDocumentsDeleteResponses, ApiDocumentsPost2Data, ApiDocumentsPost2Errors, ApiDocumentsPost2Responses, ApiDocumentsPostData, ApiDocumentsPostErrors, ApiDocumentsPostResponses, ApiMeGetData, ApiMeGetErrors, ApiMeGetResponses, ApiMePutData, ApiMePutErrors, ApiMePutResponses, ApiProfilePutData, ApiProfilePutErrors, ApiProfilePutResponses, ApiProviderGetData, ApiProviderGetResponses, ApiProvidersDeleteData, ApiProvidersDeleteErrors, ApiProvidersDeleteResponses, ApiProvidersGet2Data, ApiProvidersGet2Errors, ApiProvidersGet2Responses, ApiProvidersGet3Data, ApiProvidersGet3Errors, ApiProvidersGet3Responses, ApiProvidersGet4Data, ApiProvidersGet4Errors, ApiProvidersGet4Responses, ApiProvidersGetData, ApiProvidersGetResponses, ApiProvidersPostData, ApiProvidersPostErrors, ApiProvidersPostResponses, ApiProvidersPutData, ApiProvidersPutErrors, ApiProvidersPutResponses, ApiPublicGetData, ApiPublicGetErrors, ApiPublicGetResponses, ApiRegisterPost2Data, ApiRegisterPost2Responses, ApiRegisterPostData, ApiRegisterPostErrors, ApiRegisterPostResponses, ApiRequestVerificationPostData, ApiRequestVerificationPostErrors, ApiRequestVerificationPostResponses, ApiRequireBasicInfoCorrectionPostData, ApiRequireBasicInfoCorrectionPostErrors, ApiRequireBasicInfoCorrectionPostResponses, ApiSearchGetData, ApiSearchGetResponses, ApiServicesDelete2Data, ApiServicesDelete2Responses, ApiServicesDeleteData, ApiServicesDeleteErrors, ApiServicesDeleteResponses, ApiServicesGet2Data, ApiServicesGet2Errors, ApiServicesGet2Responses, ApiServicesGetData, ApiServicesGetResponses, ApiServicesPost2Data, ApiServicesPost2Responses, ApiServicesPostData, ApiServicesPostErrors, ApiServicesPostResponses, ApiServicesPutData, ApiServicesPutResponses, ApiStatusGet2Data, ApiStatusGet2Errors, ApiStatusGet2Responses, ApiStatusGetData, ApiStatusGetErrors, ApiStatusGetResponses, ApiUploadPostData, ApiUploadPostErrors, ApiUploadPostResponses, ApiUsersDeleteData, ApiUsersDeleteErrors, ApiUsersDeleteResponses, ApiUsersGet2Data, ApiUsersGet2Errors, ApiUsersGet2Responses, ApiUsersGetData, ApiUsersGetErrors, ApiUsersGetResponses, ApiUsersPostData, ApiUsersPostErrors, ApiUsersPostResponses, ApiValidatePostData, ApiValidatePostResponses, ApiVerificationStatusGetData, ApiVerificationStatusGetErrors, ApiVerificationStatusGetResponses, ApiVerificationStatusPutData, ApiVerificationStatusPutErrors, ApiVerificationStatusPutResponses, ApiVerifyPostData, ApiVerifyPostErrors, ApiVerifyPostResponses } from './types.gen'; + +export type Options = Options2 & { + /** + * You can provide a client instance returned by `createClient()` instead of + * individual options. This might be also useful if you want to implement a + * custom client. + */ + client?: Client; + /** + * You can pass arbitrary values through the `meta` object. This can be + * used to access values that aren't defined as part of the SDK function. + */ + meta?: Record; +}; + +/** + * Listar todas as cidades permitidas + * + * Recupera todas as cidades permitidas (opcionalmente apenas as ativas) + */ +export const apiAllowedCitiesGet = (options?: Options) => (options?.client ?? client).get({ url: '/api/v1/admin/allowed-cities', ...options }); + +/** + * Criar nova cidade permitida + * + * Cria uma nova cidade permitida para operaƧƵes de prestadores (apenas Admin) + */ +export const apiAllowedCitiesPost = (options: Options) => (options.client ?? client).post({ + url: '/api/v1/admin/allowed-cities', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options.headers + } +}); + +/** + * Deletar cidade permitida + * + * Deleta uma cidade permitida + */ +export const apiAllowedCitiesDelete = (options: Options) => (options.client ?? client).delete({ url: '/api/v1/admin/allowed-cities/{id}', ...options }); + +/** + * Buscar cidade permitida por ID + * + * Recupera uma cidade permitida especĆ­fica pelo seu ID + */ +export const apiAllowedCitiesGet2 = (options: Options) => (options.client ?? client).get({ url: '/api/v1/admin/allowed-cities/{id}', ...options }); + +/** + * Atualizar parcialmente cidade permitida + * + * Atualiza campos especĆ­ficos de uma cidade permitida (Raio, Ativo) + */ +export const apiAllowedCitiesPatch = (options: Options) => (options.client ?? client).patch({ + url: '/api/v1/admin/allowed-cities/{id}', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options.headers + } +}); + +/** + * Atualizar cidade permitida + * + * Atualiza uma cidade permitida existente + */ +export const apiAllowedCitiesPut = (options: Options) => (options.client ?? client).put({ + url: '/api/v1/admin/allowed-cities/{id}', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options.headers + } +}); + +/** + * Lista os provedores de identidade social disponĆ­veis. + */ +export const apiProvidersGet = (options?: Options) => (options?.client ?? client).get({ url: '/api/v1/users/auth/providers', ...options }); + +/** + * Retorna a configuração do cliente. + * Apenas informaƧƵes nĆ£o-sensĆ­veis sĆ£o expostas. + * + * Retorna configuraƧƵes nĆ£o-sensĆ­veis necessĆ”rias para o frontend (Keycloak, URLs, feature flags) + */ +export const apiClientGet = (options?: Options) => (options?.client ?? client).get({ url: '/api/configuration/client', ...options }); + +/** + * Gerar URL de upload com SAS token + * + * Gera uma URL de upload com SAS token para envio direto ao Azure Blob Storage. + * + * **Fluxo:** + * 1. Valida informaƧƵes do documento + * 2. Gera SAS token com 1 hora de validade + * 3. Cria registro de documento no banco com status Uploaded + * 4. Retorna URL de upload (com blob name e data de expiração) + * + * **Tipos de documentos suportados:** + * - IdentityDocument: RG, CNH, CPF + * - ProofOfResidence: Comprovante de residĆŖncia + * - CriminalRecord: CertidĆ£o de antecedentes + * - Other: Outros documentos + */ +export const apiUploadPost = (options: Options) => (options.client ?? client).post({ + url: '/api/v1/documents/upload', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options.headers + } +}); + +/** + * Consultar status de documento + * + * Retorna informaƧƵes detalhadas sobre um documento especĆ­fico. + * + * **InformaƧƵes retornadas:** + * - Status atual (Uploaded, PendingVerification, Verified, Rejected, Failed) + * - Datas de upload e verificação + * - Motivo de rejeição (se aplicĆ”vel) + * - Dados extraĆ­dos por OCR (se disponĆ­vel) + * - URLs de acesso ao documento + */ +export const apiStatusGet = (options: Options) => (options.client ?? client).get({ url: '/api/v1/documents/{documentId}/status', ...options }); + +/** + * Listar documentos de um prestador + * + * Retorna todos os documentos associados a um prestador especĆ­fico. + * + * **Casos de uso:** + * - Visualizar todos os documentos enviados + * - Verificar status de verificação de documentos + * - Acompanhar progresso de validação de cadastro + */ +export const apiProviderGet = (options: Options) => (options.client ?? client).get({ url: '/api/v1/documents/provider/{providerId}', ...options }); + +/** + * Solicitar verificação manual + * + * Solicita verificação manual de um documento quando OCR falha ou precisa validação adicional. + * + * **Quando usar:** + * - OCR nĆ£o conseguiu extrair dados do documento + * - Documento foi rejeitado automaticamente mas precisa revisĆ£o + * - Necessidade de validação humana adicional + * + * **Resultado:** + * - Documento entra em fila de verificação manual + * - Status alterado para PendingVerification + * - Administrador serĆ” notificado para anĆ”lise + */ +export const apiRequestVerificationPost = (options: Options) => (options.client ?? client).post({ url: '/api/v1/documents/{documentId}/request-verification', ...options }); + +/** + * Aprovar ou rejeitar documento + * + * Aprova ou rejeita um documento após verificação manual. + * + * **Aprovar documento:** + * ```json + * { + * "IsVerified": true, + * "VerificationNotes": "Documento vĆ”lido e legĆ­vel" + * } + * ``` + * + * **Rejeitar documento:** + * ```json + * { + * "IsVerified": false, + * "VerificationNotes": "Documento ilegĆ­vel ou invĆ”lido" + * } + * ``` + * + * **Requisitos:** + * - Documento deve estar em status PendingVerification + * - Apenas administradores podem executar esta ação + */ +export const apiVerifyPost = (options: Options) => (options.client ?? client).post({ + url: '/api/v1/documents/{documentId}/verify', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options.headers + } +}); + +/** + * Busca cidades/endereƧos para cadastro + * + * Retorna candidatos de localização baseados na query + */ +export const apiSearchGet = (options: Options) => (options.client ?? client).get({ url: '/api/v1/locations/search', ...options }); + +/** + * Consultar prestadores paginados + * + * Recupera uma lista paginada de prestadores de serviƧos do sistema com suporte a filtros de busca. + * + * **CaracterĆ­sticas:** + * - šŸ” Busca por nome, tipo de serviƧo e status de verificação + * - šŸ“„ Paginação otimizada com metadados + * - ⚔ Cache automĆ”tico para consultas frequentes + * - šŸ”’ Controle de acesso baseado em papĆ©is + * - šŸŒ Restrição geogrĆ”fica (piloto em cidades especĆ­ficas) + * + * **Restrição geogrĆ”fica (HTTP 451):** + * + * Este endpoint estĆ” sujeito a restriƧƵes geogrĆ”ficas durante a fase piloto. + * O acesso Ć© permitido apenas para usuĆ”rios nas seguintes cidades: + * + * - **MuriaĆ©** (MG) - IBGE: 3143906 + * - **Itaperuna** (RJ) - IBGE: 3302205 + * - **Linhares** (ES) - IBGE: 3203205 + * + * A localização Ć© determinada atravĆ©s dos headers HTTP: + * - `X-User-City`: Nome da cidade + * - `X-User-State`: Sigla do estado (UF) + * - `X-User-Location`: Combinação "cidade|estado" + * + * Se o acesso for bloqueado, vocĆŖ receberĆ” HTTP 451 com detalhes: + * - Sua localização detectada + * - Lista de cidades permitidas + * - Códigos IBGE para validação + * + * **ParĆ¢metros de busca:** + * - `name`: Termo para filtrar prestadores por nome + * - `type`: Filtro por tipo de serviƧo (ID numĆ©rico) + * - `verificationStatus`: Status de verificação (ID numĆ©rico) + * - `pageNumber`: NĆŗmero da pĆ”gina (padrĆ£o: 1) + * - `pageSize`: Tamanho da pĆ”gina (padrĆ£o: 10, mĆ”ximo: 100) + * + * **Exemplos de uso:** + * - Buscar prestadores: `?name=joĆ£o` + * - Por tipo: `?type=1` + * - Por status: `?verificationStatus=2` + * - Paginação: `?pageNumber=2&pageSize=20` + * - Combinado: `?name=mĆ©dico&type=1&pageNumber=1&pageSize=10` + */ +export const apiProvidersGet2 = (options?: Options) => (options?.client ?? client).get({ url: '/api/v1/providers', ...options }); + +/** + * Processa requisição de criação de prestador de forma assĆ­ncrona. + * + * Fluxo de execução: + * 1. Converte request em comando CQRS + * 2. Envia comando atravĆ©s do dispatcher + * 3. Processa resultado e retorna resposta HTTP apropriada + * 4. Inclui localização do recurso criado no header + */ +export const apiProvidersPost = (options: Options) => (options.client ?? client).post({ + url: '/api/v1/providers', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options.headers + } +}); + +/** + * Processa requisição de exclusĆ£o de prestador de forma assĆ­ncrona. + * + * Fluxo de execução: + * 1. Valida ID do prestador e autorização administrativa + * 2. Cria comando usando mapper ToDeleteCommand + * 3. Envia comando atravĆ©s do dispatcher + * 4. Processa resultado e retorna status apropriado + * 5. Registra evento de auditoria (futuro) + */ +export const apiProvidersDelete = (options: Options) => (options.client ?? client).delete({ url: '/api/v1/providers/{id}', ...options }); + +/** + * Implementa a lógica de consulta de prestador por ID. + * + * Processo da consulta: + * 1. Valida ID do prestador no formato GUID + * 2. Cria query usando mapper ToQuery + * 3. Envia query atravĆ©s do dispatcher CQRS + * 4. Retorna resposta HTTP com dados do prestador ou NotFound + */ +export const apiProvidersGet3 = (options: Options) => (options.client ?? client).get({ url: '/api/v1/providers/{id}', ...options }); + +/** + * Processa requisição de atualização de perfil de forma assĆ­ncrona. + * + * Fluxo de execução: + * 1. Valida ID do prestador e autorização + * 2. Converte request em comando CQRS + * 3. Envia comando atravĆ©s do dispatcher + * 4. Processa resultado e retorna resposta HTTP apropriada + */ +export const apiProvidersPut = (options: Options) => (options.client ?? client).put({ + url: '/api/v1/providers/{id}', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options.headers + } +}); + +/** + * Consultar perfil pĆŗblico do prestador + * + * Recupera dados pĆŗblicos e seguros de um prestador para exibição no site. + * NĆ£o requer autenticação. Aceita ID (GUID) ou slug amigĆ”vel (ex.: "joao-silva-a1b2c3d4"). + * + * **Dados Retornados:** + * - InformaƧƵes bĆ”sicas (Nome, Fantasia, Descrição) + * - Localização aproximada (Cidade/Estado) + * - Avaliação mĆ©dia e contagem de reviews + * - Lista de serviƧos oferecidos (Nota: esta lista serĆ” vazia se a configuração PublicProfilePrivacy do provedor estiver ativa e o solicitante for anĆ“nimo) + * + * **Dados Ocultados (Privacidade):** + * - Documentos (CPF/CNPJ) + * - EndereƧo completo (Rua/NĆŗmero) + * - Dados de auditoria interna + */ +export const apiPublicGet = (options: Options) => (options.client ?? client).get({ url: '/api/v1/providers/public/{idOrSlug}', ...options }); + +/** + * Tornar-se prestador (usuĆ”rio jĆ” autenticado) + * + * Transforma o usuĆ”rio autenticado em um prestador de serviƧos. Requer token de usuĆ”rio. + */ +export const apiBecomePost = (options: Options) => (options.client ?? client).post({ + url: '/api/v1/providers/become', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options.headers + } +}); + +/** + * Implementa a lógica de consulta de prestador por ID do usuĆ”rio. + * + * Processo da consulta: + * 1. Valida ID do usuĆ”rio no formato GUID + * 2. Cria query usando mapper ToUserQuery + * 3. Envia query atravĆ©s do dispatcher CQRS + * 4. Retorna resposta HTTP com dados do prestador ou NotFound + */ +export const apiByUserGet = (options: Options) => (options.client ?? client).get({ url: '/api/v1/providers/by-user/{userId}', ...options }); + +/** + * Implementa a lógica de consulta de prestadores por cidade. + * + * Processo da consulta: + * 1. Valida parĆ¢metro de cidade + * 2. Cria query usando mapper ToCityQuery + * 3. Envia query atravĆ©s do dispatcher CQRS + * 4. Retorna resposta HTTP com lista de prestadores + */ +export const apiByCityGet = (options: Options) => (options.client ?? client).get({ url: '/api/v1/providers/by-city/{city}', ...options }); + +/** + * Implementa a lógica de consulta de prestadores por estado. + * + * Processo da consulta: + * 1. Valida parĆ¢metro de estado + * 2. Cria query usando mapper ToStateQuery + * 3. Envia query atravĆ©s do dispatcher CQRS + * 4. Retorna resposta HTTP com lista de prestadores + */ +export const apiByStateGet = (options: Options) => (options.client ?? client).get({ url: '/api/v1/providers/by-state/{state}', ...options }); + +/** + * Implementa a lógica de consulta de prestadores por tipo. + * + * Processo da consulta: + * 1. Valida enum de tipo do prestador + * 2. Cria query usando mapper ToTypeQuery + * 3. Envia query atravĆ©s do dispatcher CQRS + * 4. Retorna resposta HTTP com lista de prestadores + */ +export const apiByTypeGet = (options: Options) => (options.client ?? client).get({ url: '/api/v1/providers/by-type/{type}', ...options }); + +/** + * Implementa a lógica de consulta de prestadores por status de verificação. + * + * Processo da consulta: + * 1. Valida enum de status de verificação + * 2. Cria query usando mapper ToVerificationStatusQuery + * 3. Envia query atravĆ©s do dispatcher CQRS + * 4. Retorna resposta HTTP com lista de prestadores + */ +export const apiVerificationStatusGet = (options: Options) => (options.client ?? client).get({ url: '/api/v1/providers/verification-status/{status}', ...options }); + +/** + * Processa requisição de adição de documento de forma assĆ­ncrona. + * + * Fluxo de execução: + * 1. Valida ID do prestador e autorização + * 2. Converte request em comando CQRS + * 3. Envia comando atravĆ©s do dispatcher + * 4. Processa resultado e retorna prestador atualizado + */ +export const apiDocumentsPost = (options: Options) => (options.client ?? client).post({ + url: '/api/v1/providers/{id}/documents', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options.headers + } +}); + +/** + * Processa requisição de remoção de documento de forma assĆ­ncrona. + * + * Fluxo de execução: + * 1. Valida ID do prestador e autorização + * 2. Cria comando usando mapper ToRemoveDocumentCommand + * 3. Envia comando atravĆ©s do dispatcher + * 4. Processa resultado e retorna prestador atualizado + */ +export const apiDocumentsDelete = (options: Options) => (options.client ?? client).delete({ url: '/api/v1/providers/{id}/documents/{documentType}', ...options }); + +/** + * Processa requisição de atualização de status de forma assĆ­ncrona. + * + * Fluxo de execução: + * 1. Valida ID do prestador e autorização administrativa + * 2. Converte request em comando CQRS + * 3. Envia comando atravĆ©s do dispatcher + * 4. Processa resultado e retorna prestador atualizado + * 5. Registra evento de auditoria (futuro) + */ +export const apiVerificationStatusPut = (options: Options) => (options.client ?? client).put({ + url: '/api/v1/providers/{id}/verification-status', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options.headers + } +}); + +/** + * Processa requisição de solicitação de correção de forma assĆ­ncrona. + * + * Fluxo de execução: + * 1. Valida ID do prestador e autorização + * 2. Extrai identidade do usuĆ”rio autenticado do contexto HTTP + * 3. Converte request em comando CQRS com identidade verificada + * 4. Envia comando atravĆ©s do dispatcher + * 5. Processa resultado e retorna confirmação + * 6. Emite evento de domĆ­nio para notificação + */ +export const apiRequireBasicInfoCorrectionPost = (options: Options) => (options.client ?? client).post({ + url: '/api/v1/providers/{id}/require-basic-info-correction', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options.headers + } +}); + +export const apiMeGet = (options?: Options) => (options?.client ?? client).get({ url: '/api/v1/providers/me', ...options }); + +export const apiMePut = (options: Options) => (options.client ?? client).put({ + url: '/api/v1/providers/me', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options.headers + } +}); + +/** + * Upload de documento pelo próprio prestador + * + * Permite que o prestador adicione documentos ao seu próprio perfil. + */ +export const apiDocumentsPost2 = (options: Options) => (options.client ?? client).post({ + url: '/api/v1/providers/me/documents', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options.headers + } +}); + +/** + * Status de aprovação do prestador + * + * Retorna o status atual de aprovação e tier do prestador autenticado. + */ +export const apiStatusGet2 = (options?: Options) => (options?.client ?? client).get({ url: '/api/v1/providers/me/status', ...options }); + +export const apiActivatePost = (options?: Options) => (options?.client ?? client).post({ url: '/api/v1/providers/me/activate', ...options }); + +export const apiDeactivatePost = (options?: Options) => (options?.client ?? client).post({ url: '/api/v1/providers/me/deactivate', ...options }); + +/** + * Auto-registro de prestador de serviƧos + * + * Inicia o cadastro de um prestador. Cria usuĆ”rio no Keycloak com role 'provider-standard' e a entidade Provider com Tier=Standard. Endpoint pĆŗblico, sem autenticação. + */ +export const apiRegisterPost = (options: Options) => (options.client ?? client).post({ + url: '/api/v1/providers/register', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options.headers + } +}); + +/** + * Processa requisição de remoção de serviƧo do provider. + * + * ### Remove um serviƧo do catĆ”logo do provider + * + * **Funcionalidades:** + * - āœ… Remove associação entre provider e serviƧo + * - āœ… Emite evento de domĆ­nio ProviderServiceRemovedDomainEvent + * - āœ… Valida que o provider oferece o serviƧo antes de remover + * + * **Campos obrigatórios:** + * - providerId: ID do provider (UUID) + * - serviceId: ID do serviƧo do catĆ”logo (UUID) + * + * **ValidaƧƵes:** + * - Provider deve existir + * - Provider deve oferecer o serviƧo + * - Provider nĆ£o pode estar deletado + */ +export const apiServicesDelete = (options: Options) => (options.client ?? client).delete({ url: '/api/v1/providers/{providerId}/services/{serviceId}', ...options }); + +/** + * Processa requisição de adição de serviƧo ao provider. + * + * ### Adiciona um serviƧo do catĆ”logo ao provider + * + * **Funcionalidades:** + * - āœ… Valida existĆŖncia e status do serviƧo via IServiceCatalogsModuleApi + * - āœ… Verifica se o serviƧo estĆ” ativo + * - āœ… Previne duplicação de serviƧos + * - āœ… Emite evento de domĆ­nio ProviderServiceAddedDomainEvent + * + * **Campos obrigatórios:** + * - providerId: ID do provider (UUID) + * - serviceId: ID do serviƧo do catĆ”logo (UUID) + * + * **ValidaƧƵes:** + * - ServiƧo deve existir no catĆ”logo + * - ServiƧo deve estar ativo + * - Provider nĆ£o pode jĆ” oferecer o serviƧo + * - Provider nĆ£o pode estar deletado + */ +export const apiServicesPost = (options: Options) => (options.client ?? client).post({ url: '/api/v1/providers/{providerId}/services/{serviceId}', ...options }); + +/** + * Buscar prestadores de serviƧo + * + * Busca prestadores de serviƧo ativos com base em geolocalização e filtros. + * + * **Algoritmo de Busca:** + * 1. Filtrar por raio a partir da localização de busca + * 2. Aplicar filtro textual (nome, descrição) se fornecido + * 3. Aplicar filtros opcionais (serviƧos, avaliação, nĆ­vel de assinatura) + * 4. Classificar resultados por: + * - NĆ­vel de assinatura (Platinum > Gold > Standard > Free) + * - Avaliação mĆ©dia (maior primeiro) + * - DistĆ¢ncia (mais próximo primeiro) + * + * **Casos de Uso:** + * - Encontrar prestadores próximos a uma localização especĆ­fica + * - Buscar prestadores por nome ou termo (ex: "Eletricista", "JoĆ£o") + * - Buscar prestadores que oferecem serviƧos especĆ­ficos + * - Filtrar por avaliação mĆ­nima ou nĆ­vel de assinatura + */ +export const apiProvidersGet4 = (options: Options) => (options.client ?? client).get({ url: '/api/v1/search/providers', ...options }); + +/** + * Recebe e registra violaƧƵes de CSP. + */ +export const apiCspReportPost = (options?: Options) => (options?.client ?? client).post({ url: '/api/csp-report', ...options }); + +/** + * Listar todas as categorias + * + * Retorna todas as categorias de serviƧos do catĆ”logo. + * + * **Filtros Opcionais:** + * - `activeOnly` (bool): Filtra apenas categorias ativas (padrĆ£o: false) + * + * **Ordenação:** + * - Categorias sĆ£o ordenadas por DisplayOrder (crescente) + * + * **Casos de Uso:** + * - Exibir menu de categorias para usuĆ”rios + * - Administração do catĆ”logo de categorias + * - Seleção de categoria ao criar serviƧo + */ +export const apiCategoriesGet = (options?: Options) => (options?.client ?? client).get({ url: '/api/v1/service-catalogs/categories', ...options }); + +/** + * Criar categoria de serviƧo + * + * Cria uma nova categoria de serviƧos no catĆ”logo. + * + * **ValidaƧƵes:** + * - Nome Ć© obrigatório (mĆ”ximo 100 caracteres) + * - Descrição opcional (mĆ”ximo 500 caracteres) + * - DisplayOrder deve ser >= 0 + * - Nome deve ser Ćŗnico no sistema + * + * **Efeitos:** + * - Categoria criada como ativa por padrĆ£o + * - Pode receber serviƧos imediatamente + * + * **PermissƵes:** Requer privilĆ©gios de administrador + */ +export const apiCategoriesPost = (options: Options) => (options.client ?? client).post({ + url: '/api/v1/service-catalogs/categories', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options.headers + } +}); + +/** + * Deletar categoria de serviƧo + * + * Deleta uma categoria de serviƧos permanentemente. + * + * **ValidaƧƵes:** + * - ID nĆ£o pode ser vazio + * - Categoria deve existir + * - Categoria nĆ£o pode ter serviƧos associados + * + * **Importante:** Operação destrutiva. Categorias com serviƧos nĆ£o podem + * ser deletadas. Use desativação ou mova os serviƧos primeiro. + * + * **PermissƵes:** Requer privilĆ©gios de administrador + */ +export const apiCategoriesDelete = (options: Options) => (options.client ?? client).delete({ url: '/api/v1/service-catalogs/categories/{id}', ...options }); + +/** + * Buscar categoria por ID + * + * Retorna os detalhes completos de uma categoria especĆ­fica. + * + * **Retorno:** + * - InformaƧƵes completas da categoria + * - Status de ativação + * - DisplayOrder para ordenação + * - Datas de criação e atualização + * + * **Casos de Uso:** + * - Exibir detalhes da categoria para edição + * - Validar existĆŖncia de categoria + * - Visualizar informaƧƵes completas + */ +export const apiCategoriesGet2 = (options: Options) => (options.client ?? client).get({ url: '/api/v1/service-catalogs/categories/{id}', ...options }); + +/** + * Atualizar categoria de serviƧo + * + * Atualiza as informaƧƵes de uma categoria existente. + * + * **ValidaƧƵes:** + * - ID nĆ£o pode ser vazio + * - Categoria deve existir + * - Nome Ć© obrigatório (mĆ”ximo 100 caracteres) + * - Descrição opcional (mĆ”ximo 500 caracteres) + * - DisplayOrder deve ser >= 0 + * + * **Nota:** Requer atualização completa (full-update pattern). + * Todos os campos devem ser fornecidos. + * + * **PermissƵes:** Requer privilĆ©gios de administrador + */ +export const apiCategoriesPut = (options: Options) => (options.client ?? client).put({ + url: '/api/v1/service-catalogs/categories/{id}', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options.headers + } +}); + +/** + * Ativar categoria de serviƧo + * + * Ativa uma categoria de serviƧos. + * + * **Efeitos:** + * - Categoria fica visĆ­vel em listagens pĆŗblicas + * - Permite criação de novos serviƧos nesta categoria + * - ServiƧos existentes na categoria voltam a ser acessĆ­veis + * + * **PermissƵes:** Requer privilĆ©gios de administrador + */ +export const apiActivatePost2 = (options: Options) => (options.client ?? client).post({ url: '/api/v1/service-catalogs/categories/{id}/activate', ...options }); + +/** + * Desativar categoria de serviƧo + * + * Desativa uma categoria de serviƧos. + * + * **Efeitos:** + * - Categoria nĆ£o aparece em listagens pĆŗblicas + * - Impede criação de novos serviƧos nesta categoria + * - ServiƧos existentes permanecem no sistema (soft-delete) + * + * **Nota:** PreferĆ­vel Ć  deleção quando hĆ” serviƧos associados. + * + * **PermissƵes:** Requer privilĆ©gios de administrador + */ +export const apiDeactivatePost2 = (options: Options) => (options.client ?? client).post({ url: '/api/v1/service-catalogs/categories/{id}/deactivate', ...options }); + +/** + * Listar todos os serviƧos + * + * Retorna todos os serviƧos do catĆ”logo. + * + * **Filtros Opcionais:** + * - `activeOnly` (bool): Filtra apenas serviƧos ativos (padrĆ£o: false) + * + * **Casos de Uso:** + * - Listar todo o catĆ”logo de serviƧos + * - Obter apenas serviƧos ativos para exibição pĆŗblica + * - Administração do catĆ”logo completo + */ +export const apiServicesGet = (options?: Options) => (options?.client ?? client).get({ url: '/api/v1/service-catalogs/services', ...options }); + +/** + * Criar serviƧo + * + * Cria um novo serviƧo no catĆ”logo. + * + * **ValidaƧƵes:** + * - Nome Ć© obrigatório (mĆ”ximo 150 caracteres) + * - Descrição opcional (mĆ”ximo 1000 caracteres) + * - DisplayOrder deve ser >= 0 + * - Categoria deve existir e estar ativa + * + * **PermissƵes:** Requer privilĆ©gios de administrador + */ +export const apiServicesPost2 = (options: Options) => (options.client ?? client).post({ + url: '/api/v1/service-catalogs/services', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options.headers + } +}); + +/** + * Deletar serviƧo + * + * Deleta um serviƧo do catĆ”logo permanentemente. + * + * **ValidaƧƵes:** + * - ID nĆ£o pode ser vazio + * - ServiƧo deve existir + * - Nenhum provedor pode estar oferecendo este serviƧo + * + * **Importante:** Operação destrutiva. Se provedores oferecem o serviƧo, + * use desativação em vez de deleção para preservar dados históricos. + * + * **PermissƵes:** Requer privilĆ©gios de administrador + */ +export const apiServicesDelete2 = (options: Options) => (options.client ?? client).delete({ url: '/api/v1/service-catalogs/services/{id}', ...options }); + +/** + * Buscar serviƧo por ID + * + * Retorna os detalhes completos de um serviƧo especĆ­fico. + * + * **Retorno:** + * - InformaƧƵes completas do serviƧo incluindo categoria + * - Status de ativação + * - Datas de criação e atualização + * + * **Casos de Uso:** + * - Exibir detalhes do serviƧo para edição + * - Visualizar informaƧƵes completas do serviƧo + * - Validar existĆŖncia do serviƧo + */ +export const apiServicesGet2 = (options: Options) => (options.client ?? client).get({ url: '/api/v1/service-catalogs/services/{id}', ...options }); + +/** + * Atualizar serviƧo + * + * Atualiza as informaƧƵes de um serviƧo existente. + * + * **ValidaƧƵes:** + * - ID nĆ£o pode ser vazio + * - ServiƧo deve existir + * - Nome Ć© obrigatório (mĆ”ximo 150 caracteres) + * - Descrição opcional (mĆ”ximo 1000 caracteres) + * - DisplayOrder deve ser >= 0 + * + * **Nota:** NĆ£o altera a categoria do serviƧo. Use ChangeServiceCategory para isso. + * + * **PermissƵes:** Requer privilĆ©gios de administrador + */ +export const apiServicesPut = (options: Options) => (options.client ?? client).put({ + url: '/api/v1/service-catalogs/services/{id}', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options.headers + } +}); + +/** + * Listar serviƧos por categoria + * + * Retorna todos os serviƧos de uma categoria especĆ­fica. + * + * **ParĆ¢metros:** + * - `categoryId` (route): ID da categoria + * - `activeOnly` (query, opcional): Filtrar apenas serviƧos ativos (padrĆ£o: false) + * + * **Casos de Uso:** + * - Exibir serviƧos disponĆ­veis em uma categoria + * - Listar ofertas por categoria para provedores + * - GestĆ£o de catĆ”logo segmentado por categoria + */ +export const apiCategoryGet = (options: Options) => (options.client ?? client).get({ url: '/api/v1/service-catalogs/services/category/{categoryId}', ...options }); + +/** + * Alterar categoria do serviƧo + * + * Move um serviƧo para uma categoria diferente. + * + * **ValidaƧƵes:** + * - ServiƧo deve existir + * - Nova categoria deve existir e estar ativa + * - Nova categoria nĆ£o pode ser a mesma que a atual + * + * **Casos de Uso:** + * - Reorganizar catĆ”logo de serviƧos + * - Corrigir categorização incorreta + * - Adaptar estrutura de categorias + * + * **PermissƵes:** Requer privilĆ©gios de administrador + */ +export const apiChangeCategoryPost = (options: Options) => (options.client ?? client).post({ + url: '/api/v1/service-catalogs/services/{id}/change-category', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options.headers + } +}); + +/** + * Ativar serviƧo + * + * Ativa um serviƧo, tornando-o disponĆ­vel no catĆ”logo. + * + * **Efeitos:** + * - ServiƧo fica visĆ­vel em listagens pĆŗblicas + * - Provedores podem adicionar este serviƧo Ć s suas ofertas + * - ServiƧo aparece em buscas de serviƧos ativos + * + * **PermissƵes:** Requer privilĆ©gios de administrador + */ +export const apiActivatePost3 = (options: Options) => (options.client ?? client).post({ url: '/api/v1/service-catalogs/services/{id}/activate', ...options }); + +/** + * Desativar serviƧo + * + * Desativa um serviƧo, removendo-o do catĆ”logo ativo. + * + * **Efeitos:** + * - ServiƧo nĆ£o aparece em listagens pĆŗblicas + * - Provedores nĆ£o podem adicionar este serviƧo a novas ofertas + * - ServiƧo preserva dados históricos (soft-delete) + * + * **Nota:** PreferĆ­vel Ć  deleção quando provedores jĆ” oferecem o serviƧo. + * + * **PermissƵes:** Requer privilĆ©gios de administrador + */ +export const apiDeactivatePost3 = (options: Options) => (options.client ?? client).post({ url: '/api/v1/service-catalogs/services/{id}/deactivate', ...options }); + +/** + * Validar mĆŗltiplos serviƧos + * + * Valida a existĆŖncia e status de uma lista de serviƧos. + * + * **Funcionalidade:** + * - Verifica se todos os IDs existem no catĆ”logo + * - Retorna quais serviƧos sĆ£o vĆ”lidos e quais sĆ£o invĆ”lidos + * - Indica serviƧos inativos separadamente + * + * **Casos de Uso:** + * - Validar serviƧos antes de adicionar a um provedor + * - Verificação em lote para importação de dados + * - Garantir integridade referencial entre módulos + * + * **PermissƵes:** Requer privilĆ©gios de administrador + */ +export const apiValidatePost = (options: Options) => (options.client ?? client).post({ + url: '/api/v1/service-catalogs/services/validate', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options.headers + } +}); + +/** + * Processa requisição de consulta de usuĆ”rios de forma assĆ­ncrona. + * + * Fluxo de execução: + * 1. Extrai parĆ¢metros de paginação da query string + * 2. Cria query CQRS com parĆ¢metros validados + * 3. Envia query atravĆ©s do dispatcher + * 4. Retorna resposta paginada estruturada com metadados + * + * Suporta parĆ¢metros: PageNumber, PageSize, SearchTerm + */ +export const apiUsersGet = (options?: Options) => (options?.client ?? client).get({ url: '/api/v1/users', ...options }); + +/** + * Processa requisição de criação de usuĆ”rio de forma assĆ­ncrona. + * + * Fluxo de execução: + * 1. Converte request em comando CQRS + * 2. Envia comando atravĆ©s do dispatcher + * 3. Processa resultado e retorna resposta HTTP apropriada + * 4. Inclui localização do recurso criado no header + */ +export const apiUsersPost = (options: Options) => (options.client ?? client).post({ + url: '/api/v1/users', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options.headers + } +}); + +/** + * Implementa a lógica de exclusĆ£o de usuĆ”rio. + * + * Processo de exclusĆ£o: + * 1. Valida ID do usuĆ”rio no formato GUID + * 2. Cria command usando mapper ToDeleteCommand + * 3. Envia command atravĆ©s do dispatcher CQRS + * 4. Retorna resposta HTTP 204 No Content + */ +export const apiUsersDelete = (options: Options) => (options.client ?? client).delete({ url: '/api/v1/users/{id}', ...options }); + +/** + * Implementa a lógica de consulta de usuĆ”rio por ID. + * + * Processo da consulta: + * 1. Valida ID do usuĆ”rio no formato GUID + * 2. Cria query usando mapper ToQuery + * 3. Envia query atravĆ©s do dispatcher CQRS + * 4. Retorna resposta HTTP com dados do usuĆ”rio + */ +export const apiUsersGet2 = (options: Options) => (options.client ?? client).get({ url: '/api/v1/users/{id}', ...options }); + +/** + * Implementa a lógica de consulta de usuĆ”rio por email. + * + * Processo da consulta: + * 1. Valida formato do email + * 2. Cria query usando mapper ToEmailQuery + * 3. Envia query atravĆ©s do dispatcher CQRS + * 4. Retorna resposta HTTP com dados do usuĆ”rio + */ +export const apiByEmailGet = (options: Options) => (options.client ?? client).get({ url: '/api/v1/users/by-email/{email}', ...options }); + +/** + * Processa requisição de atualização de perfil de usuĆ”rio de forma assĆ­ncrona. + * + * Fluxo de execução: + * 1. Valida ID do usuĆ”rio no formato GUID + * 2. Cria comando de atualização com dados da requisição + * 3. Envia comando atravĆ©s do dispatcher CQRS + * 4. Retorna resposta HTTP com dados atualizados + * + * Dados atualizĆ”veis: FirstName, LastName, Email, PhoneNumber + */ +export const apiProfilePut = (options: Options) => (options.client ?? client).put({ + url: '/api/v1/users/{id}/profile', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options.headers + } +}); + +/** + * Registers a new customer + * + * Creates a new user account with 'customer' role. + */ +export const apiRegisterPost2 = (options: Options) => (options.client ?? client).post({ + url: '/api/v1/users/register', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options.headers + } +}); diff --git a/src/Web/MeAjudaAi.Web.Admin-React/src/lib/api/generated/types.gen.ts b/src/Web/MeAjudaAi.Web.Admin-React/src/lib/api/generated/types.gen.ts new file mode 100644 index 000000000..5ca1ecb10 --- /dev/null +++ b/src/Web/MeAjudaAi.Web.Admin-React/src/lib/api/generated/types.gen.ts @@ -0,0 +1,3311 @@ +// This file is auto-generated by @hey-api/openapi-ts + +export type ClientOptions = { + baseUrl: 'http://localhost:7002' | (string & {}); +}; + +/** + * Configuração do cliente Blazor WASM. + * ContĆ©m apenas informaƧƵes nĆ£o-sensĆ­veis necessĆ”rias para o frontend. + */ +export type MeAjudaAiContractsConfigurationClientConfiguration = { + /** + * URL base da API backend. + */ + apiBaseUrl?: string | null; + keycloak?: MeAjudaAiContractsConfigurationKeycloakConfiguration; + external?: MeAjudaAiContractsConfigurationExternalResources; + features?: MeAjudaAiContractsConfigurationFeatureFlags; +}; + +/** + * URLs de recursos externos. + */ +export type MeAjudaAiContractsConfigurationExternalResources = { + /** + * URL da documentação/help center (se houver). + */ + documentationUrl?: string | null; + /** + * URL do suporte/support portal (se houver). + */ + supportUrl?: string | null; +}; + +/** + * Feature flags para habilitar/desabilitar funcionalidades no frontend. + */ +export type MeAjudaAiContractsConfigurationFeatureFlags = { + /** + * Habilita Redux DevTools (somente em desenvolvimento). + */ + enableReduxDevTools?: boolean; + /** + * Habilita mode de debug/diagnóstico. + */ + enableDebugMode?: boolean; + /** + * Habilita autenticação fake para desenvolvimento local. + */ + enableFakeAuth?: boolean; +}; + +/** + * Configuração do Keycloak para autenticação OIDC. + */ +export type MeAjudaAiContractsConfigurationKeycloakConfiguration = { + /** + * URL do realm Keycloak (authority). + * Exemplo: https://auth.meajudaai.com/realms/meajudaai + */ + authority?: string | null; + /** + * ID do cliente registrado no Keycloak. + */ + clientId?: string | null; + /** + * Tipo de resposta OAuth2 (geralmente "code" para PKCE). + */ + responseType?: string | null; + /** + * Escopos solicitados (space-separated). + */ + scope?: string | null; + /** + * URL de redirecionamento após logout. + */ + postLogoutRedirectUri?: string | null; +}; + +/** + * Request DTO para criação de cidade permitida. + * Usado pelo Admin Portal para adicionar novas cidades ao sistema. + */ +export type MeAjudaAiContractsContractsModulesLocationsDtosCreateAllowedCityRequestDto = { + city?: string | null; + state?: string | null; + country?: string | null; + latitude?: number; + longitude?: number; + serviceRadiusKm?: number; + isActive?: boolean; +}; + +export type MeAjudaAiContractsContractsModulesLocationsDtosLocationCandidate = { + displayName?: string | null; + city?: string | null; + state?: string | null; + country?: string | null; + latitude?: number; + longitude?: number; +}; + +/** + * DTO para resposta de cidade permitida. + * Usado pelo frontend para exibir cidades permitidas no sistema. + */ +export type MeAjudaAiContractsContractsModulesLocationsDtosModuleAllowedCityDto = { + id?: string; + city?: string | null; + state?: string | null; + country?: string | null; + latitude?: number; + longitude?: number; + isActive?: boolean; + createdAt?: string; + updatedAt?: string | null; + serviceRadiusKm?: number; +}; + +/** + * DTO para atualização parcial de cidade permitida. + */ +export type MeAjudaAiContractsContractsModulesLocationsDtosPatchAllowedCityRequestDto = { + serviceRadiusKm?: number | null; + isActive?: boolean | null; +}; + +/** + * Representa um erro com mensagem e código de status HTTP. + */ +export type MeAjudaAiContractsFunctionalError = { + /** + * Mensagem descritiva do erro + */ + message?: string | null; + /** + * Código de status HTTP (padrĆ£o: 400) + */ + statusCode?: number; +}; + +export type MeAjudaAiContractsFunctionalResult = { + isSuccess?: boolean; + readonly isFailure?: boolean; + error?: MeAjudaAiContractsFunctionalError; +}; + +/** + * Representa o resultado de uma operação que pode retornar um valor de tipo . + * + * Nota sobre tipos nullable: quando Ć© um tipo de referĆŖncia nullable + * (ex.: `Result`), MeAjudaAi.Contracts.Functional.Result`1.Value pode ser `null` mesmo em caso de sucesso. + * Nesse cenĆ”rio, os atributos `[MemberNotNullWhen]` nĆ£o se aplicam e o chamador deve verificar a nulidade + * do valor separadamente. Prefira usar `Result` (nĆ£o-nullable) quando o sucesso + * garantir um valor. + */ +export type MeAjudaAiContractsFunctionalResult1MeAjudaAiContractsFunctionalUnit_MeAjudaAiContracts_Version_0000_Culture_neutral_PublicKeyToken_null = { + isSuccess?: boolean; + readonly isFailure?: boolean; + value?: MeAjudaAiContractsFunctionalUnit; + error?: MeAjudaAiContractsFunctionalError; +}; + +/** + * Representa o resultado de uma operação que pode retornar um valor de tipo . + * + * Nota sobre tipos nullable: quando Ć© um tipo de referĆŖncia nullable + * (ex.: `Result`), MeAjudaAi.Contracts.Functional.Result`1.Value pode ser `null` mesmo em caso de sucesso. + * Nesse cenĆ”rio, os atributos `[MemberNotNullWhen]` nĆ£o se aplicam e o chamador deve verificar a nulidade + * do valor separadamente. Prefira usar `Result` (nĆ£o-nullable) quando o sucesso + * garantir um valor. + */ +export type MeAjudaAiContractsFunctionalResult1SystemCollectionsGenericIReadOnlyList1MeAjudaAiContractsContractsModulesLocationsDtosModuleAllowedCityDto_MeAjudaAiContracts_Version_0000_Culture_neutral_PublicKeyToken_null___SystemPrivateCoreLib_Version_10000_Culture_neutral_PublicKeyToken_7Cec85D7Bea7798E = { + isSuccess?: boolean; + readonly isFailure?: boolean; + value?: Array | null; + error?: MeAjudaAiContractsFunctionalError; +}; + +/** + * Representa um tipo que nĆ£o retorna valor Ćŗtil. + * Usado para padronizar interfaces que podem ou nĆ£o retornar valores. + */ +export type MeAjudaAiContractsFunctionalUnit = { + [key: string]: never; +}; + +/** + * Representa uma cidade permitida para acesso ao serviƧo. + */ +export type MeAjudaAiContractsModelsAllowedCity = { + /** + * Nome da cidade. + */ + name: string | null; + /** + * Sigla do estado (UF). + */ + state: string | null; + /** + * Código IBGE do municĆ­pio (7 dĆ­gitos). + */ + ibgeCode?: string | null; +}; + +/** + * Modelo para erros de autenticação/autorização. + */ +export type MeAjudaAiContractsModelsAuthenticationErrorResponse = { + /** + * Código de status HTTP do erro. + */ + statusCode?: number; + /** + * TĆ­tulo/tipo do erro. + */ + title?: string | null; + /** + * Mensagem detalhada do erro. + */ + detail?: string | null; + /** + * Identificador Ćŗnico para rastreamento do erro. + */ + traceId?: string | null; + /** + * Timestamp de quando o erro ocorreu. + */ + timestamp?: string; + /** + * Detalhes especĆ­ficos dos erros de validação (quando aplicĆ”vel). + */ + validationErrors?: { + [key: string]: Array; + } | null; +}; + +/** + * Modelo para erros de permissĆ£o/autorização. + */ +export type MeAjudaAiContractsModelsAuthorizationErrorResponse = { + /** + * Código de status HTTP do erro. + */ + statusCode?: number; + /** + * TĆ­tulo/tipo do erro. + */ + title?: string | null; + /** + * Mensagem detalhada do erro. + */ + detail?: string | null; + /** + * Identificador Ćŗnico para rastreamento do erro. + */ + traceId?: string | null; + /** + * Timestamp de quando o erro ocorreu. + */ + timestamp?: string; + /** + * Detalhes especĆ­ficos dos erros de validação (quando aplicĆ”vel). + */ + validationErrors?: { + [key: string]: Array; + } | null; +}; + +/** + * Modelo para erros de restrição geogrĆ”fica (HTTP 451 - Unavailable For Legal Reasons). + */ +export type MeAjudaAiContractsModelsGeographicRestrictionErrorResponse = { + /** + * Código de status HTTP do erro. + */ + statusCode?: number; + /** + * TĆ­tulo/tipo do erro. + */ + title?: string | null; + /** + * Mensagem detalhada do erro. + */ + detail?: string | null; + /** + * Identificador Ćŗnico para rastreamento do erro. + */ + traceId?: string | null; + /** + * Timestamp de quando o erro ocorreu. + */ + timestamp?: string; + /** + * Detalhes especĆ­ficos dos erros de validação (quando aplicĆ”vel). + */ + validationErrors?: { + [key: string]: Array; + } | null; + yourLocation?: MeAjudaAiContractsModelsUserLocation; + /** + * Lista de cidades permitidas onde o serviƧo estĆ” disponĆ­vel. + */ + allowedCities?: Array | null; + /** + * Lista de estados (UFs) permitidos onde o serviƧo estĆ” disponĆ­vel. + */ + allowedStates?: Array | null; + /** + * Código de erro especĆ­fico para restrição geogrĆ”fica. + */ + error?: string | null; +}; + +/** + * Modelo para erros internos do servidor. + */ +export type MeAjudaAiContractsModelsInternalServerErrorResponse = { + /** + * Código de status HTTP do erro. + */ + statusCode?: number; + /** + * TĆ­tulo/tipo do erro. + */ + title?: string | null; + /** + * Mensagem detalhada do erro. + */ + detail?: string | null; + /** + * Identificador Ćŗnico para rastreamento do erro. + */ + traceId?: string | null; + /** + * Timestamp de quando o erro ocorreu. + */ + timestamp?: string; + /** + * Detalhes especĆ­ficos dos erros de validação (quando aplicĆ”vel). + */ + validationErrors?: { + [key: string]: Array; + } | null; +}; + +/** + * Envelope padrĆ£o para respostas paginadas da API + */ +export type MeAjudaAiContractsModelsPagedResponse1SystemCollectionsGenericIEnumerable1MeAjudaAiModulesProvidersApplicationDtosProviderDto_MeAjudaAiModulesProvidersApplication_Version_0000_Culture_neutral_PublicKeyToken_null___SystemPrivateCoreLib_Version_10000_Culture_neutral_PublicKeyToken_7Cec85D7Bea7798E = { + /** + * Dados da resposta + */ + data?: Array | null; + /** + * Total de itens disponĆ­veis + */ + totalCount?: number; + /** + * PĆ”gina atual (1-based) + */ + currentPage?: number; + /** + * Tamanho da pĆ”gina + */ + pageSize?: number; + /** + * Total de pĆ”ginas + */ + readonly totalPages?: number; +}; + +/** + * Envelope padrĆ£o para respostas paginadas da API + */ +export type MeAjudaAiContractsModelsPagedResponse1SystemCollectionsGenericIEnumerable1MeAjudaAiModulesUsersApplicationDtosUserDto_MeAjudaAiModulesUsersApplication_Version_0000_Culture_neutral_PublicKeyToken_null___SystemPrivateCoreLib_Version_10000_Culture_neutral_PublicKeyToken_7Cec85D7Bea7798E = { + /** + * Dados da resposta + */ + data?: Array | null; + /** + * Total de itens disponĆ­veis + */ + totalCount?: number; + /** + * PĆ”gina atual (1-based) + */ + currentPage?: number; + /** + * Tamanho da pĆ”gina + */ + pageSize?: number; + /** + * Total de pĆ”ginas + */ + readonly totalPages?: number; +}; + +/** + * Representa um resultado paginado de uma consulta Ć  API. + */ +export type MeAjudaAiContractsModelsPagedResult1MeAjudaAiModulesSearchProvidersApplicationDtosSearchableProviderDto_MeAjudaAiModulesSearchProvidersApplication_Version_0000_Culture_neutral_PublicKeyToken_null = { + /** + * Itens da pĆ”gina atual + */ + items: Array | null; + /** + * NĆŗmero da pĆ”gina atual (1-based) + */ + pageNumber: number; + /** + * Tamanho da pĆ”gina (quantidade de itens por pĆ”gina) + */ + pageSize: number; + /** + * Total de itens em todas as pĆ”ginas + */ + totalItems: number; + /** + * Total de pĆ”ginas disponĆ­veis + */ + readonly totalPages?: number; + /** + * Indica se existe uma pĆ”gina anterior + */ + readonly hasPreviousPage?: boolean; + /** + * Indica se existe uma próxima pĆ”gina + */ + readonly hasNextPage?: boolean; +}; + +/** + * Modelo para erros de rate limiting. + */ +export type MeAjudaAiContractsModelsRateLimitErrorResponse = { + /** + * Código de status HTTP do erro. + */ + statusCode?: number; + /** + * TĆ­tulo/tipo do erro. + */ + title?: string | null; + /** + * Mensagem detalhada do erro. + */ + detail?: string | null; + /** + * Identificador Ćŗnico para rastreamento do erro. + */ + traceId?: string | null; + /** + * Timestamp de quando o erro ocorreu. + */ + timestamp?: string; + /** + * Detalhes especĆ­ficos dos erros de validação (quando aplicĆ”vel). + */ + validationErrors?: { + [key: string]: Array; + } | null; + /** + * Tempo de espera recomendado em segundos. + */ + retryAfterSeconds?: number | null; + /** + * Limite de requests por minuto para o usuĆ”rio. + */ + requestLimit?: number | null; + /** + * Requests restantes no perĆ­odo atual. + */ + requestsRemaining?: number | null; +}; + +/** + * Envelope padrĆ£o para respostas da API + */ +export type MeAjudaAiContractsModelsResponse1MeAjudaAiModulesLocationsApplicationDtosAllowedCityDto_MeAjudaAiModulesLocationsApplication_Version_0000_Culture_neutral_PublicKeyToken_null = { + data?: MeAjudaAiModulesLocationsApplicationDtosAllowedCityDto; + /** + * Código HTTP da resposta + */ + statusCode?: number; + /** + * Mensagem descritiva (opcional) + */ + message?: string | null; + /** + * Indica se a resposta representa sucesso (status code 2xx) + */ + readonly isSuccess?: boolean; +}; + +/** + * Envelope padrĆ£o para respostas da API + */ +export type MeAjudaAiContractsModelsResponse1MeAjudaAiModulesProvidersApplicationDtosProviderDto_MeAjudaAiModulesProvidersApplication_Version_0000_Culture_neutral_PublicKeyToken_null = { + data?: MeAjudaAiModulesProvidersApplicationDtosProviderDto; + /** + * Código HTTP da resposta + */ + statusCode?: number; + /** + * Mensagem descritiva (opcional) + */ + message?: string | null; + /** + * Indica se a resposta representa sucesso (status code 2xx) + */ + readonly isSuccess?: boolean; +}; + +/** + * Envelope padrĆ£o para respostas da API + */ +export type MeAjudaAiContractsModelsResponse1MeAjudaAiModulesProvidersApplicationDtosProviderStatusDto_MeAjudaAiModulesProvidersApplication_Version_0000_Culture_neutral_PublicKeyToken_null = { + data?: MeAjudaAiModulesProvidersApplicationDtosProviderStatusDto; + /** + * Código HTTP da resposta + */ + statusCode?: number; + /** + * Mensagem descritiva (opcional) + */ + message?: string | null; + /** + * Indica se a resposta representa sucesso (status code 2xx) + */ + readonly isSuccess?: boolean; +}; + +/** + * Envelope padrĆ£o para respostas da API + */ +export type MeAjudaAiContractsModelsResponse1MeAjudaAiModulesProvidersApplicationDtosPublicProviderDto_MeAjudaAiModulesProvidersApplication_Version_0000_Culture_neutral_PublicKeyToken_null = { + data?: MeAjudaAiModulesProvidersApplicationDtosPublicProviderDto; + /** + * Código HTTP da resposta + */ + statusCode?: number; + /** + * Mensagem descritiva (opcional) + */ + message?: string | null; + /** + * Indica se a resposta representa sucesso (status code 2xx) + */ + readonly isSuccess?: boolean; +}; + +/** + * Envelope padrĆ£o para respostas da API + */ +export type MeAjudaAiContractsModelsResponse1MeAjudaAiModulesServiceCatalogsApplicationDtosRequestsServiceValidateServicesResponse_MeAjudaAiModulesServiceCatalogsApplication_Version_0000_Culture_neutral_PublicKeyToken_null = { + data?: MeAjudaAiModulesServiceCatalogsApplicationDtosRequestsServiceValidateServicesResponse; + /** + * Código HTTP da resposta + */ + statusCode?: number; + /** + * Mensagem descritiva (opcional) + */ + message?: string | null; + /** + * Indica se a resposta representa sucesso (status code 2xx) + */ + readonly isSuccess?: boolean; +}; + +/** + * Envelope padrĆ£o para respostas da API + */ +export type MeAjudaAiContractsModelsResponse1MeAjudaAiModulesServiceCatalogsApplicationDtosServiceCategoryDto_MeAjudaAiModulesServiceCatalogsApplication_Version_0000_Culture_neutral_PublicKeyToken_null = { + data?: MeAjudaAiModulesServiceCatalogsApplicationDtosServiceCategoryDto; + /** + * Código HTTP da resposta + */ + statusCode?: number; + /** + * Mensagem descritiva (opcional) + */ + message?: string | null; + /** + * Indica se a resposta representa sucesso (status code 2xx) + */ + readonly isSuccess?: boolean; +}; + +/** + * Envelope padrĆ£o para respostas da API + */ +export type MeAjudaAiContractsModelsResponse1MeAjudaAiModulesServiceCatalogsApplicationDtosServiceDto_MeAjudaAiModulesServiceCatalogsApplication_Version_0000_Culture_neutral_PublicKeyToken_null = { + data?: MeAjudaAiModulesServiceCatalogsApplicationDtosServiceDto; + /** + * Código HTTP da resposta + */ + statusCode?: number; + /** + * Mensagem descritiva (opcional) + */ + message?: string | null; + /** + * Indica se a resposta representa sucesso (status code 2xx) + */ + readonly isSuccess?: boolean; +}; + +/** + * Envelope padrĆ£o para respostas da API + */ +export type MeAjudaAiContractsModelsResponse1MeAjudaAiModulesUsersApplicationDtosUserDto_MeAjudaAiModulesUsersApplication_Version_0000_Culture_neutral_PublicKeyToken_null = { + data?: MeAjudaAiModulesUsersApplicationDtosUserDto; + /** + * Código HTTP da resposta + */ + statusCode?: number; + /** + * Mensagem descritiva (opcional) + */ + message?: string | null; + /** + * Indica se a resposta representa sucesso (status code 2xx) + */ + readonly isSuccess?: boolean; +}; + +/** + * Envelope padrĆ£o para respostas da API + */ +export type MeAjudaAiContractsModelsResponse1SystemCollectionsGenericIReadOnlyList1MeAjudaAiModulesProvidersApplicationDtosProviderDto_MeAjudaAiModulesProvidersApplication_Version_0000_Culture_neutral_PublicKeyToken_null___SystemPrivateCoreLib_Version_10000_Culture_neutral_PublicKeyToken_7Cec85D7Bea7798E = { + /** + * Dados da resposta + */ + data?: Array | null; + /** + * Código HTTP da resposta + */ + statusCode?: number; + /** + * Mensagem descritiva (opcional) + */ + message?: string | null; + /** + * Indica se a resposta representa sucesso (status code 2xx) + */ + readonly isSuccess?: boolean; +}; + +/** + * Envelope padrĆ£o para respostas da API + */ +export type MeAjudaAiContractsModelsResponse1SystemCollectionsGenericIReadOnlyList1MeAjudaAiModulesServiceCatalogsApplicationDtosServiceCategoryDto_MeAjudaAiModulesServiceCatalogsApplication_Version_0000_Culture_neutral_PublicKeyToken_null___SystemPrivateCoreLib_Version_10000_Culture_neutral_PublicKeyToken_7Cec85D7Bea7798E = { + /** + * Dados da resposta + */ + data?: Array | null; + /** + * Código HTTP da resposta + */ + statusCode?: number; + /** + * Mensagem descritiva (opcional) + */ + message?: string | null; + /** + * Indica se a resposta representa sucesso (status code 2xx) + */ + readonly isSuccess?: boolean; +}; + +/** + * Envelope padrĆ£o para respostas da API + */ +export type MeAjudaAiContractsModelsResponse1SystemCollectionsGenericIReadOnlyList1MeAjudaAiModulesServiceCatalogsApplicationDtosServiceListDto_MeAjudaAiModulesServiceCatalogsApplication_Version_0000_Culture_neutral_PublicKeyToken_null___SystemPrivateCoreLib_Version_10000_Culture_neutral_PublicKeyToken_7Cec85D7Bea7798E = { + /** + * Dados da resposta + */ + data?: Array | null; + /** + * Código HTTP da resposta + */ + statusCode?: number; + /** + * Mensagem descritiva (opcional) + */ + message?: string | null; + /** + * Indica se a resposta representa sucesso (status code 2xx) + */ + readonly isSuccess?: boolean; +}; + +/** + * Envelope padrĆ£o para respostas da API + */ +export type MeAjudaAiContractsModelsResponse1SystemGuid_SystemPrivateCoreLib_Version_10000_Culture_neutral_PublicKeyToken_7Cec85D7Bea7798E = { + /** + * Dados da resposta + */ + data?: string; + /** + * Código HTTP da resposta + */ + statusCode?: number; + /** + * Mensagem descritiva (opcional) + */ + message?: string | null; + /** + * Indica se a resposta representa sucesso (status code 2xx) + */ + readonly isSuccess?: boolean; +}; + +/** + * Envelope padrĆ£o para respostas da API + */ +export type MeAjudaAiContractsModelsResponse1SystemObject_SystemPrivateCoreLib_Version_10000_Culture_neutral_PublicKeyToken_7Cec85D7Bea7798E = { + /** + * Dados da resposta + */ + data?: unknown; + /** + * Código HTTP da resposta + */ + statusCode?: number; + /** + * Mensagem descritiva (opcional) + */ + message?: string | null; + /** + * Indica se a resposta representa sucesso (status code 2xx) + */ + readonly isSuccess?: boolean; +}; + +/** + * Representa a localização detectada do usuĆ”rio. + */ +export type MeAjudaAiContractsModelsUserLocation = { + /** + * Nome da cidade. + */ + city?: string | null; + /** + * Sigla do estado (UF). + */ + state?: string | null; +}; + +export type MeAjudaAiModulesDocumentsApplicationDtosDocumentDto = { + id?: string; + providerId?: string; + /** + * Tipos de documentos suportados pelo sistema + */ + documentType?: 1 | 2 | 3 | 99; + fileName?: string | null; + fileUrl?: string | null; + /** + * Status de um documento no processo de verificação + */ + status?: 1 | 2 | 3 | 4 | 5; + uploadedAt?: string; + verifiedAt?: string | null; + rejectionReason?: string | null; + ocrData?: string | null; +}; + +/** + * Request para geração de URL de upload de documento. + */ +export type MeAjudaAiModulesDocumentsApplicationDtosRequestsUploadDocumentRequest = { + /** + * ID do prestador que estĆ” enviando o documento. + */ + providerId?: string; + /** + * Tipos de documentos suportados pelo sistema + */ + documentType?: 1 | 2 | 3 | 99; + /** + * Nome do arquivo. + */ + fileName?: string | null; + /** + * Tipo de conteĆŗdo (MIME type). + */ + contentType?: string | null; + /** + * Tamanho do arquivo em bytes. + */ + fileSizeBytes?: number; +}; + +/** + * Request para verificação de documento. + */ +export type MeAjudaAiModulesDocumentsApplicationDtosRequestsVerifyDocumentRequest = { + /** + * True para aprovar, False para rejeitar + */ + isVerified?: boolean; + /** + * Notas da verificação + */ + verificationNotes?: string | null; +}; + +export type MeAjudaAiModulesDocumentsApplicationDtosUploadDocumentResponse = { + documentId?: string; + uploadUrl?: string | null; + blobName?: string | null; + expiresAt?: string; +}; + +/** + * DTO para resposta de cidade permitida + */ +export type MeAjudaAiModulesLocationsApplicationDtosAllowedCityDto = { + id?: string; + cityName?: string | null; + stateSigla?: string | null; + ibgeCode?: number | null; + latitude?: number; + longitude?: number; + serviceRadiusKm?: number; + isActive?: boolean; + createdAt?: string; + updatedAt?: string | null; + createdBy?: string | null; + updatedBy?: string | null; +}; + +/** + * Request DTO para atualização de cidade permitida + */ +export type MeAjudaAiModulesLocationsApplicationDtosRequestsUpdateAllowedCityRequest = { + cityName?: string | null; + stateSigla?: string | null; + ibgeCode?: number | null; + latitude?: number; + longitude?: number; + serviceRadiusKm?: number; + isActive?: boolean; +}; + +export type MeAjudaAiModulesProvidersApiEndpointsPublicRegisterProviderApiRequest = { + name?: string | null; + /** + * Tipo de prestador de serviƧos: None, Individual, Company, Cooperative, Freelancer. + */ + type?: 0 | 1 | 2 | 3 | 4; + documentNumber?: string | null; + phoneNumber?: string | null; +}; + +/** + * DTO para endereƧo. + */ +export type MeAjudaAiModulesProvidersApplicationDtosAddressDto = { + street?: string | null; + number?: string | null; + complement?: string | null; + neighborhood?: string | null; + city?: string | null; + state?: string | null; + zipCode?: string | null; + country?: string | null; +}; + +/** + * DTO para perfil empresarial. + */ +export type MeAjudaAiModulesProvidersApplicationDtosBusinessProfileDto = { + legalName?: string | null; + fantasyName?: string | null; + description?: string | null; + contactInfo?: MeAjudaAiModulesProvidersApplicationDtosContactInfoDto; + primaryAddress?: MeAjudaAiModulesProvidersApplicationDtosAddressDto; + showAddressToClient?: boolean; +}; + +/** + * DTO para informaƧƵes de contato. + */ +export type MeAjudaAiModulesProvidersApplicationDtosContactInfoDto = { + email?: string | null; + phoneNumber?: string | null; + website?: string | null; + additionalPhones?: Array | null; +}; + +/** + * DTO para documento. + */ +export type MeAjudaAiModulesProvidersApplicationDtosDocumentDto = { + number?: string | null; + /** + * Tipos de documentos suportados pelo sistema. + */ + documentType?: 0 | 1 | 2 | 3 | 4 | 5 | 99; + fileName?: string | null; + fileUrl?: string | null; + isPrimary?: boolean; +}; + +/** + * DTO para prestador de serviƧos. + */ +export type MeAjudaAiModulesProvidersApplicationDtosProviderDto = { + id?: string; + userId?: string; + name?: string | null; + slug?: string | null; + /** + * Tipo de prestador de serviƧos: None, Individual, Company, Cooperative, Freelancer. + */ + type?: 0 | 1 | 2 | 3 | 4; + businessProfile?: MeAjudaAiModulesProvidersApplicationDtosBusinessProfileDto; + /** + * Status do fluxo de registro do prestador de serviƧos. + */ + status?: 0 | 1 | 2 | 3 | 4 | 5; + /** + * Status de verificação do prestador de serviƧos. + */ + verificationStatus?: 0 | 1 | 2 | 3 | 4 | 5; + /** + * Tier de assinatura do prestador de serviƧos. + */ + tier?: 0 | 1 | 2 | 3; + documents?: Array | null; + qualifications?: Array | null; + services?: Array | null; + createdAt?: string; + updatedAt?: string | null; + isDeleted?: boolean; + deletedAt?: string | null; + isActive?: boolean; + suspensionReason?: string | null; + rejectionReason?: string | null; +}; + +/** + * DTO para serviƧo de um prestador. + */ +export type MeAjudaAiModulesProvidersApplicationDtosProviderServiceDto = { + serviceId?: string; + serviceName?: string | null; +}; + +/** + * DTO leve para consulta de status de aprovação e tier do prestador. + * Usado pelo endpoint GET /api/v1/providers/me/status. + */ +export type MeAjudaAiModulesProvidersApplicationDtosProviderStatusDto = { + /** + * Status do fluxo de registro do prestador de serviƧos. + */ + status?: 0 | 1 | 2 | 3 | 4 | 5; + /** + * Tier de assinatura do prestador de serviƧos. + */ + tier?: 0 | 1 | 2 | 3; + /** + * Status de verificação do prestador de serviƧos. + */ + verificationStatus?: 0 | 1 | 2 | 3 | 4 | 5; + rejectionReason?: string | null; +}; + +/** + * DTO seguro para exibição pĆŗblica de dados do prestador. + * Remove informaƧƵes sensĆ­veis como documentos, motivo de rejeição, etc. + */ +export type MeAjudaAiModulesProvidersApplicationDtosPublicProviderDto = { + id?: string; + name?: string | null; + slug?: string | null; + /** + * Tipo de prestador de serviƧos: None, Individual, Company, Cooperative, Freelancer. + */ + type?: 0 | 1 | 2 | 3 | 4; + fantasyName?: string | null; + description?: string | null; + city?: string | null; + state?: string | null; + createdAt?: string; + rating?: number | null; + reviewCount?: number; + services?: Array | null; + phoneNumbers?: Array | null; + email?: string | null; + /** + * Status de verificação do prestador de serviƧos. + */ + verificationStatus?: 0 | 1 | 2 | 3 | 4 | 5; + isActive?: boolean; +}; + +/** + * DTO para qualificação. + */ +export type MeAjudaAiModulesProvidersApplicationDtosQualificationDto = { + name?: string | null; + description?: string | null; + issuingOrganization?: string | null; + issueDate?: string | null; + expirationDate?: string | null; + documentNumber?: string | null; +}; + +/** + * Request para adição de documento a um prestador de serviƧos. + */ +export type MeAjudaAiModulesProvidersApplicationDtosRequestsAddDocumentRequest = { + /** + * NĆŗmero do documento + */ + number?: string | null; + /** + * Tipos de documentos suportados pelo sistema. + */ + documentType?: 0 | 1 | 2 | 3 | 4 | 5 | 99; + /** + * Nome do arquivo (opcional para documentos apenas numĆ©ricos) + */ + fileName?: string | null; + /** + * URL do arquivo (opcional para documentos apenas numĆ©ricos) + */ + fileUrl?: string | null; +}; + +/** + * Request para criação de um novo prestador de serviƧos. + */ +export type MeAjudaAiModulesProvidersApplicationDtosRequestsCreateProviderRequest = { + /** + * ID do usuĆ”rio proprietĆ”rio. + */ + userId?: string; + /** + * Nome do prestador. + */ + name?: string | null; + /** + * Tipo de prestador de serviƧos: None, Individual, Company, Cooperative, Freelancer. + */ + type?: 0 | 1 | 2 | 3 | 4; + businessProfile?: MeAjudaAiModulesProvidersApplicationDtosBusinessProfileDto; +}; + +/** + * Request para auto-registro de um novo prestador de serviƧos na plataforma. + * Endpoint pĆŗblico — nĆ£o requer autenticação. + */ +export type MeAjudaAiModulesProvidersApplicationDtosRequestsRegisterProviderRequest = { + /** + * Nome completo ou nome fantasia do prestador. + */ + name?: string | null; + /** + * Tipo de prestador de serviƧos: None, Individual, Company, Cooperative, Freelancer. + */ + type?: 0 | 1 | 2 | 3 | 4; + /** + * NĆŗmero de telefone profissional (obrigatório). + */ + phoneNumber?: string | null; + /** + * Email profissional do prestador. + */ + email?: string | null; + /** + * Indica que o prestador aceitou os Termos de Uso (obrigatório). + */ + acceptedTerms?: boolean; + /** + * Indica que o prestador aceitou a PolĆ­tica de Privacidade/LGPD (obrigatório). + */ + acceptedPrivacyPolicy?: boolean; + /** + * NĆŗmero do documento (CPF/CNPJ) do prestador. + */ + documentNumber?: string | null; +}; + +/** + * Request para solicitar correção de informaƧƵes bĆ”sicas de um prestador de serviƧos. + */ +export type MeAjudaAiModulesProvidersApplicationDtosRequestsRequireBasicInfoCorrectionRequest = { + /** + * Motivo detalhado da correção necessĆ”ria (obrigatório). + */ + reason?: string | null; +}; + +/** + * Request para atualização do perfil de um prestador de serviƧos. + */ +export type MeAjudaAiModulesProvidersApplicationDtosRequestsUpdateProviderProfileRequest = { + /** + * Nome do prestador. + */ + name?: string | null; + businessProfile?: MeAjudaAiModulesProvidersApplicationDtosBusinessProfileDto; + /** + * Lista de serviƧos oferecidos pelo prestador. Pode ser nulo se nĆ£o houver alteração. + */ + services?: Array | null; +}; + +/** + * Request para atualização do status de verificação de um prestador de serviƧos. + */ +export type MeAjudaAiModulesProvidersApplicationDtosRequestsUpdateVerificationStatusRequest = { + /** + * Status de verificação do prestador de serviƧos. + */ + status?: 0 | 1 | 2 | 3 | 4 | 5; + /** + * ObservaƧƵes sobre a verificação (opcional). + */ + notes?: string | null; +}; + +/** + * DTO representando coordenadas geogrĆ”ficas. + * Intervalos vĆ”lidos: Latitude [-90, 90], Longitude [-180, 180]. + */ +export type MeAjudaAiModulesSearchProvidersApplicationDtosLocationDto = { + latitude?: number; + longitude?: number; +}; + +/** + * DTO representando um provedor pesquisĆ”vel nos resultados de busca. + */ +export type MeAjudaAiModulesSearchProvidersApplicationDtosSearchableProviderDto = { + providerId?: string; + name?: string | null; + location?: MeAjudaAiModulesSearchProvidersApplicationDtosLocationDto; + averageRating?: number; + totalReviews?: number; + /** + * Representa o tier de assinatura de um provedor. + * Tiers mais altos recebem melhor posicionamento nos resultados de busca. + */ + subscriptionTier?: 0 | 1 | 2 | 3; + serviceIds?: Array | null; + slug?: string | null; + description?: string | null; + distanceInKm?: number | null; + city?: string | null; + state?: string | null; +}; + +export type MeAjudaAiModulesServiceCatalogsApiEndpointsServiceCategoryCreateServiceCategoryRequest = { + name?: string | null; + description?: string | null; + displayOrder?: number; +}; + +export type MeAjudaAiModulesServiceCatalogsApiEndpointsServiceCategoryUpdateServiceCategoryRequest = { + name?: string | null; + description?: string | null; + displayOrder?: number; +}; + +export type MeAjudaAiModulesServiceCatalogsApplicationDtosRequestsServiceChangeServiceCategoryRequest = { + newCategoryId?: string; +}; + +export type MeAjudaAiModulesServiceCatalogsApplicationDtosRequestsServiceCreateServiceRequest = { + categoryId?: string; + name?: string | null; + description?: string | null; + displayOrder?: number; +}; + +/** + * Request to update an existing service's information. + */ +export type MeAjudaAiModulesServiceCatalogsApplicationDtosRequestsServiceUpdateServiceRequest = { + name?: string | null; + description?: string | null; + displayOrder?: number; +}; + +export type MeAjudaAiModulesServiceCatalogsApplicationDtosRequestsServiceValidateServicesRequest = { + serviceIds?: Array | null; +}; + +/** + * Resposta da validação de serviƧos contendo os IDs invĆ”lidos e inativos. + */ +export type MeAjudaAiModulesServiceCatalogsApplicationDtosRequestsServiceValidateServicesResponse = { + /** + * Indica se todos os serviƧos sĆ£o vĆ”lidos. + */ + allValid?: boolean; + /** + * IDs dos serviƧos que nĆ£o existem. + */ + invalidServiceIds?: Array | null; + /** + * IDs dos serviƧos que estĆ£o inativos. + */ + inactiveServiceIds?: Array | null; +}; + +/** + * DTO para informaƧƵes de categoria de serviƧo. + */ +export type MeAjudaAiModulesServiceCatalogsApplicationDtosServiceCategoryDto = { + id?: string; + name?: string | null; + description?: string | null; + isActive?: boolean; + displayOrder?: number; + createdAt?: string; + updatedAt?: string | null; +}; + +/** + * DTO para informaƧƵes de serviƧo. + */ +export type MeAjudaAiModulesServiceCatalogsApplicationDtosServiceDto = { + id?: string; + categoryId?: string; + categoryName?: string | null; + name?: string | null; + description?: string | null; + isActive?: boolean; + displayOrder?: number; + createdAt?: string; + updatedAt?: string | null; +}; + +/** + * DTO simplificado para serviƧo sem detalhes de categoria (para listas). + */ +export type MeAjudaAiModulesServiceCatalogsApplicationDtosServiceListDto = { + id?: string; + categoryId?: string; + name?: string | null; + description?: string | null; + displayOrder?: number; + isActive?: boolean; +}; + +export type MeAjudaAiModulesUsersApiEndpointsPublicRegisterCustomerRequest = { + name?: string | null; + email?: string | null; + password?: string | null; + phoneNumber?: string | null; + termsAccepted?: boolean; + acceptedPrivacyPolicy?: boolean; +}; + +export type MeAjudaAiModulesUsersApplicationDtosRequestsCreateUserRequest = { + username?: string | null; + email?: string | null; + password?: string | null; + firstName?: string | null; + lastName?: string | null; + roles?: Array | null; + phoneNumber?: string | null; +}; + +/** + * Requisição para atualização de perfil de usuĆ”rio. + */ +export type MeAjudaAiModulesUsersApplicationDtosRequestsUpdateUserProfileRequest = { + /** + * Primeiro nome do usuĆ”rio (obrigatório). + */ + firstName?: string | null; + /** + * Sobrenome do usuĆ”rio (obrigatório). + */ + lastName?: string | null; + /** + * Email do usuĆ”rio. Envie null para nĆ£o alterar, string vĆ”lida para atualizar. + * Strings vazias ou whitespace sĆ£o rejeitadas. + */ + email?: string | null; + /** + * NĆŗmero de telefone do usuĆ”rio. Envie null para nĆ£o alterar, string vĆ”lida para atualizar. + * Strings vazias ou whitespace sĆ£o rejeitadas. + */ + phoneNumber?: string | null; +}; + +export type MeAjudaAiModulesUsersApplicationDtosUserDto = { + id?: string; + username?: string | null; + email?: string | null; + firstName?: string | null; + lastName?: string | null; + fullName?: string | null; + keycloakId?: string | null; + createdAt?: string; + updatedAt?: string | null; +}; + +export type MicrosoftAspNetCoreHttpHttpValidationProblemDetails = { + type?: string | null; + title?: string | null; + status?: number | null; + detail?: string | null; + instance?: string | null; + errors?: { + [key: string]: Array; + } | null; + [key: string]: unknown; +}; + +export type MicrosoftAspNetCoreMvcProblemDetails = { + type?: string | null; + title?: string | null; + status?: number | null; + detail?: string | null; + instance?: string | null; + [key: string]: unknown; +}; + +export type MeAjudaAiContractsFunctionalResultWritable = { + isSuccess?: boolean; + error?: MeAjudaAiContractsFunctionalError; +}; + +/** + * Representa o resultado de uma operação que pode retornar um valor de tipo . + * + * Nota sobre tipos nullable: quando Ć© um tipo de referĆŖncia nullable + * (ex.: `Result`), MeAjudaAi.Contracts.Functional.Result`1.Value pode ser `null` mesmo em caso de sucesso. + * Nesse cenĆ”rio, os atributos `[MemberNotNullWhen]` nĆ£o se aplicam e o chamador deve verificar a nulidade + * do valor separadamente. Prefira usar `Result` (nĆ£o-nullable) quando o sucesso + * garantir um valor. + */ +export type MeAjudaAiContractsFunctionalResult1MeAjudaAiContractsFunctionalUnit_MeAjudaAiContracts_Version_0000_Culture_neutral_PublicKeyToken_nullWritable = { + isSuccess?: boolean; + value?: MeAjudaAiContractsFunctionalUnit; + error?: MeAjudaAiContractsFunctionalError; +}; + +/** + * Representa o resultado de uma operação que pode retornar um valor de tipo . + * + * Nota sobre tipos nullable: quando Ć© um tipo de referĆŖncia nullable + * (ex.: `Result`), MeAjudaAi.Contracts.Functional.Result`1.Value pode ser `null` mesmo em caso de sucesso. + * Nesse cenĆ”rio, os atributos `[MemberNotNullWhen]` nĆ£o se aplicam e o chamador deve verificar a nulidade + * do valor separadamente. Prefira usar `Result` (nĆ£o-nullable) quando o sucesso + * garantir um valor. + */ +export type MeAjudaAiContractsFunctionalResult1SystemCollectionsGenericIReadOnlyList1MeAjudaAiContractsContractsModulesLocationsDtosModuleAllowedCityDto_MeAjudaAiContracts_Version_0000_Culture_neutral_PublicKeyToken_null___SystemPrivateCoreLib_Version_10000_Culture_neutral_PublicKeyToken_7Cec85D7Bea7798EWritable = { + isSuccess?: boolean; + value?: Array | null; + error?: MeAjudaAiContractsFunctionalError; +}; + +/** + * Envelope padrĆ£o para respostas paginadas da API + */ +export type MeAjudaAiContractsModelsPagedResponse1SystemCollectionsGenericIEnumerable1MeAjudaAiModulesProvidersApplicationDtosProviderDto_MeAjudaAiModulesProvidersApplication_Version_0000_Culture_neutral_PublicKeyToken_null___SystemPrivateCoreLib_Version_10000_Culture_neutral_PublicKeyToken_7Cec85D7Bea7798EWritable = { + /** + * Dados da resposta + */ + data?: Array | null; + /** + * Total de itens disponĆ­veis + */ + totalCount?: number; + /** + * PĆ”gina atual (1-based) + */ + currentPage?: number; + /** + * Tamanho da pĆ”gina + */ + pageSize?: number; +}; + +/** + * Envelope padrĆ£o para respostas paginadas da API + */ +export type MeAjudaAiContractsModelsPagedResponse1SystemCollectionsGenericIEnumerable1MeAjudaAiModulesUsersApplicationDtosUserDto_MeAjudaAiModulesUsersApplication_Version_0000_Culture_neutral_PublicKeyToken_null___SystemPrivateCoreLib_Version_10000_Culture_neutral_PublicKeyToken_7Cec85D7Bea7798EWritable = { + /** + * Dados da resposta + */ + data?: Array | null; + /** + * Total de itens disponĆ­veis + */ + totalCount?: number; + /** + * PĆ”gina atual (1-based) + */ + currentPage?: number; + /** + * Tamanho da pĆ”gina + */ + pageSize?: number; +}; + +/** + * Representa um resultado paginado de uma consulta Ć  API. + */ +export type MeAjudaAiContractsModelsPagedResult1MeAjudaAiModulesSearchProvidersApplicationDtosSearchableProviderDto_MeAjudaAiModulesSearchProvidersApplication_Version_0000_Culture_neutral_PublicKeyToken_nullWritable = { + /** + * Itens da pĆ”gina atual + */ + items: Array | null; + /** + * NĆŗmero da pĆ”gina atual (1-based) + */ + pageNumber: number; + /** + * Tamanho da pĆ”gina (quantidade de itens por pĆ”gina) + */ + pageSize: number; + /** + * Total de itens em todas as pĆ”ginas + */ + totalItems: number; +}; + +/** + * Envelope padrĆ£o para respostas da API + */ +export type MeAjudaAiContractsModelsResponse1MeAjudaAiModulesLocationsApplicationDtosAllowedCityDto_MeAjudaAiModulesLocationsApplication_Version_0000_Culture_neutral_PublicKeyToken_nullWritable = { + data?: MeAjudaAiModulesLocationsApplicationDtosAllowedCityDto; + /** + * Código HTTP da resposta + */ + statusCode?: number; + /** + * Mensagem descritiva (opcional) + */ + message?: string | null; +}; + +/** + * Envelope padrĆ£o para respostas da API + */ +export type MeAjudaAiContractsModelsResponse1MeAjudaAiModulesProvidersApplicationDtosProviderDto_MeAjudaAiModulesProvidersApplication_Version_0000_Culture_neutral_PublicKeyToken_nullWritable = { + data?: MeAjudaAiModulesProvidersApplicationDtosProviderDto; + /** + * Código HTTP da resposta + */ + statusCode?: number; + /** + * Mensagem descritiva (opcional) + */ + message?: string | null; +}; + +/** + * Envelope padrĆ£o para respostas da API + */ +export type MeAjudaAiContractsModelsResponse1MeAjudaAiModulesProvidersApplicationDtosProviderStatusDto_MeAjudaAiModulesProvidersApplication_Version_0000_Culture_neutral_PublicKeyToken_nullWritable = { + data?: MeAjudaAiModulesProvidersApplicationDtosProviderStatusDto; + /** + * Código HTTP da resposta + */ + statusCode?: number; + /** + * Mensagem descritiva (opcional) + */ + message?: string | null; +}; + +/** + * Envelope padrĆ£o para respostas da API + */ +export type MeAjudaAiContractsModelsResponse1MeAjudaAiModulesProvidersApplicationDtosPublicProviderDto_MeAjudaAiModulesProvidersApplication_Version_0000_Culture_neutral_PublicKeyToken_nullWritable = { + data?: MeAjudaAiModulesProvidersApplicationDtosPublicProviderDto; + /** + * Código HTTP da resposta + */ + statusCode?: number; + /** + * Mensagem descritiva (opcional) + */ + message?: string | null; +}; + +/** + * Envelope padrĆ£o para respostas da API + */ +export type MeAjudaAiContractsModelsResponse1MeAjudaAiModulesServiceCatalogsApplicationDtosRequestsServiceValidateServicesResponse_MeAjudaAiModulesServiceCatalogsApplication_Version_0000_Culture_neutral_PublicKeyToken_nullWritable = { + data?: MeAjudaAiModulesServiceCatalogsApplicationDtosRequestsServiceValidateServicesResponse; + /** + * Código HTTP da resposta + */ + statusCode?: number; + /** + * Mensagem descritiva (opcional) + */ + message?: string | null; +}; + +/** + * Envelope padrĆ£o para respostas da API + */ +export type MeAjudaAiContractsModelsResponse1MeAjudaAiModulesServiceCatalogsApplicationDtosServiceCategoryDto_MeAjudaAiModulesServiceCatalogsApplication_Version_0000_Culture_neutral_PublicKeyToken_nullWritable = { + data?: MeAjudaAiModulesServiceCatalogsApplicationDtosServiceCategoryDto; + /** + * Código HTTP da resposta + */ + statusCode?: number; + /** + * Mensagem descritiva (opcional) + */ + message?: string | null; +}; + +/** + * Envelope padrĆ£o para respostas da API + */ +export type MeAjudaAiContractsModelsResponse1MeAjudaAiModulesServiceCatalogsApplicationDtosServiceDto_MeAjudaAiModulesServiceCatalogsApplication_Version_0000_Culture_neutral_PublicKeyToken_nullWritable = { + data?: MeAjudaAiModulesServiceCatalogsApplicationDtosServiceDto; + /** + * Código HTTP da resposta + */ + statusCode?: number; + /** + * Mensagem descritiva (opcional) + */ + message?: string | null; +}; + +/** + * Envelope padrĆ£o para respostas da API + */ +export type MeAjudaAiContractsModelsResponse1MeAjudaAiModulesUsersApplicationDtosUserDto_MeAjudaAiModulesUsersApplication_Version_0000_Culture_neutral_PublicKeyToken_nullWritable = { + data?: MeAjudaAiModulesUsersApplicationDtosUserDto; + /** + * Código HTTP da resposta + */ + statusCode?: number; + /** + * Mensagem descritiva (opcional) + */ + message?: string | null; +}; + +/** + * Envelope padrĆ£o para respostas da API + */ +export type MeAjudaAiContractsModelsResponse1SystemCollectionsGenericIReadOnlyList1MeAjudaAiModulesProvidersApplicationDtosProviderDto_MeAjudaAiModulesProvidersApplication_Version_0000_Culture_neutral_PublicKeyToken_null___SystemPrivateCoreLib_Version_10000_Culture_neutral_PublicKeyToken_7Cec85D7Bea7798EWritable = { + /** + * Dados da resposta + */ + data?: Array | null; + /** + * Código HTTP da resposta + */ + statusCode?: number; + /** + * Mensagem descritiva (opcional) + */ + message?: string | null; +}; + +/** + * Envelope padrĆ£o para respostas da API + */ +export type MeAjudaAiContractsModelsResponse1SystemCollectionsGenericIReadOnlyList1MeAjudaAiModulesServiceCatalogsApplicationDtosServiceCategoryDto_MeAjudaAiModulesServiceCatalogsApplication_Version_0000_Culture_neutral_PublicKeyToken_null___SystemPrivateCoreLib_Version_10000_Culture_neutral_PublicKeyToken_7Cec85D7Bea7798EWritable = { + /** + * Dados da resposta + */ + data?: Array | null; + /** + * Código HTTP da resposta + */ + statusCode?: number; + /** + * Mensagem descritiva (opcional) + */ + message?: string | null; +}; + +/** + * Envelope padrĆ£o para respostas da API + */ +export type MeAjudaAiContractsModelsResponse1SystemCollectionsGenericIReadOnlyList1MeAjudaAiModulesServiceCatalogsApplicationDtosServiceListDto_MeAjudaAiModulesServiceCatalogsApplication_Version_0000_Culture_neutral_PublicKeyToken_null___SystemPrivateCoreLib_Version_10000_Culture_neutral_PublicKeyToken_7Cec85D7Bea7798EWritable = { + /** + * Dados da resposta + */ + data?: Array | null; + /** + * Código HTTP da resposta + */ + statusCode?: number; + /** + * Mensagem descritiva (opcional) + */ + message?: string | null; +}; + +/** + * Envelope padrĆ£o para respostas da API + */ +export type MeAjudaAiContractsModelsResponse1SystemGuid_SystemPrivateCoreLib_Version_10000_Culture_neutral_PublicKeyToken_7Cec85D7Bea7798EWritable = { + /** + * Dados da resposta + */ + data?: string; + /** + * Código HTTP da resposta + */ + statusCode?: number; + /** + * Mensagem descritiva (opcional) + */ + message?: string | null; +}; + +/** + * Envelope padrĆ£o para respostas da API + */ +export type MeAjudaAiContractsModelsResponse1SystemObject_SystemPrivateCoreLib_Version_10000_Culture_neutral_PublicKeyToken_7Cec85D7Bea7798EWritable = { + /** + * Dados da resposta + */ + data?: unknown; + /** + * Código HTTP da resposta + */ + statusCode?: number; + /** + * Mensagem descritiva (opcional) + */ + message?: string | null; +}; + +export type ApiAllowedCitiesGetData = { + body?: never; + path?: never; + query?: { + onlyActive?: boolean; + }; + url: '/api/v1/admin/allowed-cities'; +}; + +export type ApiAllowedCitiesGetResponses = { + /** + * OK + */ + 200: MeAjudaAiContractsFunctionalResult1SystemCollectionsGenericIReadOnlyList1MeAjudaAiContractsContractsModulesLocationsDtosModuleAllowedCityDto_MeAjudaAiContracts_Version_0000_Culture_neutral_PublicKeyToken_null___SystemPrivateCoreLib_Version_10000_Culture_neutral_PublicKeyToken_7Cec85D7Bea7798E; +}; + +export type ApiAllowedCitiesGetResponse = ApiAllowedCitiesGetResponses[keyof ApiAllowedCitiesGetResponses]; + +export type ApiAllowedCitiesPostData = { + body: MeAjudaAiContractsContractsModulesLocationsDtosCreateAllowedCityRequestDto; + path?: never; + query?: never; + url: '/api/v1/admin/allowed-cities'; +}; + +export type ApiAllowedCitiesPostErrors = { + /** + * Bad Request + */ + 400: MicrosoftAspNetCoreMvcProblemDetails; + /** + * Internal Server Error + */ + 500: MicrosoftAspNetCoreMvcProblemDetails; +}; + +export type ApiAllowedCitiesPostError = ApiAllowedCitiesPostErrors[keyof ApiAllowedCitiesPostErrors]; + +export type ApiAllowedCitiesPostResponses = { + /** + * Created + */ + 201: MeAjudaAiContractsModelsResponse1SystemGuid_SystemPrivateCoreLib_Version_10000_Culture_neutral_PublicKeyToken_7Cec85D7Bea7798E; +}; + +export type ApiAllowedCitiesPostResponse = ApiAllowedCitiesPostResponses[keyof ApiAllowedCitiesPostResponses]; + +export type ApiAllowedCitiesDeleteData = { + body?: never; + path: { + id: string; + }; + query?: never; + url: '/api/v1/admin/allowed-cities/{id}'; +}; + +export type ApiAllowedCitiesDeleteErrors = { + /** + * Not Found + */ + 404: unknown; +}; + +export type ApiAllowedCitiesDeleteResponses = { + /** + * OK + */ + 200: MeAjudaAiContractsFunctionalResult; +}; + +export type ApiAllowedCitiesDeleteResponse = ApiAllowedCitiesDeleteResponses[keyof ApiAllowedCitiesDeleteResponses]; + +export type ApiAllowedCitiesGet2Data = { + body?: never; + path: { + id: string; + }; + query?: never; + url: '/api/v1/admin/allowed-cities/{id}'; +}; + +export type ApiAllowedCitiesGet2Errors = { + /** + * Not Found + */ + 404: unknown; +}; + +export type ApiAllowedCitiesGet2Responses = { + /** + * OK + */ + 200: MeAjudaAiContractsModelsResponse1MeAjudaAiModulesLocationsApplicationDtosAllowedCityDto_MeAjudaAiModulesLocationsApplication_Version_0000_Culture_neutral_PublicKeyToken_null; +}; + +export type ApiAllowedCitiesGet2Response = ApiAllowedCitiesGet2Responses[keyof ApiAllowedCitiesGet2Responses]; + +export type ApiAllowedCitiesPatchData = { + body: MeAjudaAiContractsContractsModulesLocationsDtosPatchAllowedCityRequestDto; + path: { + id: string; + }; + query?: never; + url: '/api/v1/admin/allowed-cities/{id}'; +}; + +export type ApiAllowedCitiesPatchErrors = { + /** + * Bad Request + */ + 400: MicrosoftAspNetCoreMvcProblemDetails; + /** + * Not Found + */ + 404: MicrosoftAspNetCoreMvcProblemDetails; + /** + * Internal Server Error + */ + 500: MicrosoftAspNetCoreMvcProblemDetails; +}; + +export type ApiAllowedCitiesPatchError = ApiAllowedCitiesPatchErrors[keyof ApiAllowedCitiesPatchErrors]; + +export type ApiAllowedCitiesPatchResponses = { + /** + * OK + */ + 200: MeAjudaAiContractsFunctionalResult1MeAjudaAiContractsFunctionalUnit_MeAjudaAiContracts_Version_0000_Culture_neutral_PublicKeyToken_null; +}; + +export type ApiAllowedCitiesPatchResponse = ApiAllowedCitiesPatchResponses[keyof ApiAllowedCitiesPatchResponses]; + +export type ApiAllowedCitiesPutData = { + body: MeAjudaAiModulesLocationsApplicationDtosRequestsUpdateAllowedCityRequest; + path: { + id: string; + }; + query?: never; + url: '/api/v1/admin/allowed-cities/{id}'; +}; + +export type ApiAllowedCitiesPutErrors = { + /** + * Bad Request + */ + 400: unknown; + /** + * Not Found + */ + 404: unknown; +}; + +export type ApiAllowedCitiesPutResponses = { + /** + * No Content + */ + 204: void; +}; + +export type ApiAllowedCitiesPutResponse = ApiAllowedCitiesPutResponses[keyof ApiAllowedCitiesPutResponses]; + +export type ApiProvidersGetData = { + body?: never; + path?: never; + query?: never; + url: '/api/v1/users/auth/providers'; +}; + +export type ApiProvidersGetResponses = { + /** + * OK + */ + 200: unknown; +}; + +export type ApiClientGetData = { + body?: never; + path?: never; + query?: never; + url: '/api/configuration/client'; +}; + +export type ApiClientGetResponses = { + /** + * OK + */ + 200: MeAjudaAiContractsConfigurationClientConfiguration; +}; + +export type ApiClientGetResponse = ApiClientGetResponses[keyof ApiClientGetResponses]; + +export type ApiUploadPostData = { + body: MeAjudaAiModulesDocumentsApplicationDtosRequestsUploadDocumentRequest; + path?: never; + query?: never; + url: '/api/v1/documents/upload'; +}; + +export type ApiUploadPostErrors = { + /** + * Bad Request + */ + 400: unknown; +}; + +export type ApiUploadPostResponses = { + /** + * OK + */ + 200: MeAjudaAiModulesDocumentsApplicationDtosUploadDocumentResponse; +}; + +export type ApiUploadPostResponse = ApiUploadPostResponses[keyof ApiUploadPostResponses]; + +export type ApiStatusGetData = { + body?: never; + path: { + documentId: string; + }; + query?: never; + url: '/api/v1/documents/{documentId}/status'; +}; + +export type ApiStatusGetErrors = { + /** + * Not Found + */ + 404: unknown; +}; + +export type ApiStatusGetResponses = { + /** + * OK + */ + 200: MeAjudaAiModulesDocumentsApplicationDtosDocumentDto; +}; + +export type ApiStatusGetResponse = ApiStatusGetResponses[keyof ApiStatusGetResponses]; + +export type ApiProviderGetData = { + body?: never; + path: { + providerId: string; + }; + query?: never; + url: '/api/v1/documents/provider/{providerId}'; +}; + +export type ApiProviderGetResponses = { + /** + * OK + */ + 200: Array; +}; + +export type ApiProviderGetResponse = ApiProviderGetResponses[keyof ApiProviderGetResponses]; + +export type ApiRequestVerificationPostData = { + body?: never; + path: { + documentId: string; + }; + query?: never; + url: '/api/v1/documents/{documentId}/request-verification'; +}; + +export type ApiRequestVerificationPostErrors = { + /** + * Not Found + */ + 404: unknown; + /** + * Conflict + */ + 409: unknown; + /** + * Unprocessable Content + */ + 422: unknown; + /** + * Internal Server Error + */ + 500: MicrosoftAspNetCoreMvcProblemDetails; +}; + +export type ApiRequestVerificationPostError = ApiRequestVerificationPostErrors[keyof ApiRequestVerificationPostErrors]; + +export type ApiRequestVerificationPostResponses = { + /** + * Accepted + */ + 202: unknown; +}; + +export type ApiVerifyPostData = { + body: MeAjudaAiModulesDocumentsApplicationDtosRequestsVerifyDocumentRequest; + path: { + documentId: string; + }; + query?: never; + url: '/api/v1/documents/{documentId}/verify'; +}; + +export type ApiVerifyPostErrors = { + /** + * Bad Request + */ + 400: unknown; + /** + * Forbidden + */ + 403: unknown; + /** + * Not Found + */ + 404: unknown; +}; + +export type ApiVerifyPostResponses = { + /** + * OK + */ + 200: unknown; +}; + +export type ApiSearchGetData = { + body?: never; + path?: never; + query: { + query: string; + }; + url: '/api/v1/locations/search'; +}; + +export type ApiSearchGetResponses = { + /** + * OK + */ + 200: Array; +}; + +export type ApiSearchGetResponse = ApiSearchGetResponses[keyof ApiSearchGetResponses]; + +export type ApiProvidersGet2Data = { + body?: never; + path?: never; + query?: { + pageNumber?: number; + pageSize?: number; + name?: string; + type?: number; + verificationStatus?: number; + }; + url: '/api/v1/providers'; +}; + +export type ApiProvidersGet2Errors = { + /** + * Bad Request + */ + 400: MicrosoftAspNetCoreHttpHttpValidationProblemDetails; + /** + * Unauthorized + */ + 401: MeAjudaAiContractsModelsAuthenticationErrorResponse; + /** + * Forbidden + */ + 403: MeAjudaAiContractsModelsAuthorizationErrorResponse; + /** + * Too Many Requests + */ + 429: MeAjudaAiContractsModelsRateLimitErrorResponse; + /** + * Unavailable For Legal Reasons + */ + 451: MeAjudaAiContractsModelsGeographicRestrictionErrorResponse; + /** + * Internal Server Error + */ + 500: MeAjudaAiContractsModelsInternalServerErrorResponse; +}; + +export type ApiProvidersGet2Error = ApiProvidersGet2Errors[keyof ApiProvidersGet2Errors]; + +export type ApiProvidersGet2Responses = { + /** + * OK + */ + 200: MeAjudaAiContractsModelsPagedResponse1SystemCollectionsGenericIEnumerable1MeAjudaAiModulesProvidersApplicationDtosProviderDto_MeAjudaAiModulesProvidersApplication_Version_0000_Culture_neutral_PublicKeyToken_null___SystemPrivateCoreLib_Version_10000_Culture_neutral_PublicKeyToken_7Cec85D7Bea7798E; +}; + +export type ApiProvidersGet2Response = ApiProvidersGet2Responses[keyof ApiProvidersGet2Responses]; + +export type ApiProvidersPostData = { + /** + * Dados do prestador a ser criado + */ + body: MeAjudaAiModulesProvidersApplicationDtosRequestsCreateProviderRequest; + path?: never; + query?: never; + url: '/api/v1/providers'; +}; + +export type ApiProvidersPostErrors = { + /** + * Bad Request + */ + 400: unknown; +}; + +export type ApiProvidersPostResponses = { + /** + * Created + */ + 201: MeAjudaAiContractsModelsResponse1MeAjudaAiModulesProvidersApplicationDtosProviderDto_MeAjudaAiModulesProvidersApplication_Version_0000_Culture_neutral_PublicKeyToken_null; +}; + +export type ApiProvidersPostResponse = ApiProvidersPostResponses[keyof ApiProvidersPostResponses]; + +export type ApiProvidersDeleteData = { + body?: never; + path: { + /** + * ID Ćŗnico do prestador a ser excluĆ­do + */ + id: string; + }; + query?: never; + url: '/api/v1/providers/{id}'; +}; + +export type ApiProvidersDeleteErrors = { + /** + * Bad Request + */ + 400: unknown; + /** + * Not Found + */ + 404: unknown; +}; + +export type ApiProvidersDeleteResponses = { + /** + * No Content + */ + 204: void; +}; + +export type ApiProvidersDeleteResponse = ApiProvidersDeleteResponses[keyof ApiProvidersDeleteResponses]; + +export type ApiProvidersGet3Data = { + body?: never; + path: { + /** + * ID Ćŗnico do prestador (GUID) + */ + id: string; + }; + query?: never; + url: '/api/v1/providers/{id}'; +}; + +export type ApiProvidersGet3Errors = { + /** + * Not Found + */ + 404: unknown; +}; + +export type ApiProvidersGet3Responses = { + /** + * OK + */ + 200: MeAjudaAiContractsModelsResponse1MeAjudaAiModulesProvidersApplicationDtosProviderDto_MeAjudaAiModulesProvidersApplication_Version_0000_Culture_neutral_PublicKeyToken_null; +}; + +export type ApiProvidersGet3Response = ApiProvidersGet3Responses[keyof ApiProvidersGet3Responses]; + +export type ApiProvidersPutData = { + /** + * Dados atualizados do prestador + */ + body: MeAjudaAiModulesProvidersApplicationDtosRequestsUpdateProviderProfileRequest; + path: { + /** + * ID Ćŗnico do prestador a ser atualizado + */ + id: string; + }; + query?: never; + url: '/api/v1/providers/{id}'; +}; + +export type ApiProvidersPutErrors = { + /** + * Bad Request + */ + 400: unknown; + /** + * Not Found + */ + 404: unknown; +}; + +export type ApiProvidersPutResponses = { + /** + * OK + */ + 200: MeAjudaAiContractsModelsResponse1MeAjudaAiModulesProvidersApplicationDtosProviderDto_MeAjudaAiModulesProvidersApplication_Version_0000_Culture_neutral_PublicKeyToken_null; +}; + +export type ApiProvidersPutResponse = ApiProvidersPutResponses[keyof ApiProvidersPutResponses]; + +export type ApiPublicGetData = { + body?: never; + path: { + idOrSlug: string; + }; + query?: never; + url: '/api/v1/providers/public/{idOrSlug}'; +}; + +export type ApiPublicGetErrors = { + /** + * Not Found + */ + 404: unknown; +}; + +export type ApiPublicGetResponses = { + /** + * OK + */ + 200: MeAjudaAiContractsModelsResponse1MeAjudaAiModulesProvidersApplicationDtosPublicProviderDto_MeAjudaAiModulesProvidersApplication_Version_0000_Culture_neutral_PublicKeyToken_null; +}; + +export type ApiPublicGetResponse = ApiPublicGetResponses[keyof ApiPublicGetResponses]; + +export type ApiBecomePostData = { + body: MeAjudaAiModulesProvidersApiEndpointsPublicRegisterProviderApiRequest; + path?: never; + query?: never; + url: '/api/v1/providers/become'; +}; + +export type ApiBecomePostErrors = { + /** + * Bad Request + */ + 400: MeAjudaAiContractsModelsResponse1SystemObject_SystemPrivateCoreLib_Version_10000_Culture_neutral_PublicKeyToken_7Cec85D7Bea7798E; + /** + * Unauthorized + */ + 401: unknown; +}; + +export type ApiBecomePostError = ApiBecomePostErrors[keyof ApiBecomePostErrors]; + +export type ApiBecomePostResponses = { + /** + * Created + */ + 201: MeAjudaAiContractsModelsResponse1MeAjudaAiModulesProvidersApplicationDtosProviderDto_MeAjudaAiModulesProvidersApplication_Version_0000_Culture_neutral_PublicKeyToken_null; +}; + +export type ApiBecomePostResponse = ApiBecomePostResponses[keyof ApiBecomePostResponses]; + +export type ApiByUserGetData = { + body?: never; + path: { + /** + * ID Ćŗnico do usuĆ”rio (GUID) + */ + userId: string; + }; + query?: never; + url: '/api/v1/providers/by-user/{userId}'; +}; + +export type ApiByUserGetErrors = { + /** + * Not Found + */ + 404: unknown; +}; + +export type ApiByUserGetResponses = { + /** + * OK + */ + 200: MeAjudaAiContractsModelsResponse1MeAjudaAiModulesProvidersApplicationDtosProviderDto_MeAjudaAiModulesProvidersApplication_Version_0000_Culture_neutral_PublicKeyToken_null; +}; + +export type ApiByUserGetResponse = ApiByUserGetResponses[keyof ApiByUserGetResponses]; + +export type ApiByCityGetData = { + body?: never; + path: { + /** + * Nome da cidade para busca + */ + city: string; + }; + query?: never; + url: '/api/v1/providers/by-city/{city}'; +}; + +export type ApiByCityGetErrors = { + /** + * Bad Request + */ + 400: unknown; +}; + +export type ApiByCityGetResponses = { + /** + * OK + */ + 200: MeAjudaAiContractsModelsResponse1SystemCollectionsGenericIReadOnlyList1MeAjudaAiModulesProvidersApplicationDtosProviderDto_MeAjudaAiModulesProvidersApplication_Version_0000_Culture_neutral_PublicKeyToken_null___SystemPrivateCoreLib_Version_10000_Culture_neutral_PublicKeyToken_7Cec85D7Bea7798E; +}; + +export type ApiByCityGetResponse = ApiByCityGetResponses[keyof ApiByCityGetResponses]; + +export type ApiByStateGetData = { + body?: never; + path: { + /** + * Nome do estado para busca + */ + state: string; + }; + query?: never; + url: '/api/v1/providers/by-state/{state}'; +}; + +export type ApiByStateGetErrors = { + /** + * Bad Request + */ + 400: unknown; +}; + +export type ApiByStateGetResponses = { + /** + * OK + */ + 200: MeAjudaAiContractsModelsResponse1SystemCollectionsGenericIReadOnlyList1MeAjudaAiModulesProvidersApplicationDtosProviderDto_MeAjudaAiModulesProvidersApplication_Version_0000_Culture_neutral_PublicKeyToken_null___SystemPrivateCoreLib_Version_10000_Culture_neutral_PublicKeyToken_7Cec85D7Bea7798E; +}; + +export type ApiByStateGetResponse = ApiByStateGetResponses[keyof ApiByStateGetResponses]; + +export type ApiByTypeGetData = { + body?: never; + path: { + /** + * Tipo de prestador de serviƧos: None, Individual, Company, Cooperative, Freelancer. + */ + type: 0 | 1 | 2 | 3 | 4; + }; + query?: never; + url: '/api/v1/providers/by-type/{type}'; +}; + +export type ApiByTypeGetErrors = { + /** + * Bad Request + */ + 400: unknown; +}; + +export type ApiByTypeGetResponses = { + /** + * OK + */ + 200: MeAjudaAiContractsModelsResponse1SystemCollectionsGenericIReadOnlyList1MeAjudaAiModulesProvidersApplicationDtosProviderDto_MeAjudaAiModulesProvidersApplication_Version_0000_Culture_neutral_PublicKeyToken_null___SystemPrivateCoreLib_Version_10000_Culture_neutral_PublicKeyToken_7Cec85D7Bea7798E; +}; + +export type ApiByTypeGetResponse = ApiByTypeGetResponses[keyof ApiByTypeGetResponses]; + +export type ApiVerificationStatusGetData = { + body?: never; + path: { + /** + * Status de verificação do prestador de serviƧos. + */ + status: 0 | 1 | 2 | 3 | 4 | 5; + }; + query?: never; + url: '/api/v1/providers/verification-status/{status}'; +}; + +export type ApiVerificationStatusGetErrors = { + /** + * Bad Request + */ + 400: unknown; + /** + * Internal Server Error + */ + 500: MicrosoftAspNetCoreMvcProblemDetails; +}; + +export type ApiVerificationStatusGetError = ApiVerificationStatusGetErrors[keyof ApiVerificationStatusGetErrors]; + +export type ApiVerificationStatusGetResponses = { + /** + * OK + */ + 200: MeAjudaAiContractsModelsResponse1SystemCollectionsGenericIReadOnlyList1MeAjudaAiModulesProvidersApplicationDtosProviderDto_MeAjudaAiModulesProvidersApplication_Version_0000_Culture_neutral_PublicKeyToken_null___SystemPrivateCoreLib_Version_10000_Culture_neutral_PublicKeyToken_7Cec85D7Bea7798E; +}; + +export type ApiVerificationStatusGetResponse = ApiVerificationStatusGetResponses[keyof ApiVerificationStatusGetResponses]; + +export type ApiDocumentsPostData = { + /** + * Dados do documento a ser adicionado + */ + body: MeAjudaAiModulesProvidersApplicationDtosRequestsAddDocumentRequest; + path: { + /** + * ID Ćŗnico do prestador + */ + id: string; + }; + query?: never; + url: '/api/v1/providers/{id}/documents'; +}; + +export type ApiDocumentsPostErrors = { + /** + * Bad Request + */ + 400: unknown; + /** + * Not Found + */ + 404: unknown; +}; + +export type ApiDocumentsPostResponses = { + /** + * OK + */ + 200: MeAjudaAiContractsModelsResponse1MeAjudaAiModulesProvidersApplicationDtosProviderDto_MeAjudaAiModulesProvidersApplication_Version_0000_Culture_neutral_PublicKeyToken_null; +}; + +export type ApiDocumentsPostResponse = ApiDocumentsPostResponses[keyof ApiDocumentsPostResponses]; + +export type ApiDocumentsDeleteData = { + body?: never; + path: { + /** + * ID Ćŗnico do prestador + */ + id: string; + /** + * Tipos de documentos suportados pelo sistema. + */ + documentType: 0 | 1 | 2 | 3 | 4 | 5 | 99; + }; + query?: never; + url: '/api/v1/providers/{id}/documents/{documentType}'; +}; + +export type ApiDocumentsDeleteErrors = { + /** + * Bad Request + */ + 400: unknown; + /** + * Not Found + */ + 404: unknown; +}; + +export type ApiDocumentsDeleteResponses = { + /** + * OK + */ + 200: MeAjudaAiContractsModelsResponse1MeAjudaAiModulesProvidersApplicationDtosProviderDto_MeAjudaAiModulesProvidersApplication_Version_0000_Culture_neutral_PublicKeyToken_null; +}; + +export type ApiDocumentsDeleteResponse = ApiDocumentsDeleteResponses[keyof ApiDocumentsDeleteResponses]; + +export type ApiVerificationStatusPutData = { + /** + * Dados do novo status de verificação + */ + body: MeAjudaAiModulesProvidersApplicationDtosRequestsUpdateVerificationStatusRequest; + path: { + /** + * ID Ćŗnico do prestador + */ + id: string; + }; + query?: never; + url: '/api/v1/providers/{id}/verification-status'; +}; + +export type ApiVerificationStatusPutErrors = { + /** + * Bad Request + */ + 400: unknown; + /** + * Not Found + */ + 404: unknown; +}; + +export type ApiVerificationStatusPutResponses = { + /** + * OK + */ + 200: MeAjudaAiContractsModelsResponse1MeAjudaAiModulesProvidersApplicationDtosProviderDto_MeAjudaAiModulesProvidersApplication_Version_0000_Culture_neutral_PublicKeyToken_null; +}; + +export type ApiVerificationStatusPutResponse = ApiVerificationStatusPutResponses[keyof ApiVerificationStatusPutResponses]; + +export type ApiRequireBasicInfoCorrectionPostData = { + /** + * Dados da solicitação de correção + */ + body: MeAjudaAiModulesProvidersApplicationDtosRequestsRequireBasicInfoCorrectionRequest; + path: { + /** + * ID Ćŗnico do prestador + */ + id: string; + }; + query?: never; + url: '/api/v1/providers/{id}/require-basic-info-correction'; +}; + +export type ApiRequireBasicInfoCorrectionPostErrors = { + /** + * Bad Request + */ + 400: unknown; + /** + * Not Found + */ + 404: unknown; +}; + +export type ApiRequireBasicInfoCorrectionPostResponses = { + /** + * OK + */ + 200: unknown; +}; + +export type ApiMeGetData = { + body?: never; + path?: never; + query?: never; + url: '/api/v1/providers/me'; +}; + +export type ApiMeGetErrors = { + /** + * Not Found + */ + 404: unknown; +}; + +export type ApiMeGetResponses = { + /** + * OK + */ + 200: MeAjudaAiContractsModelsResponse1MeAjudaAiModulesProvidersApplicationDtosProviderDto_MeAjudaAiModulesProvidersApplication_Version_0000_Culture_neutral_PublicKeyToken_null; +}; + +export type ApiMeGetResponse = ApiMeGetResponses[keyof ApiMeGetResponses]; + +export type ApiMePutData = { + body: MeAjudaAiModulesProvidersApplicationDtosRequestsUpdateProviderProfileRequest; + path?: never; + query?: never; + url: '/api/v1/providers/me'; +}; + +export type ApiMePutErrors = { + /** + * Bad Request + */ + 400: unknown; + /** + * Not Found + */ + 404: unknown; +}; + +export type ApiMePutResponses = { + /** + * OK + */ + 200: MeAjudaAiContractsModelsResponse1MeAjudaAiModulesProvidersApplicationDtosProviderDto_MeAjudaAiModulesProvidersApplication_Version_0000_Culture_neutral_PublicKeyToken_null; +}; + +export type ApiMePutResponse = ApiMePutResponses[keyof ApiMePutResponses]; + +export type ApiDocumentsPost2Data = { + body: MeAjudaAiModulesProvidersApplicationDtosRequestsAddDocumentRequest; + path?: never; + query?: never; + url: '/api/v1/providers/me/documents'; +}; + +export type ApiDocumentsPost2Errors = { + /** + * Bad Request + */ + 400: unknown; + /** + * Not Found + */ + 404: unknown; +}; + +export type ApiDocumentsPost2Responses = { + /** + * OK + */ + 200: MeAjudaAiContractsModelsResponse1MeAjudaAiModulesProvidersApplicationDtosProviderDto_MeAjudaAiModulesProvidersApplication_Version_0000_Culture_neutral_PublicKeyToken_null; +}; + +export type ApiDocumentsPost2Response = ApiDocumentsPost2Responses[keyof ApiDocumentsPost2Responses]; + +export type ApiStatusGet2Data = { + body?: never; + path?: never; + query?: never; + url: '/api/v1/providers/me/status'; +}; + +export type ApiStatusGet2Errors = { + /** + * Bad Request + */ + 400: unknown; + /** + * Not Found + */ + 404: unknown; +}; + +export type ApiStatusGet2Responses = { + /** + * OK + */ + 200: MeAjudaAiContractsModelsResponse1MeAjudaAiModulesProvidersApplicationDtosProviderStatusDto_MeAjudaAiModulesProvidersApplication_Version_0000_Culture_neutral_PublicKeyToken_null; +}; + +export type ApiStatusGet2Response = ApiStatusGet2Responses[keyof ApiStatusGet2Responses]; + +export type ApiActivatePostData = { + body?: never; + path?: never; + query?: never; + url: '/api/v1/providers/me/activate'; +}; + +export type ApiActivatePostErrors = { + /** + * Bad Request + */ + 400: unknown; + /** + * Not Found + */ + 404: unknown; +}; + +export type ApiActivatePostResponses = { + /** + * OK + */ + 200: MeAjudaAiContractsModelsResponse1SystemObject_SystemPrivateCoreLib_Version_10000_Culture_neutral_PublicKeyToken_7Cec85D7Bea7798E; +}; + +export type ApiActivatePostResponse = ApiActivatePostResponses[keyof ApiActivatePostResponses]; + +export type ApiDeactivatePostData = { + body?: never; + path?: never; + query?: never; + url: '/api/v1/providers/me/deactivate'; +}; + +export type ApiDeactivatePostErrors = { + /** + * Bad Request + */ + 400: unknown; + /** + * Not Found + */ + 404: unknown; +}; + +export type ApiDeactivatePostResponses = { + /** + * OK + */ + 200: MeAjudaAiContractsModelsResponse1SystemObject_SystemPrivateCoreLib_Version_10000_Culture_neutral_PublicKeyToken_7Cec85D7Bea7798E; +}; + +export type ApiDeactivatePostResponse = ApiDeactivatePostResponses[keyof ApiDeactivatePostResponses]; + +export type ApiRegisterPostData = { + body: MeAjudaAiModulesProvidersApplicationDtosRequestsRegisterProviderRequest; + path?: never; + query?: never; + url: '/api/v1/providers/register'; +}; + +export type ApiRegisterPostErrors = { + /** + * Bad Request + */ + 400: unknown; +}; + +export type ApiRegisterPostResponses = { + /** + * Created + */ + 201: MeAjudaAiContractsModelsResponse1MeAjudaAiModulesProvidersApplicationDtosProviderDto_MeAjudaAiModulesProvidersApplication_Version_0000_Culture_neutral_PublicKeyToken_null; +}; + +export type ApiRegisterPostResponse = ApiRegisterPostResponses[keyof ApiRegisterPostResponses]; + +export type ApiServicesDeleteData = { + body?: never; + path: { + providerId: string; + serviceId: string; + }; + query?: never; + url: '/api/v1/providers/{providerId}/services/{serviceId}'; +}; + +export type ApiServicesDeleteErrors = { + /** + * Bad Request + */ + 400: unknown; + /** + * Not Found + */ + 404: unknown; +}; + +export type ApiServicesDeleteResponses = { + /** + * No Content + */ + 204: void; +}; + +export type ApiServicesDeleteResponse = ApiServicesDeleteResponses[keyof ApiServicesDeleteResponses]; + +export type ApiServicesPostData = { + body?: never; + path: { + providerId: string; + serviceId: string; + }; + query?: never; + url: '/api/v1/providers/{providerId}/services/{serviceId}'; +}; + +export type ApiServicesPostErrors = { + /** + * Bad Request + */ + 400: unknown; + /** + * Not Found + */ + 404: unknown; +}; + +export type ApiServicesPostResponses = { + /** + * No Content + */ + 204: void; +}; + +export type ApiServicesPostResponse = ApiServicesPostResponses[keyof ApiServicesPostResponses]; + +export type ApiProvidersGet4Data = { + body?: never; + path?: never; + query: { + latitude: number; + longitude: number; + radiusInKm: number; + term?: string; + serviceIds?: Array; + minRating?: number; + subscriptionTiers?: Array<0 | 1 | 2 | 3>; + page?: number; + pageSize?: number; + }; + url: '/api/v1/search/providers'; +}; + +export type ApiProvidersGet4Errors = { + /** + * Bad Request + */ + 400: MicrosoftAspNetCoreMvcProblemDetails; +}; + +export type ApiProvidersGet4Error = ApiProvidersGet4Errors[keyof ApiProvidersGet4Errors]; + +export type ApiProvidersGet4Responses = { + /** + * OK + */ + 200: MeAjudaAiContractsModelsPagedResult1MeAjudaAiModulesSearchProvidersApplicationDtosSearchableProviderDto_MeAjudaAiModulesSearchProvidersApplication_Version_0000_Culture_neutral_PublicKeyToken_null; +}; + +export type ApiProvidersGet4Response = ApiProvidersGet4Responses[keyof ApiProvidersGet4Responses]; + +export type ApiCspReportPostData = { + body?: never; + path?: never; + query?: never; + url: '/api/csp-report'; +}; + +export type ApiCspReportPostResponses = { + /** + * OK + */ + 200: unknown; +}; + +export type ApiCategoriesGetData = { + body?: never; + path?: never; + query?: { + activeOnly?: boolean; + }; + url: '/api/v1/service-catalogs/categories'; +}; + +export type ApiCategoriesGetResponses = { + /** + * OK + */ + 200: MeAjudaAiContractsModelsResponse1SystemCollectionsGenericIReadOnlyList1MeAjudaAiModulesServiceCatalogsApplicationDtosServiceCategoryDto_MeAjudaAiModulesServiceCatalogsApplication_Version_0000_Culture_neutral_PublicKeyToken_null___SystemPrivateCoreLib_Version_10000_Culture_neutral_PublicKeyToken_7Cec85D7Bea7798E; +}; + +export type ApiCategoriesGetResponse = ApiCategoriesGetResponses[keyof ApiCategoriesGetResponses]; + +export type ApiCategoriesPostData = { + body: MeAjudaAiModulesServiceCatalogsApiEndpointsServiceCategoryCreateServiceCategoryRequest; + path?: never; + query?: never; + url: '/api/v1/service-catalogs/categories'; +}; + +export type ApiCategoriesPostResponses = { + /** + * Created + */ + 201: MeAjudaAiContractsModelsResponse1MeAjudaAiModulesServiceCatalogsApplicationDtosServiceCategoryDto_MeAjudaAiModulesServiceCatalogsApplication_Version_0000_Culture_neutral_PublicKeyToken_null; +}; + +export type ApiCategoriesPostResponse = ApiCategoriesPostResponses[keyof ApiCategoriesPostResponses]; + +export type ApiCategoriesDeleteData = { + body?: never; + path: { + id: string; + }; + query?: never; + url: '/api/v1/service-catalogs/categories/{id}'; +}; + +export type ApiCategoriesDeleteResponses = { + /** + * No Content + */ + 204: void; +}; + +export type ApiCategoriesDeleteResponse = ApiCategoriesDeleteResponses[keyof ApiCategoriesDeleteResponses]; + +export type ApiCategoriesGet2Data = { + body?: never; + path: { + id: string; + }; + query?: never; + url: '/api/v1/service-catalogs/categories/{id}'; +}; + +export type ApiCategoriesGet2Errors = { + /** + * Not Found + */ + 404: unknown; +}; + +export type ApiCategoriesGet2Responses = { + /** + * OK + */ + 200: MeAjudaAiContractsModelsResponse1MeAjudaAiModulesServiceCatalogsApplicationDtosServiceCategoryDto_MeAjudaAiModulesServiceCatalogsApplication_Version_0000_Culture_neutral_PublicKeyToken_null; +}; + +export type ApiCategoriesGet2Response = ApiCategoriesGet2Responses[keyof ApiCategoriesGet2Responses]; + +export type ApiCategoriesPutData = { + body: MeAjudaAiModulesServiceCatalogsApiEndpointsServiceCategoryUpdateServiceCategoryRequest; + path: { + id: string; + }; + query?: never; + url: '/api/v1/service-catalogs/categories/{id}'; +}; + +export type ApiCategoriesPutResponses = { + /** + * No Content + */ + 204: void; +}; + +export type ApiCategoriesPutResponse = ApiCategoriesPutResponses[keyof ApiCategoriesPutResponses]; + +export type ApiActivatePost2Data = { + body?: never; + path: { + id: string; + }; + query?: never; + url: '/api/v1/service-catalogs/categories/{id}/activate'; +}; + +export type ApiActivatePost2Responses = { + /** + * No Content + */ + 204: void; +}; + +export type ApiActivatePost2Response = ApiActivatePost2Responses[keyof ApiActivatePost2Responses]; + +export type ApiDeactivatePost2Data = { + body?: never; + path: { + id: string; + }; + query?: never; + url: '/api/v1/service-catalogs/categories/{id}/deactivate'; +}; + +export type ApiDeactivatePost2Responses = { + /** + * No Content + */ + 204: void; +}; + +export type ApiDeactivatePost2Response = ApiDeactivatePost2Responses[keyof ApiDeactivatePost2Responses]; + +export type ApiServicesGetData = { + body?: never; + path?: never; + query?: { + activeOnly?: boolean; + name?: string; + }; + url: '/api/v1/service-catalogs/services'; +}; + +export type ApiServicesGetResponses = { + /** + * OK + */ + 200: MeAjudaAiContractsModelsResponse1SystemCollectionsGenericIReadOnlyList1MeAjudaAiModulesServiceCatalogsApplicationDtosServiceListDto_MeAjudaAiModulesServiceCatalogsApplication_Version_0000_Culture_neutral_PublicKeyToken_null___SystemPrivateCoreLib_Version_10000_Culture_neutral_PublicKeyToken_7Cec85D7Bea7798E; +}; + +export type ApiServicesGetResponse = ApiServicesGetResponses[keyof ApiServicesGetResponses]; + +export type ApiServicesPost2Data = { + body: MeAjudaAiModulesServiceCatalogsApplicationDtosRequestsServiceCreateServiceRequest; + path?: never; + query?: never; + url: '/api/v1/service-catalogs/services'; +}; + +export type ApiServicesPost2Responses = { + /** + * Created + */ + 201: MeAjudaAiContractsModelsResponse1MeAjudaAiModulesServiceCatalogsApplicationDtosServiceDto_MeAjudaAiModulesServiceCatalogsApplication_Version_0000_Culture_neutral_PublicKeyToken_null; +}; + +export type ApiServicesPost2Response = ApiServicesPost2Responses[keyof ApiServicesPost2Responses]; + +export type ApiServicesDelete2Data = { + body?: never; + path: { + id: string; + }; + query?: never; + url: '/api/v1/service-catalogs/services/{id}'; +}; + +export type ApiServicesDelete2Responses = { + /** + * No Content + */ + 204: void; +}; + +export type ApiServicesDelete2Response = ApiServicesDelete2Responses[keyof ApiServicesDelete2Responses]; + +export type ApiServicesGet2Data = { + body?: never; + path: { + id: string; + }; + query?: never; + url: '/api/v1/service-catalogs/services/{id}'; +}; + +export type ApiServicesGet2Errors = { + /** + * Not Found + */ + 404: unknown; +}; + +export type ApiServicesGet2Responses = { + /** + * OK + */ + 200: MeAjudaAiContractsModelsResponse1MeAjudaAiModulesServiceCatalogsApplicationDtosServiceDto_MeAjudaAiModulesServiceCatalogsApplication_Version_0000_Culture_neutral_PublicKeyToken_null; +}; + +export type ApiServicesGet2Response = ApiServicesGet2Responses[keyof ApiServicesGet2Responses]; + +export type ApiServicesPutData = { + body: MeAjudaAiModulesServiceCatalogsApplicationDtosRequestsServiceUpdateServiceRequest; + path: { + id: string; + }; + query?: never; + url: '/api/v1/service-catalogs/services/{id}'; +}; + +export type ApiServicesPutResponses = { + /** + * No Content + */ + 204: void; +}; + +export type ApiServicesPutResponse = ApiServicesPutResponses[keyof ApiServicesPutResponses]; + +export type ApiCategoryGetData = { + body?: never; + path: { + categoryId: string; + }; + query?: { + activeOnly?: boolean; + }; + url: '/api/v1/service-catalogs/services/category/{categoryId}'; +}; + +export type ApiCategoryGetResponses = { + /** + * OK + */ + 200: MeAjudaAiContractsModelsResponse1SystemCollectionsGenericIReadOnlyList1MeAjudaAiModulesServiceCatalogsApplicationDtosServiceListDto_MeAjudaAiModulesServiceCatalogsApplication_Version_0000_Culture_neutral_PublicKeyToken_null___SystemPrivateCoreLib_Version_10000_Culture_neutral_PublicKeyToken_7Cec85D7Bea7798E; +}; + +export type ApiCategoryGetResponse = ApiCategoryGetResponses[keyof ApiCategoryGetResponses]; + +export type ApiChangeCategoryPostData = { + body: MeAjudaAiModulesServiceCatalogsApplicationDtosRequestsServiceChangeServiceCategoryRequest; + path: { + id: string; + }; + query?: never; + url: '/api/v1/service-catalogs/services/{id}/change-category'; +}; + +export type ApiChangeCategoryPostResponses = { + /** + * No Content + */ + 204: void; +}; + +export type ApiChangeCategoryPostResponse = ApiChangeCategoryPostResponses[keyof ApiChangeCategoryPostResponses]; + +export type ApiActivatePost3Data = { + body?: never; + path: { + id: string; + }; + query?: never; + url: '/api/v1/service-catalogs/services/{id}/activate'; +}; + +export type ApiActivatePost3Responses = { + /** + * No Content + */ + 204: void; +}; + +export type ApiActivatePost3Response = ApiActivatePost3Responses[keyof ApiActivatePost3Responses]; + +export type ApiDeactivatePost3Data = { + body?: never; + path: { + id: string; + }; + query?: never; + url: '/api/v1/service-catalogs/services/{id}/deactivate'; +}; + +export type ApiDeactivatePost3Responses = { + /** + * No Content + */ + 204: void; +}; + +export type ApiDeactivatePost3Response = ApiDeactivatePost3Responses[keyof ApiDeactivatePost3Responses]; + +export type ApiValidatePostData = { + body: MeAjudaAiModulesServiceCatalogsApplicationDtosRequestsServiceValidateServicesRequest; + path?: never; + query?: never; + url: '/api/v1/service-catalogs/services/validate'; +}; + +export type ApiValidatePostResponses = { + /** + * OK + */ + 200: MeAjudaAiContractsModelsResponse1MeAjudaAiModulesServiceCatalogsApplicationDtosRequestsServiceValidateServicesResponse_MeAjudaAiModulesServiceCatalogsApplication_Version_0000_Culture_neutral_PublicKeyToken_null; +}; + +export type ApiValidatePostResponse = ApiValidatePostResponses[keyof ApiValidatePostResponses]; + +export type ApiUsersGetData = { + body?: never; + path?: never; + query?: { + /** + * NĆŗmero da pĆ”gina (padrĆ£o: 1) + */ + pageNumber?: number; + /** + * Tamanho da pĆ”gina (padrĆ£o: 10) + */ + pageSize?: number; + /** + * Termo de busca (opcional) + */ + searchTerm?: string; + }; + url: '/api/v1/users'; +}; + +export type ApiUsersGetErrors = { + /** + * Bad Request + */ + 400: MicrosoftAspNetCoreHttpHttpValidationProblemDetails; + /** + * Unauthorized + */ + 401: MeAjudaAiContractsModelsAuthenticationErrorResponse; + /** + * Forbidden + */ + 403: MeAjudaAiContractsModelsAuthorizationErrorResponse; + /** + * Too Many Requests + */ + 429: MeAjudaAiContractsModelsRateLimitErrorResponse; + /** + * Internal Server Error + */ + 500: MeAjudaAiContractsModelsInternalServerErrorResponse; +}; + +export type ApiUsersGetError = ApiUsersGetErrors[keyof ApiUsersGetErrors]; + +export type ApiUsersGetResponses = { + /** + * OK + */ + 200: MeAjudaAiContractsModelsPagedResponse1SystemCollectionsGenericIEnumerable1MeAjudaAiModulesUsersApplicationDtosUserDto_MeAjudaAiModulesUsersApplication_Version_0000_Culture_neutral_PublicKeyToken_null___SystemPrivateCoreLib_Version_10000_Culture_neutral_PublicKeyToken_7Cec85D7Bea7798E; +}; + +export type ApiUsersGetResponse = ApiUsersGetResponses[keyof ApiUsersGetResponses]; + +export type ApiUsersPostData = { + /** + * Dados do usuĆ”rio a ser criado + */ + body: MeAjudaAiModulesUsersApplicationDtosRequestsCreateUserRequest; + path?: never; + query?: never; + url: '/api/v1/users'; +}; + +export type ApiUsersPostErrors = { + /** + * Bad Request + */ + 400: unknown; +}; + +export type ApiUsersPostResponses = { + /** + * Created + */ + 201: MeAjudaAiContractsModelsResponse1MeAjudaAiModulesUsersApplicationDtosUserDto_MeAjudaAiModulesUsersApplication_Version_0000_Culture_neutral_PublicKeyToken_null; +}; + +export type ApiUsersPostResponse = ApiUsersPostResponses[keyof ApiUsersPostResponses]; + +export type ApiUsersDeleteData = { + body?: never; + path: { + /** + * ID Ćŗnico do usuĆ”rio a ser excluĆ­do (GUID) + */ + id: string; + }; + query?: never; + url: '/api/v1/users/{id}'; +}; + +export type ApiUsersDeleteErrors = { + /** + * Not Found + */ + 404: unknown; +}; + +export type ApiUsersDeleteResponses = { + /** + * No Content + */ + 204: void; +}; + +export type ApiUsersDeleteResponse = ApiUsersDeleteResponses[keyof ApiUsersDeleteResponses]; + +export type ApiUsersGet2Data = { + body?: never; + path: { + /** + * ID Ćŗnico do usuĆ”rio (GUID) + */ + id: string; + }; + query?: never; + url: '/api/v1/users/{id}'; +}; + +export type ApiUsersGet2Errors = { + /** + * Not Found + */ + 404: unknown; +}; + +export type ApiUsersGet2Responses = { + /** + * OK + */ + 200: MeAjudaAiContractsModelsResponse1MeAjudaAiModulesUsersApplicationDtosUserDto_MeAjudaAiModulesUsersApplication_Version_0000_Culture_neutral_PublicKeyToken_null; +}; + +export type ApiUsersGet2Response = ApiUsersGet2Responses[keyof ApiUsersGet2Responses]; + +export type ApiByEmailGetData = { + body?: never; + path: { + /** + * EndereƧo de email do usuĆ”rio + */ + email: string; + }; + query?: never; + url: '/api/v1/users/by-email/{email}'; +}; + +export type ApiByEmailGetErrors = { + /** + * Not Found + */ + 404: unknown; +}; + +export type ApiByEmailGetResponses = { + /** + * OK + */ + 200: MeAjudaAiContractsModelsResponse1MeAjudaAiModulesUsersApplicationDtosUserDto_MeAjudaAiModulesUsersApplication_Version_0000_Culture_neutral_PublicKeyToken_null; +}; + +export type ApiByEmailGetResponse = ApiByEmailGetResponses[keyof ApiByEmailGetResponses]; + +export type ApiProfilePutData = { + /** + * Dados atualizados do perfil do usuĆ”rio + */ + body: MeAjudaAiModulesUsersApplicationDtosRequestsUpdateUserProfileRequest; + path: { + /** + * Identificador Ćŗnico do usuĆ”rio a ser atualizado + */ + id: string; + }; + query?: never; + url: '/api/v1/users/{id}/profile'; +}; + +export type ApiProfilePutErrors = { + /** + * Not Found + */ + 404: unknown; +}; + +export type ApiProfilePutResponses = { + /** + * OK + */ + 200: MeAjudaAiContractsModelsResponse1MeAjudaAiModulesUsersApplicationDtosUserDto_MeAjudaAiModulesUsersApplication_Version_0000_Culture_neutral_PublicKeyToken_null; +}; + +export type ApiProfilePutResponse = ApiProfilePutResponses[keyof ApiProfilePutResponses]; + +export type ApiRegisterPost2Data = { + body: MeAjudaAiModulesUsersApiEndpointsPublicRegisterCustomerRequest; + path?: never; + query?: never; + url: '/api/v1/users/register'; +}; + +export type ApiRegisterPost2Responses = { + /** + * OK + */ + 200: unknown; +}; diff --git a/src/Web/MeAjudaAi.Web.Admin-React/src/lib/api/generated/zod.gen.ts b/src/Web/MeAjudaAi.Web.Admin-React/src/lib/api/generated/zod.gen.ts new file mode 100644 index 000000000..163aafb24 --- /dev/null +++ b/src/Web/MeAjudaAi.Web.Admin-React/src/lib/api/generated/zod.gen.ts @@ -0,0 +1,1946 @@ +// This file is auto-generated by @hey-api/openapi-ts + +import * as z from 'zod'; + +/** + * URLs de recursos externos. + */ +export const zMeAjudaAiContractsConfigurationExternalResources = z.object({ + documentationUrl: z.string().nullish(), + supportUrl: z.string().nullish() +}); + +/** + * Feature flags para habilitar/desabilitar funcionalidades no frontend. + */ +export const zMeAjudaAiContractsConfigurationFeatureFlags = z.object({ + enableReduxDevTools: z.boolean().optional(), + enableDebugMode: z.boolean().optional(), + enableFakeAuth: z.boolean().optional() +}); + +/** + * Configuração do Keycloak para autenticação OIDC. + */ +export const zMeAjudaAiContractsConfigurationKeycloakConfiguration = z.object({ + authority: z.string().nullish(), + clientId: z.string().nullish(), + responseType: z.string().nullish(), + scope: z.string().nullish(), + postLogoutRedirectUri: z.string().nullish() +}); + +/** + * Configuração do cliente Blazor WASM. + * ContĆ©m apenas informaƧƵes nĆ£o-sensĆ­veis necessĆ”rias para o frontend. + */ +export const zMeAjudaAiContractsConfigurationClientConfiguration = z.object({ + apiBaseUrl: z.string().nullish(), + keycloak: zMeAjudaAiContractsConfigurationKeycloakConfiguration.optional(), + external: zMeAjudaAiContractsConfigurationExternalResources.optional(), + features: zMeAjudaAiContractsConfigurationFeatureFlags.optional() +}); + +/** + * Request DTO para criação de cidade permitida. + * Usado pelo Admin Portal para adicionar novas cidades ao sistema. + */ +export const zMeAjudaAiContractsContractsModulesLocationsDtosCreateAllowedCityRequestDto = z.object({ + city: z.string().nullish(), + state: z.string().nullish(), + country: z.string().nullish(), + latitude: z.number().optional(), + longitude: z.number().optional(), + serviceRadiusKm: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).optional(), + isActive: z.boolean().optional() +}); + +export const zMeAjudaAiContractsContractsModulesLocationsDtosLocationCandidate = z.object({ + displayName: z.string().nullish(), + city: z.string().nullish(), + state: z.string().nullish(), + country: z.string().nullish(), + latitude: z.number().optional(), + longitude: z.number().optional() +}); + +/** + * DTO para resposta de cidade permitida. + * Usado pelo frontend para exibir cidades permitidas no sistema. + */ +export const zMeAjudaAiContractsContractsModulesLocationsDtosModuleAllowedCityDto = z.object({ + id: z.uuid().optional(), + city: z.string().nullish(), + state: z.string().nullish(), + country: z.string().nullish(), + latitude: z.number().optional(), + longitude: z.number().optional(), + isActive: z.boolean().optional(), + createdAt: z.iso.datetime().optional(), + updatedAt: z.iso.datetime().nullish(), + serviceRadiusKm: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).optional() +}); + +/** + * DTO para atualização parcial de cidade permitida. + */ +export const zMeAjudaAiContractsContractsModulesLocationsDtosPatchAllowedCityRequestDto = z.object({ + serviceRadiusKm: z.number().nullish(), + isActive: z.boolean().nullish() +}); + +/** + * Representa um erro com mensagem e código de status HTTP. + */ +export const zMeAjudaAiContractsFunctionalError = z.object({ + message: z.string().nullish(), + statusCode: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).optional() +}); + +export const zMeAjudaAiContractsFunctionalResult = z.object({ + isSuccess: z.boolean().optional(), + isFailure: z.boolean().readonly().optional(), + error: zMeAjudaAiContractsFunctionalError.optional() +}); + +/** + * Representa o resultado de uma operação que pode retornar um valor de tipo . + * + * Nota sobre tipos nullable: quando Ć© um tipo de referĆŖncia nullable + * (ex.: `Result`), MeAjudaAi.Contracts.Functional.Result`1.Value pode ser `null` mesmo em caso de sucesso. + * Nesse cenĆ”rio, os atributos `[MemberNotNullWhen]` nĆ£o se aplicam e o chamador deve verificar a nulidade + * do valor separadamente. Prefira usar `Result` (nĆ£o-nullable) quando o sucesso + * garantir um valor. + */ +export const zMeAjudaAiContractsFunctionalResult1SystemCollectionsGenericIReadOnlyList1MeAjudaAiContractsContractsModulesLocationsDtosModuleAllowedCityDto_MeAjudaAiContracts_Version_0000_Culture_neutral_PublicKeyToken_null___SystemPrivateCoreLib_Version_10000_Culture_neutral_PublicKeyToken_7Cec85D7Bea7798E = z.object({ + isSuccess: z.boolean().optional(), + isFailure: z.boolean().readonly().optional(), + value: z.array(zMeAjudaAiContractsContractsModulesLocationsDtosModuleAllowedCityDto).nullish(), + error: zMeAjudaAiContractsFunctionalError.optional() +}); + +/** + * Representa um tipo que nĆ£o retorna valor Ćŗtil. + * Usado para padronizar interfaces que podem ou nĆ£o retornar valores. + */ +export const zMeAjudaAiContractsFunctionalUnit = z.record(z.string(), z.never()); + +/** + * Representa o resultado de uma operação que pode retornar um valor de tipo . + * + * Nota sobre tipos nullable: quando Ć© um tipo de referĆŖncia nullable + * (ex.: `Result`), MeAjudaAi.Contracts.Functional.Result`1.Value pode ser `null` mesmo em caso de sucesso. + * Nesse cenĆ”rio, os atributos `[MemberNotNullWhen]` nĆ£o se aplicam e o chamador deve verificar a nulidade + * do valor separadamente. Prefira usar `Result` (nĆ£o-nullable) quando o sucesso + * garantir um valor. + */ +export const zMeAjudaAiContractsFunctionalResult1MeAjudaAiContractsFunctionalUnit_MeAjudaAiContracts_Version_0000_Culture_neutral_PublicKeyToken_null = z.object({ + isSuccess: z.boolean().optional(), + isFailure: z.boolean().readonly().optional(), + value: zMeAjudaAiContractsFunctionalUnit.optional(), + error: zMeAjudaAiContractsFunctionalError.optional() +}); + +/** + * Representa uma cidade permitida para acesso ao serviƧo. + */ +export const zMeAjudaAiContractsModelsAllowedCity = z.object({ + name: z.string().nullable(), + state: z.string().nullable(), + ibgeCode: z.string().nullish() +}); + +/** + * Modelo para erros de autenticação/autorização. + */ +export const zMeAjudaAiContractsModelsAuthenticationErrorResponse = z.object({ + statusCode: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).optional(), + title: z.string().nullish(), + detail: z.string().nullish(), + traceId: z.string().nullish(), + timestamp: z.iso.datetime().optional(), + validationErrors: z.record(z.string(), z.array(z.string())).nullish() +}); + +/** + * Modelo para erros de permissĆ£o/autorização. + */ +export const zMeAjudaAiContractsModelsAuthorizationErrorResponse = z.object({ + statusCode: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).optional(), + title: z.string().nullish(), + detail: z.string().nullish(), + traceId: z.string().nullish(), + timestamp: z.iso.datetime().optional(), + validationErrors: z.record(z.string(), z.array(z.string())).nullish() +}); + +/** + * Modelo para erros internos do servidor. + */ +export const zMeAjudaAiContractsModelsInternalServerErrorResponse = z.object({ + statusCode: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).optional(), + title: z.string().nullish(), + detail: z.string().nullish(), + traceId: z.string().nullish(), + timestamp: z.iso.datetime().optional(), + validationErrors: z.record(z.string(), z.array(z.string())).nullish() +}); + +/** + * Modelo para erros de rate limiting. + */ +export const zMeAjudaAiContractsModelsRateLimitErrorResponse = z.object({ + statusCode: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).optional(), + title: z.string().nullish(), + detail: z.string().nullish(), + traceId: z.string().nullish(), + timestamp: z.iso.datetime().optional(), + validationErrors: z.record(z.string(), z.array(z.string())).nullish(), + retryAfterSeconds: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).nullish(), + requestLimit: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).nullish(), + requestsRemaining: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).nullish() +}); + +/** + * Envelope padrĆ£o para respostas da API + */ +export const zMeAjudaAiContractsModelsResponse1SystemGuid_SystemPrivateCoreLib_Version_10000_Culture_neutral_PublicKeyToken_7Cec85D7Bea7798E = z.object({ + data: z.uuid().optional(), + statusCode: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).optional(), + message: z.string().nullish(), + isSuccess: z.boolean().readonly().optional() +}); + +/** + * Envelope padrĆ£o para respostas da API + */ +export const zMeAjudaAiContractsModelsResponse1SystemObject_SystemPrivateCoreLib_Version_10000_Culture_neutral_PublicKeyToken_7Cec85D7Bea7798E = z.object({ + data: z.unknown().optional(), + statusCode: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).optional(), + message: z.string().nullish(), + isSuccess: z.boolean().readonly().optional() +}); + +/** + * Representa a localização detectada do usuĆ”rio. + */ +export const zMeAjudaAiContractsModelsUserLocation = z.object({ + city: z.string().nullish(), + state: z.string().nullish() +}); + +/** + * Modelo para erros de restrição geogrĆ”fica (HTTP 451 - Unavailable For Legal Reasons). + */ +export const zMeAjudaAiContractsModelsGeographicRestrictionErrorResponse = z.object({ + statusCode: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).optional(), + title: z.string().nullish(), + detail: z.string().nullish(), + traceId: z.string().nullish(), + timestamp: z.iso.datetime().optional(), + validationErrors: z.record(z.string(), z.array(z.string())).nullish(), + yourLocation: zMeAjudaAiContractsModelsUserLocation.optional(), + allowedCities: z.array(zMeAjudaAiContractsModelsAllowedCity).nullish(), + allowedStates: z.array(z.string()).nullish(), + error: z.string().nullish() +}); + +export const zMeAjudaAiModulesDocumentsApplicationDtosDocumentDto = z.object({ + id: z.uuid().optional(), + providerId: z.uuid().optional(), + documentType: z.union([ + z.literal(1), + z.literal(2), + z.literal(3), + z.literal(99) + ]).optional(), + fileName: z.string().nullish(), + fileUrl: z.string().nullish(), + status: z.union([ + z.literal(1), + z.literal(2), + z.literal(3), + z.literal(4), + z.literal(5) + ]).optional(), + uploadedAt: z.iso.datetime().optional(), + verifiedAt: z.iso.datetime().nullish(), + rejectionReason: z.string().nullish(), + ocrData: z.string().nullish() +}); + +/** + * Request para geração de URL de upload de documento. + */ +export const zMeAjudaAiModulesDocumentsApplicationDtosRequestsUploadDocumentRequest = z.object({ + providerId: z.uuid().optional(), + documentType: z.union([ + z.literal(1), + z.literal(2), + z.literal(3), + z.literal(99) + ]).optional(), + fileName: z.string().nullish(), + contentType: z.string().nullish(), + fileSizeBytes: z.coerce.bigint().min(BigInt('-9223372036854775808'), { error: 'Invalid value: Expected int64 to be >= -9223372036854775808' }).max(BigInt('9223372036854775807'), { error: 'Invalid value: Expected int64 to be <= 9223372036854775807' }).optional() +}); + +/** + * Request para verificação de documento. + */ +export const zMeAjudaAiModulesDocumentsApplicationDtosRequestsVerifyDocumentRequest = z.object({ + isVerified: z.boolean().optional(), + verificationNotes: z.string().nullish() +}); + +export const zMeAjudaAiModulesDocumentsApplicationDtosUploadDocumentResponse = z.object({ + documentId: z.uuid().optional(), + uploadUrl: z.string().nullish(), + blobName: z.string().nullish(), + expiresAt: z.iso.datetime().optional() +}); + +/** + * DTO para resposta de cidade permitida + */ +export const zMeAjudaAiModulesLocationsApplicationDtosAllowedCityDto = z.object({ + id: z.uuid().optional(), + cityName: z.string().nullish(), + stateSigla: z.string().nullish(), + ibgeCode: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).nullish(), + latitude: z.number().optional(), + longitude: z.number().optional(), + serviceRadiusKm: z.number().optional(), + isActive: z.boolean().optional(), + createdAt: z.iso.datetime().optional(), + updatedAt: z.iso.datetime().nullish(), + createdBy: z.string().nullish(), + updatedBy: z.string().nullish() +}); + +/** + * Envelope padrĆ£o para respostas da API + */ +export const zMeAjudaAiContractsModelsResponse1MeAjudaAiModulesLocationsApplicationDtosAllowedCityDto_MeAjudaAiModulesLocationsApplication_Version_0000_Culture_neutral_PublicKeyToken_null = z.object({ + data: zMeAjudaAiModulesLocationsApplicationDtosAllowedCityDto.optional(), + statusCode: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).optional(), + message: z.string().nullish(), + isSuccess: z.boolean().readonly().optional() +}); + +/** + * Request DTO para atualização de cidade permitida + */ +export const zMeAjudaAiModulesLocationsApplicationDtosRequestsUpdateAllowedCityRequest = z.object({ + cityName: z.string().nullish(), + stateSigla: z.string().nullish(), + ibgeCode: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).nullish(), + latitude: z.number().optional(), + longitude: z.number().optional(), + serviceRadiusKm: z.number().optional(), + isActive: z.boolean().optional() +}); + +export const zMeAjudaAiModulesProvidersApiEndpointsPublicRegisterProviderApiRequest = z.object({ + name: z.string().nullish(), + type: z.union([ + z.literal(0), + z.literal(1), + z.literal(2), + z.literal(3), + z.literal(4) + ]).optional(), + documentNumber: z.string().nullish(), + phoneNumber: z.string().nullish() +}); + +/** + * DTO para endereƧo. + */ +export const zMeAjudaAiModulesProvidersApplicationDtosAddressDto = z.object({ + street: z.string().nullish(), + number: z.string().nullish(), + complement: z.string().nullish(), + neighborhood: z.string().nullish(), + city: z.string().nullish(), + state: z.string().nullish(), + zipCode: z.string().nullish(), + country: z.string().nullish() +}); + +/** + * DTO para informaƧƵes de contato. + */ +export const zMeAjudaAiModulesProvidersApplicationDtosContactInfoDto = z.object({ + email: z.string().nullish(), + phoneNumber: z.string().nullish(), + website: z.string().nullish(), + additionalPhones: z.array(z.string()).nullish() +}); + +/** + * DTO para perfil empresarial. + */ +export const zMeAjudaAiModulesProvidersApplicationDtosBusinessProfileDto = z.object({ + legalName: z.string().nullish(), + fantasyName: z.string().nullish(), + description: z.string().nullish(), + contactInfo: zMeAjudaAiModulesProvidersApplicationDtosContactInfoDto.optional(), + primaryAddress: zMeAjudaAiModulesProvidersApplicationDtosAddressDto.optional(), + showAddressToClient: z.boolean().optional() +}); + +/** + * DTO para documento. + */ +export const zMeAjudaAiModulesProvidersApplicationDtosDocumentDto = z.object({ + number: z.string().nullish(), + documentType: z.union([ + z.literal(0), + z.literal(1), + z.literal(2), + z.literal(3), + z.literal(4), + z.literal(5), + z.literal(99) + ]).optional(), + fileName: z.string().nullish(), + fileUrl: z.string().nullish(), + isPrimary: z.boolean().optional() +}); + +/** + * DTO para serviƧo de um prestador. + */ +export const zMeAjudaAiModulesProvidersApplicationDtosProviderServiceDto = z.object({ + serviceId: z.uuid().optional(), + serviceName: z.string().nullish() +}); + +/** + * DTO leve para consulta de status de aprovação e tier do prestador. + * Usado pelo endpoint GET /api/v1/providers/me/status. + */ +export const zMeAjudaAiModulesProvidersApplicationDtosProviderStatusDto = z.object({ + status: z.union([ + z.literal(0), + z.literal(1), + z.literal(2), + z.literal(3), + z.literal(4), + z.literal(5) + ]).optional(), + tier: z.union([ + z.literal(0), + z.literal(1), + z.literal(2), + z.literal(3) + ]).optional(), + verificationStatus: z.union([ + z.literal(0), + z.literal(1), + z.literal(2), + z.literal(3), + z.literal(4), + z.literal(5) + ]).optional(), + rejectionReason: z.string().nullish() +}); + +/** + * Envelope padrĆ£o para respostas da API + */ +export const zMeAjudaAiContractsModelsResponse1MeAjudaAiModulesProvidersApplicationDtosProviderStatusDto_MeAjudaAiModulesProvidersApplication_Version_0000_Culture_neutral_PublicKeyToken_null = z.object({ + data: zMeAjudaAiModulesProvidersApplicationDtosProviderStatusDto.optional(), + statusCode: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).optional(), + message: z.string().nullish(), + isSuccess: z.boolean().readonly().optional() +}); + +/** + * DTO seguro para exibição pĆŗblica de dados do prestador. + * Remove informaƧƵes sensĆ­veis como documentos, motivo de rejeição, etc. + */ +export const zMeAjudaAiModulesProvidersApplicationDtosPublicProviderDto = z.object({ + id: z.uuid().optional(), + name: z.string().nullish(), + slug: z.string().nullish(), + type: z.union([ + z.literal(0), + z.literal(1), + z.literal(2), + z.literal(3), + z.literal(4) + ]).optional(), + fantasyName: z.string().nullish(), + description: z.string().nullish(), + city: z.string().nullish(), + state: z.string().nullish(), + createdAt: z.iso.datetime().optional(), + rating: z.number().nullish(), + reviewCount: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).optional(), + services: z.array(z.string()).nullish(), + phoneNumbers: z.array(z.string()).nullish(), + email: z.string().nullish(), + verificationStatus: z.union([ + z.literal(0), + z.literal(1), + z.literal(2), + z.literal(3), + z.literal(4), + z.literal(5) + ]).optional(), + isActive: z.boolean().optional() +}); + +/** + * Envelope padrĆ£o para respostas da API + */ +export const zMeAjudaAiContractsModelsResponse1MeAjudaAiModulesProvidersApplicationDtosPublicProviderDto_MeAjudaAiModulesProvidersApplication_Version_0000_Culture_neutral_PublicKeyToken_null = z.object({ + data: zMeAjudaAiModulesProvidersApplicationDtosPublicProviderDto.optional(), + statusCode: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).optional(), + message: z.string().nullish(), + isSuccess: z.boolean().readonly().optional() +}); + +/** + * DTO para qualificação. + */ +export const zMeAjudaAiModulesProvidersApplicationDtosQualificationDto = z.object({ + name: z.string().nullish(), + description: z.string().nullish(), + issuingOrganization: z.string().nullish(), + issueDate: z.iso.datetime().nullish(), + expirationDate: z.iso.datetime().nullish(), + documentNumber: z.string().nullish() +}); + +/** + * DTO para prestador de serviƧos. + */ +export const zMeAjudaAiModulesProvidersApplicationDtosProviderDto = z.object({ + id: z.uuid().optional(), + userId: z.uuid().optional(), + name: z.string().nullish(), + slug: z.string().nullish(), + type: z.union([ + z.literal(0), + z.literal(1), + z.literal(2), + z.literal(3), + z.literal(4) + ]).optional(), + businessProfile: zMeAjudaAiModulesProvidersApplicationDtosBusinessProfileDto.optional(), + status: z.union([ + z.literal(0), + z.literal(1), + z.literal(2), + z.literal(3), + z.literal(4), + z.literal(5) + ]).optional(), + verificationStatus: z.union([ + z.literal(0), + z.literal(1), + z.literal(2), + z.literal(3), + z.literal(4), + z.literal(5) + ]).optional(), + tier: z.union([ + z.literal(0), + z.literal(1), + z.literal(2), + z.literal(3) + ]).optional(), + documents: z.array(zMeAjudaAiModulesProvidersApplicationDtosDocumentDto).nullish(), + qualifications: z.array(zMeAjudaAiModulesProvidersApplicationDtosQualificationDto).nullish(), + services: z.array(zMeAjudaAiModulesProvidersApplicationDtosProviderServiceDto).nullish(), + createdAt: z.iso.datetime().optional(), + updatedAt: z.iso.datetime().nullish(), + isDeleted: z.boolean().optional(), + deletedAt: z.iso.datetime().nullish(), + isActive: z.boolean().optional(), + suspensionReason: z.string().nullish(), + rejectionReason: z.string().nullish() +}); + +/** + * Envelope padrĆ£o para respostas paginadas da API + */ +export const zMeAjudaAiContractsModelsPagedResponse1SystemCollectionsGenericIEnumerable1MeAjudaAiModulesProvidersApplicationDtosProviderDto_MeAjudaAiModulesProvidersApplication_Version_0000_Culture_neutral_PublicKeyToken_null___SystemPrivateCoreLib_Version_10000_Culture_neutral_PublicKeyToken_7Cec85D7Bea7798E = z.object({ + data: z.array(zMeAjudaAiModulesProvidersApplicationDtosProviderDto).nullish(), + totalCount: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).optional(), + currentPage: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).optional(), + pageSize: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).optional(), + totalPages: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).readonly().optional() +}); + +/** + * Envelope padrĆ£o para respostas da API + */ +export const zMeAjudaAiContractsModelsResponse1MeAjudaAiModulesProvidersApplicationDtosProviderDto_MeAjudaAiModulesProvidersApplication_Version_0000_Culture_neutral_PublicKeyToken_null = z.object({ + data: zMeAjudaAiModulesProvidersApplicationDtosProviderDto.optional(), + statusCode: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).optional(), + message: z.string().nullish(), + isSuccess: z.boolean().readonly().optional() +}); + +/** + * Envelope padrĆ£o para respostas da API + */ +export const zMeAjudaAiContractsModelsResponse1SystemCollectionsGenericIReadOnlyList1MeAjudaAiModulesProvidersApplicationDtosProviderDto_MeAjudaAiModulesProvidersApplication_Version_0000_Culture_neutral_PublicKeyToken_null___SystemPrivateCoreLib_Version_10000_Culture_neutral_PublicKeyToken_7Cec85D7Bea7798E = z.object({ + data: z.array(zMeAjudaAiModulesProvidersApplicationDtosProviderDto).nullish(), + statusCode: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).optional(), + message: z.string().nullish(), + isSuccess: z.boolean().readonly().optional() +}); + +/** + * Request para adição de documento a um prestador de serviƧos. + */ +export const zMeAjudaAiModulesProvidersApplicationDtosRequestsAddDocumentRequest = z.object({ + number: z.string().nullish(), + documentType: z.union([ + z.literal(0), + z.literal(1), + z.literal(2), + z.literal(3), + z.literal(4), + z.literal(5), + z.literal(99) + ]).optional(), + fileName: z.string().nullish(), + fileUrl: z.string().nullish() +}); + +/** + * Request para criação de um novo prestador de serviƧos. + */ +export const zMeAjudaAiModulesProvidersApplicationDtosRequestsCreateProviderRequest = z.object({ + userId: z.uuid().optional(), + name: z.string().nullish(), + type: z.union([ + z.literal(0), + z.literal(1), + z.literal(2), + z.literal(3), + z.literal(4) + ]).optional(), + businessProfile: zMeAjudaAiModulesProvidersApplicationDtosBusinessProfileDto.optional() +}); + +/** + * Request para auto-registro de um novo prestador de serviƧos na plataforma. + * Endpoint pĆŗblico — nĆ£o requer autenticação. + */ +export const zMeAjudaAiModulesProvidersApplicationDtosRequestsRegisterProviderRequest = z.object({ + name: z.string().nullish(), + type: z.union([ + z.literal(0), + z.literal(1), + z.literal(2), + z.literal(3), + z.literal(4) + ]).optional(), + phoneNumber: z.string().nullish(), + email: z.string().nullish(), + acceptedTerms: z.boolean().optional(), + acceptedPrivacyPolicy: z.boolean().optional(), + documentNumber: z.string().nullish() +}); + +/** + * Request para solicitar correção de informaƧƵes bĆ”sicas de um prestador de serviƧos. + */ +export const zMeAjudaAiModulesProvidersApplicationDtosRequestsRequireBasicInfoCorrectionRequest = z.object({ + reason: z.string().nullish() +}); + +/** + * Request para atualização do perfil de um prestador de serviƧos. + */ +export const zMeAjudaAiModulesProvidersApplicationDtosRequestsUpdateProviderProfileRequest = z.object({ + name: z.string().nullish(), + businessProfile: zMeAjudaAiModulesProvidersApplicationDtosBusinessProfileDto.optional(), + services: z.array(zMeAjudaAiModulesProvidersApplicationDtosProviderServiceDto).nullish() +}); + +/** + * Request para atualização do status de verificação de um prestador de serviƧos. + */ +export const zMeAjudaAiModulesProvidersApplicationDtosRequestsUpdateVerificationStatusRequest = z.object({ + status: z.union([ + z.literal(0), + z.literal(1), + z.literal(2), + z.literal(3), + z.literal(4), + z.literal(5) + ]).optional(), + notes: z.string().nullish() +}); + +/** + * DTO representando coordenadas geogrĆ”ficas. + * Intervalos vĆ”lidos: Latitude [-90, 90], Longitude [-180, 180]. + */ +export const zMeAjudaAiModulesSearchProvidersApplicationDtosLocationDto = z.object({ + latitude: z.number().gte(-90).lte(90).optional(), + longitude: z.number().gte(-180).lte(180).optional() +}); + +/** + * DTO representando um provedor pesquisĆ”vel nos resultados de busca. + */ +export const zMeAjudaAiModulesSearchProvidersApplicationDtosSearchableProviderDto = z.object({ + providerId: z.uuid().optional(), + name: z.string().nullish(), + location: zMeAjudaAiModulesSearchProvidersApplicationDtosLocationDto.optional(), + averageRating: z.number().optional(), + totalReviews: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).optional(), + subscriptionTier: z.union([ + z.literal(0), + z.literal(1), + z.literal(2), + z.literal(3) + ]).optional(), + serviceIds: z.array(z.uuid()).nullish(), + slug: z.string().nullish(), + description: z.string().nullish(), + distanceInKm: z.number().nullish(), + city: z.string().nullish(), + state: z.string().nullish() +}); + +/** + * Representa um resultado paginado de uma consulta Ć  API. + */ +export const zMeAjudaAiContractsModelsPagedResult1MeAjudaAiModulesSearchProvidersApplicationDtosSearchableProviderDto_MeAjudaAiModulesSearchProvidersApplication_Version_0000_Culture_neutral_PublicKeyToken_null = z.object({ + items: z.array(zMeAjudaAiModulesSearchProvidersApplicationDtosSearchableProviderDto).nullable(), + pageNumber: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }), + pageSize: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }), + totalItems: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }), + totalPages: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).readonly().optional(), + hasPreviousPage: z.boolean().readonly().optional(), + hasNextPage: z.boolean().readonly().optional() +}); + +export const zMeAjudaAiModulesServiceCatalogsApiEndpointsServiceCategoryCreateServiceCategoryRequest = z.object({ + name: z.string().nullish(), + description: z.string().nullish(), + displayOrder: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).optional() +}); + +export const zMeAjudaAiModulesServiceCatalogsApiEndpointsServiceCategoryUpdateServiceCategoryRequest = z.object({ + name: z.string().nullish(), + description: z.string().nullish(), + displayOrder: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).optional() +}); + +export const zMeAjudaAiModulesServiceCatalogsApplicationDtosRequestsServiceChangeServiceCategoryRequest = z.object({ + newCategoryId: z.uuid().optional() +}); + +export const zMeAjudaAiModulesServiceCatalogsApplicationDtosRequestsServiceCreateServiceRequest = z.object({ + categoryId: z.uuid().optional(), + name: z.string().nullish(), + description: z.string().nullish(), + displayOrder: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).optional() +}); + +/** + * Request to update an existing service's information. + */ +export const zMeAjudaAiModulesServiceCatalogsApplicationDtosRequestsServiceUpdateServiceRequest = z.object({ + name: z.string().nullish(), + description: z.string().nullish(), + displayOrder: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).optional() +}); + +export const zMeAjudaAiModulesServiceCatalogsApplicationDtosRequestsServiceValidateServicesRequest = z.object({ + serviceIds: z.array(z.uuid()).nullish() +}); + +/** + * Resposta da validação de serviƧos contendo os IDs invĆ”lidos e inativos. + */ +export const zMeAjudaAiModulesServiceCatalogsApplicationDtosRequestsServiceValidateServicesResponse = z.object({ + allValid: z.boolean().optional(), + invalidServiceIds: z.array(z.uuid()).nullish(), + inactiveServiceIds: z.array(z.uuid()).nullish() +}); + +/** + * Envelope padrĆ£o para respostas da API + */ +export const zMeAjudaAiContractsModelsResponse1MeAjudaAiModulesServiceCatalogsApplicationDtosRequestsServiceValidateServicesResponse_MeAjudaAiModulesServiceCatalogsApplication_Version_0000_Culture_neutral_PublicKeyToken_null = z.object({ + data: zMeAjudaAiModulesServiceCatalogsApplicationDtosRequestsServiceValidateServicesResponse.optional(), + statusCode: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).optional(), + message: z.string().nullish(), + isSuccess: z.boolean().readonly().optional() +}); + +/** + * DTO para informaƧƵes de categoria de serviƧo. + */ +export const zMeAjudaAiModulesServiceCatalogsApplicationDtosServiceCategoryDto = z.object({ + id: z.uuid().optional(), + name: z.string().nullish(), + description: z.string().nullish(), + isActive: z.boolean().optional(), + displayOrder: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).optional(), + createdAt: z.iso.datetime().optional(), + updatedAt: z.iso.datetime().nullish() +}); + +/** + * Envelope padrĆ£o para respostas da API + */ +export const zMeAjudaAiContractsModelsResponse1MeAjudaAiModulesServiceCatalogsApplicationDtosServiceCategoryDto_MeAjudaAiModulesServiceCatalogsApplication_Version_0000_Culture_neutral_PublicKeyToken_null = z.object({ + data: zMeAjudaAiModulesServiceCatalogsApplicationDtosServiceCategoryDto.optional(), + statusCode: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).optional(), + message: z.string().nullish(), + isSuccess: z.boolean().readonly().optional() +}); + +/** + * Envelope padrĆ£o para respostas da API + */ +export const zMeAjudaAiContractsModelsResponse1SystemCollectionsGenericIReadOnlyList1MeAjudaAiModulesServiceCatalogsApplicationDtosServiceCategoryDto_MeAjudaAiModulesServiceCatalogsApplication_Version_0000_Culture_neutral_PublicKeyToken_null___SystemPrivateCoreLib_Version_10000_Culture_neutral_PublicKeyToken_7Cec85D7Bea7798E = z.object({ + data: z.array(zMeAjudaAiModulesServiceCatalogsApplicationDtosServiceCategoryDto).nullish(), + statusCode: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).optional(), + message: z.string().nullish(), + isSuccess: z.boolean().readonly().optional() +}); + +/** + * DTO para informaƧƵes de serviƧo. + */ +export const zMeAjudaAiModulesServiceCatalogsApplicationDtosServiceDto = z.object({ + id: z.uuid().optional(), + categoryId: z.uuid().optional(), + categoryName: z.string().nullish(), + name: z.string().nullish(), + description: z.string().nullish(), + isActive: z.boolean().optional(), + displayOrder: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).optional(), + createdAt: z.iso.datetime().optional(), + updatedAt: z.iso.datetime().nullish() +}); + +/** + * Envelope padrĆ£o para respostas da API + */ +export const zMeAjudaAiContractsModelsResponse1MeAjudaAiModulesServiceCatalogsApplicationDtosServiceDto_MeAjudaAiModulesServiceCatalogsApplication_Version_0000_Culture_neutral_PublicKeyToken_null = z.object({ + data: zMeAjudaAiModulesServiceCatalogsApplicationDtosServiceDto.optional(), + statusCode: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).optional(), + message: z.string().nullish(), + isSuccess: z.boolean().readonly().optional() +}); + +/** + * DTO simplificado para serviƧo sem detalhes de categoria (para listas). + */ +export const zMeAjudaAiModulesServiceCatalogsApplicationDtosServiceListDto = z.object({ + id: z.uuid().optional(), + categoryId: z.uuid().optional(), + name: z.string().nullish(), + description: z.string().nullish(), + displayOrder: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).optional(), + isActive: z.boolean().optional() +}); + +/** + * Envelope padrĆ£o para respostas da API + */ +export const zMeAjudaAiContractsModelsResponse1SystemCollectionsGenericIReadOnlyList1MeAjudaAiModulesServiceCatalogsApplicationDtosServiceListDto_MeAjudaAiModulesServiceCatalogsApplication_Version_0000_Culture_neutral_PublicKeyToken_null___SystemPrivateCoreLib_Version_10000_Culture_neutral_PublicKeyToken_7Cec85D7Bea7798E = z.object({ + data: z.array(zMeAjudaAiModulesServiceCatalogsApplicationDtosServiceListDto).nullish(), + statusCode: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).optional(), + message: z.string().nullish(), + isSuccess: z.boolean().readonly().optional() +}); + +export const zMeAjudaAiModulesUsersApiEndpointsPublicRegisterCustomerRequest = z.object({ + name: z.string().nullish(), + email: z.string().nullish(), + password: z.string().nullish(), + phoneNumber: z.string().nullish(), + termsAccepted: z.boolean().optional(), + acceptedPrivacyPolicy: z.boolean().optional() +}); + +export const zMeAjudaAiModulesUsersApplicationDtosRequestsCreateUserRequest = z.object({ + username: z.string().nullish(), + email: z.string().nullish(), + password: z.string().nullish(), + firstName: z.string().nullish(), + lastName: z.string().nullish(), + roles: z.array(z.string()).nullish(), + phoneNumber: z.string().nullish() +}); + +/** + * Requisição para atualização de perfil de usuĆ”rio. + */ +export const zMeAjudaAiModulesUsersApplicationDtosRequestsUpdateUserProfileRequest = z.object({ + firstName: z.string().nullish(), + lastName: z.string().nullish(), + email: z.string().nullish(), + phoneNumber: z.string().nullish() +}); + +export const zMeAjudaAiModulesUsersApplicationDtosUserDto = z.object({ + id: z.uuid().optional(), + username: z.string().nullish(), + email: z.string().nullish(), + firstName: z.string().nullish(), + lastName: z.string().nullish(), + fullName: z.string().nullish(), + keycloakId: z.string().nullish(), + createdAt: z.iso.datetime().optional(), + updatedAt: z.iso.datetime().nullish() +}); + +/** + * Envelope padrĆ£o para respostas paginadas da API + */ +export const zMeAjudaAiContractsModelsPagedResponse1SystemCollectionsGenericIEnumerable1MeAjudaAiModulesUsersApplicationDtosUserDto_MeAjudaAiModulesUsersApplication_Version_0000_Culture_neutral_PublicKeyToken_null___SystemPrivateCoreLib_Version_10000_Culture_neutral_PublicKeyToken_7Cec85D7Bea7798E = z.object({ + data: z.array(zMeAjudaAiModulesUsersApplicationDtosUserDto).nullish(), + totalCount: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).optional(), + currentPage: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).optional(), + pageSize: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).optional(), + totalPages: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).readonly().optional() +}); + +/** + * Envelope padrĆ£o para respostas da API + */ +export const zMeAjudaAiContractsModelsResponse1MeAjudaAiModulesUsersApplicationDtosUserDto_MeAjudaAiModulesUsersApplication_Version_0000_Culture_neutral_PublicKeyToken_null = z.object({ + data: zMeAjudaAiModulesUsersApplicationDtosUserDto.optional(), + statusCode: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).optional(), + message: z.string().nullish(), + isSuccess: z.boolean().readonly().optional() +}); + +export const zMicrosoftAspNetCoreHttpHttpValidationProblemDetails = z.object({ + type: z.string().nullish(), + title: z.string().nullish(), + status: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).nullish(), + detail: z.string().nullish(), + instance: z.string().nullish(), + errors: z.record(z.string(), z.array(z.string())).nullish() +}); + +export const zMicrosoftAspNetCoreMvcProblemDetails = z.object({ + type: z.string().nullish(), + title: z.string().nullish(), + status: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).nullish(), + detail: z.string().nullish(), + instance: z.string().nullish() +}); + +export const zMeAjudaAiContractsFunctionalResultWritable = z.object({ + isSuccess: z.boolean().optional(), + error: zMeAjudaAiContractsFunctionalError.optional() +}); + +/** + * Representa o resultado de uma operação que pode retornar um valor de tipo . + * + * Nota sobre tipos nullable: quando Ć© um tipo de referĆŖncia nullable + * (ex.: `Result`), MeAjudaAi.Contracts.Functional.Result`1.Value pode ser `null` mesmo em caso de sucesso. + * Nesse cenĆ”rio, os atributos `[MemberNotNullWhen]` nĆ£o se aplicam e o chamador deve verificar a nulidade + * do valor separadamente. Prefira usar `Result` (nĆ£o-nullable) quando o sucesso + * garantir um valor. + */ +export const zMeAjudaAiContractsFunctionalResult1MeAjudaAiContractsFunctionalUnit_MeAjudaAiContracts_Version_0000_Culture_neutral_PublicKeyToken_nullWritable = z.object({ + isSuccess: z.boolean().optional(), + value: zMeAjudaAiContractsFunctionalUnit.optional(), + error: zMeAjudaAiContractsFunctionalError.optional() +}); + +/** + * Representa o resultado de uma operação que pode retornar um valor de tipo . + * + * Nota sobre tipos nullable: quando Ć© um tipo de referĆŖncia nullable + * (ex.: `Result`), MeAjudaAi.Contracts.Functional.Result`1.Value pode ser `null` mesmo em caso de sucesso. + * Nesse cenĆ”rio, os atributos `[MemberNotNullWhen]` nĆ£o se aplicam e o chamador deve verificar a nulidade + * do valor separadamente. Prefira usar `Result` (nĆ£o-nullable) quando o sucesso + * garantir um valor. + */ +export const zMeAjudaAiContractsFunctionalResult1SystemCollectionsGenericIReadOnlyList1MeAjudaAiContractsContractsModulesLocationsDtosModuleAllowedCityDto_MeAjudaAiContracts_Version_0000_Culture_neutral_PublicKeyToken_null___SystemPrivateCoreLib_Version_10000_Culture_neutral_PublicKeyToken_7Cec85D7Bea7798EWritable = z.object({ + isSuccess: z.boolean().optional(), + value: z.array(zMeAjudaAiContractsContractsModulesLocationsDtosModuleAllowedCityDto).nullish(), + error: zMeAjudaAiContractsFunctionalError.optional() +}); + +/** + * Envelope padrĆ£o para respostas paginadas da API + */ +export const zMeAjudaAiContractsModelsPagedResponse1SystemCollectionsGenericIEnumerable1MeAjudaAiModulesProvidersApplicationDtosProviderDto_MeAjudaAiModulesProvidersApplication_Version_0000_Culture_neutral_PublicKeyToken_null___SystemPrivateCoreLib_Version_10000_Culture_neutral_PublicKeyToken_7Cec85D7Bea7798EWritable = z.object({ + data: z.array(zMeAjudaAiModulesProvidersApplicationDtosProviderDto).nullish(), + totalCount: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).optional(), + currentPage: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).optional(), + pageSize: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).optional() +}); + +/** + * Envelope padrĆ£o para respostas paginadas da API + */ +export const zMeAjudaAiContractsModelsPagedResponse1SystemCollectionsGenericIEnumerable1MeAjudaAiModulesUsersApplicationDtosUserDto_MeAjudaAiModulesUsersApplication_Version_0000_Culture_neutral_PublicKeyToken_null___SystemPrivateCoreLib_Version_10000_Culture_neutral_PublicKeyToken_7Cec85D7Bea7798EWritable = z.object({ + data: z.array(zMeAjudaAiModulesUsersApplicationDtosUserDto).nullish(), + totalCount: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).optional(), + currentPage: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).optional(), + pageSize: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).optional() +}); + +/** + * Representa um resultado paginado de uma consulta Ć  API. + */ +export const zMeAjudaAiContractsModelsPagedResult1MeAjudaAiModulesSearchProvidersApplicationDtosSearchableProviderDto_MeAjudaAiModulesSearchProvidersApplication_Version_0000_Culture_neutral_PublicKeyToken_nullWritable = z.object({ + items: z.array(zMeAjudaAiModulesSearchProvidersApplicationDtosSearchableProviderDto).nullable(), + pageNumber: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }), + pageSize: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }), + totalItems: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }) +}); + +/** + * Envelope padrĆ£o para respostas da API + */ +export const zMeAjudaAiContractsModelsResponse1MeAjudaAiModulesLocationsApplicationDtosAllowedCityDto_MeAjudaAiModulesLocationsApplication_Version_0000_Culture_neutral_PublicKeyToken_nullWritable = z.object({ + data: zMeAjudaAiModulesLocationsApplicationDtosAllowedCityDto.optional(), + statusCode: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).optional(), + message: z.string().nullish() +}); + +/** + * Envelope padrĆ£o para respostas da API + */ +export const zMeAjudaAiContractsModelsResponse1MeAjudaAiModulesProvidersApplicationDtosProviderDto_MeAjudaAiModulesProvidersApplication_Version_0000_Culture_neutral_PublicKeyToken_nullWritable = z.object({ + data: zMeAjudaAiModulesProvidersApplicationDtosProviderDto.optional(), + statusCode: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).optional(), + message: z.string().nullish() +}); + +/** + * Envelope padrĆ£o para respostas da API + */ +export const zMeAjudaAiContractsModelsResponse1MeAjudaAiModulesProvidersApplicationDtosProviderStatusDto_MeAjudaAiModulesProvidersApplication_Version_0000_Culture_neutral_PublicKeyToken_nullWritable = z.object({ + data: zMeAjudaAiModulesProvidersApplicationDtosProviderStatusDto.optional(), + statusCode: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).optional(), + message: z.string().nullish() +}); + +/** + * Envelope padrĆ£o para respostas da API + */ +export const zMeAjudaAiContractsModelsResponse1MeAjudaAiModulesProvidersApplicationDtosPublicProviderDto_MeAjudaAiModulesProvidersApplication_Version_0000_Culture_neutral_PublicKeyToken_nullWritable = z.object({ + data: zMeAjudaAiModulesProvidersApplicationDtosPublicProviderDto.optional(), + statusCode: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).optional(), + message: z.string().nullish() +}); + +/** + * Envelope padrĆ£o para respostas da API + */ +export const zMeAjudaAiContractsModelsResponse1MeAjudaAiModulesServiceCatalogsApplicationDtosRequestsServiceValidateServicesResponse_MeAjudaAiModulesServiceCatalogsApplication_Version_0000_Culture_neutral_PublicKeyToken_nullWritable = z.object({ + data: zMeAjudaAiModulesServiceCatalogsApplicationDtosRequestsServiceValidateServicesResponse.optional(), + statusCode: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).optional(), + message: z.string().nullish() +}); + +/** + * Envelope padrĆ£o para respostas da API + */ +export const zMeAjudaAiContractsModelsResponse1MeAjudaAiModulesServiceCatalogsApplicationDtosServiceCategoryDto_MeAjudaAiModulesServiceCatalogsApplication_Version_0000_Culture_neutral_PublicKeyToken_nullWritable = z.object({ + data: zMeAjudaAiModulesServiceCatalogsApplicationDtosServiceCategoryDto.optional(), + statusCode: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).optional(), + message: z.string().nullish() +}); + +/** + * Envelope padrĆ£o para respostas da API + */ +export const zMeAjudaAiContractsModelsResponse1MeAjudaAiModulesServiceCatalogsApplicationDtosServiceDto_MeAjudaAiModulesServiceCatalogsApplication_Version_0000_Culture_neutral_PublicKeyToken_nullWritable = z.object({ + data: zMeAjudaAiModulesServiceCatalogsApplicationDtosServiceDto.optional(), + statusCode: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).optional(), + message: z.string().nullish() +}); + +/** + * Envelope padrĆ£o para respostas da API + */ +export const zMeAjudaAiContractsModelsResponse1MeAjudaAiModulesUsersApplicationDtosUserDto_MeAjudaAiModulesUsersApplication_Version_0000_Culture_neutral_PublicKeyToken_nullWritable = z.object({ + data: zMeAjudaAiModulesUsersApplicationDtosUserDto.optional(), + statusCode: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).optional(), + message: z.string().nullish() +}); + +/** + * Envelope padrĆ£o para respostas da API + */ +export const zMeAjudaAiContractsModelsResponse1SystemCollectionsGenericIReadOnlyList1MeAjudaAiModulesProvidersApplicationDtosProviderDto_MeAjudaAiModulesProvidersApplication_Version_0000_Culture_neutral_PublicKeyToken_null___SystemPrivateCoreLib_Version_10000_Culture_neutral_PublicKeyToken_7Cec85D7Bea7798EWritable = z.object({ + data: z.array(zMeAjudaAiModulesProvidersApplicationDtosProviderDto).nullish(), + statusCode: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).optional(), + message: z.string().nullish() +}); + +/** + * Envelope padrĆ£o para respostas da API + */ +export const zMeAjudaAiContractsModelsResponse1SystemCollectionsGenericIReadOnlyList1MeAjudaAiModulesServiceCatalogsApplicationDtosServiceCategoryDto_MeAjudaAiModulesServiceCatalogsApplication_Version_0000_Culture_neutral_PublicKeyToken_null___SystemPrivateCoreLib_Version_10000_Culture_neutral_PublicKeyToken_7Cec85D7Bea7798EWritable = z.object({ + data: z.array(zMeAjudaAiModulesServiceCatalogsApplicationDtosServiceCategoryDto).nullish(), + statusCode: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).optional(), + message: z.string().nullish() +}); + +/** + * Envelope padrĆ£o para respostas da API + */ +export const zMeAjudaAiContractsModelsResponse1SystemCollectionsGenericIReadOnlyList1MeAjudaAiModulesServiceCatalogsApplicationDtosServiceListDto_MeAjudaAiModulesServiceCatalogsApplication_Version_0000_Culture_neutral_PublicKeyToken_null___SystemPrivateCoreLib_Version_10000_Culture_neutral_PublicKeyToken_7Cec85D7Bea7798EWritable = z.object({ + data: z.array(zMeAjudaAiModulesServiceCatalogsApplicationDtosServiceListDto).nullish(), + statusCode: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).optional(), + message: z.string().nullish() +}); + +/** + * Envelope padrĆ£o para respostas da API + */ +export const zMeAjudaAiContractsModelsResponse1SystemGuid_SystemPrivateCoreLib_Version_10000_Culture_neutral_PublicKeyToken_7Cec85D7Bea7798EWritable = z.object({ + data: z.uuid().optional(), + statusCode: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).optional(), + message: z.string().nullish() +}); + +/** + * Envelope padrĆ£o para respostas da API + */ +export const zMeAjudaAiContractsModelsResponse1SystemObject_SystemPrivateCoreLib_Version_10000_Culture_neutral_PublicKeyToken_7Cec85D7Bea7798EWritable = z.object({ + data: z.unknown().optional(), + statusCode: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).optional(), + message: z.string().nullish() +}); + +export const zApiAllowedCitiesGetData = z.object({ + body: z.never().optional(), + path: z.never().optional(), + query: z.object({ + onlyActive: z.boolean().optional().default(false) + }).optional() +}); + +/** + * OK + */ +export const zApiAllowedCitiesGetResponse = zMeAjudaAiContractsFunctionalResult1SystemCollectionsGenericIReadOnlyList1MeAjudaAiContractsContractsModulesLocationsDtosModuleAllowedCityDto_MeAjudaAiContracts_Version_0000_Culture_neutral_PublicKeyToken_null___SystemPrivateCoreLib_Version_10000_Culture_neutral_PublicKeyToken_7Cec85D7Bea7798E; + +export const zApiAllowedCitiesPostData = z.object({ + body: zMeAjudaAiContractsContractsModulesLocationsDtosCreateAllowedCityRequestDto, + path: z.never().optional(), + query: z.never().optional() +}); + +/** + * Created + */ +export const zApiAllowedCitiesPostResponse = zMeAjudaAiContractsModelsResponse1SystemGuid_SystemPrivateCoreLib_Version_10000_Culture_neutral_PublicKeyToken_7Cec85D7Bea7798E; + +export const zApiAllowedCitiesDeleteData = z.object({ + body: z.never().optional(), + path: z.object({ + id: z.uuid() + }), + query: z.never().optional() +}); + +/** + * OK + */ +export const zApiAllowedCitiesDeleteResponse = zMeAjudaAiContractsFunctionalResult; + +export const zApiAllowedCitiesGet2Data = z.object({ + body: z.never().optional(), + path: z.object({ + id: z.uuid() + }), + query: z.never().optional() +}); + +/** + * OK + */ +export const zApiAllowedCitiesGet2Response = zMeAjudaAiContractsModelsResponse1MeAjudaAiModulesLocationsApplicationDtosAllowedCityDto_MeAjudaAiModulesLocationsApplication_Version_0000_Culture_neutral_PublicKeyToken_null; + +export const zApiAllowedCitiesPatchData = z.object({ + body: zMeAjudaAiContractsContractsModulesLocationsDtosPatchAllowedCityRequestDto, + path: z.object({ + id: z.uuid() + }), + query: z.never().optional() +}); + +/** + * OK + */ +export const zApiAllowedCitiesPatchResponse = zMeAjudaAiContractsFunctionalResult1MeAjudaAiContractsFunctionalUnit_MeAjudaAiContracts_Version_0000_Culture_neutral_PublicKeyToken_null; + +export const zApiAllowedCitiesPutData = z.object({ + body: zMeAjudaAiModulesLocationsApplicationDtosRequestsUpdateAllowedCityRequest, + path: z.object({ + id: z.uuid() + }), + query: z.never().optional() +}); + +/** + * No Content + */ +export const zApiAllowedCitiesPutResponse = z.void(); + +export const zApiProvidersGetData = z.object({ + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() +}); + +export const zApiClientGetData = z.object({ + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() +}); + +/** + * OK + */ +export const zApiClientGetResponse = zMeAjudaAiContractsConfigurationClientConfiguration; + +export const zApiUploadPostData = z.object({ + body: zMeAjudaAiModulesDocumentsApplicationDtosRequestsUploadDocumentRequest, + path: z.never().optional(), + query: z.never().optional() +}); + +/** + * OK + */ +export const zApiUploadPostResponse = zMeAjudaAiModulesDocumentsApplicationDtosUploadDocumentResponse; + +export const zApiStatusGetData = z.object({ + body: z.never().optional(), + path: z.object({ + documentId: z.uuid() + }), + query: z.never().optional() +}); + +/** + * OK + */ +export const zApiStatusGetResponse = zMeAjudaAiModulesDocumentsApplicationDtosDocumentDto; + +export const zApiProviderGetData = z.object({ + body: z.never().optional(), + path: z.object({ + providerId: z.uuid() + }), + query: z.never().optional() +}); + +/** + * OK + */ +export const zApiProviderGetResponse = z.array(zMeAjudaAiModulesDocumentsApplicationDtosDocumentDto); + +export const zApiRequestVerificationPostData = z.object({ + body: z.never().optional(), + path: z.object({ + documentId: z.uuid() + }), + query: z.never().optional() +}); + +export const zApiVerifyPostData = z.object({ + body: zMeAjudaAiModulesDocumentsApplicationDtosRequestsVerifyDocumentRequest, + path: z.object({ + documentId: z.uuid() + }), + query: z.never().optional() +}); + +export const zApiSearchGetData = z.object({ + body: z.never().optional(), + path: z.never().optional(), + query: z.object({ + query: z.string() + }) +}); + +/** + * OK + */ +export const zApiSearchGetResponse = z.array(zMeAjudaAiContractsContractsModulesLocationsDtosLocationCandidate); + +export const zApiProvidersGet2Data = z.object({ + body: z.never().optional(), + path: z.never().optional(), + query: z.object({ + pageNumber: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).optional().default(1), + pageSize: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).optional().default(10), + name: z.string().optional(), + type: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).optional(), + verificationStatus: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).optional() + }).optional() +}); + +/** + * OK + */ +export const zApiProvidersGet2Response = zMeAjudaAiContractsModelsPagedResponse1SystemCollectionsGenericIEnumerable1MeAjudaAiModulesProvidersApplicationDtosProviderDto_MeAjudaAiModulesProvidersApplication_Version_0000_Culture_neutral_PublicKeyToken_null___SystemPrivateCoreLib_Version_10000_Culture_neutral_PublicKeyToken_7Cec85D7Bea7798E; + +export const zApiProvidersPostData = z.object({ + body: zMeAjudaAiModulesProvidersApplicationDtosRequestsCreateProviderRequest, + path: z.never().optional(), + query: z.never().optional() +}); + +/** + * Created + */ +export const zApiProvidersPostResponse = zMeAjudaAiContractsModelsResponse1MeAjudaAiModulesProvidersApplicationDtosProviderDto_MeAjudaAiModulesProvidersApplication_Version_0000_Culture_neutral_PublicKeyToken_null; + +export const zApiProvidersDeleteData = z.object({ + body: z.never().optional(), + path: z.object({ + id: z.uuid() + }), + query: z.never().optional() +}); + +/** + * No Content + */ +export const zApiProvidersDeleteResponse = z.void(); + +export const zApiProvidersGet3Data = z.object({ + body: z.never().optional(), + path: z.object({ + id: z.uuid() + }), + query: z.never().optional() +}); + +/** + * OK + */ +export const zApiProvidersGet3Response = zMeAjudaAiContractsModelsResponse1MeAjudaAiModulesProvidersApplicationDtosProviderDto_MeAjudaAiModulesProvidersApplication_Version_0000_Culture_neutral_PublicKeyToken_null; + +export const zApiProvidersPutData = z.object({ + body: zMeAjudaAiModulesProvidersApplicationDtosRequestsUpdateProviderProfileRequest, + path: z.object({ + id: z.uuid() + }), + query: z.never().optional() +}); + +/** + * OK + */ +export const zApiProvidersPutResponse = zMeAjudaAiContractsModelsResponse1MeAjudaAiModulesProvidersApplicationDtosProviderDto_MeAjudaAiModulesProvidersApplication_Version_0000_Culture_neutral_PublicKeyToken_null; + +export const zApiPublicGetData = z.object({ + body: z.never().optional(), + path: z.object({ + idOrSlug: z.string() + }), + query: z.never().optional() +}); + +/** + * OK + */ +export const zApiPublicGetResponse = zMeAjudaAiContractsModelsResponse1MeAjudaAiModulesProvidersApplicationDtosPublicProviderDto_MeAjudaAiModulesProvidersApplication_Version_0000_Culture_neutral_PublicKeyToken_null; + +export const zApiBecomePostData = z.object({ + body: zMeAjudaAiModulesProvidersApiEndpointsPublicRegisterProviderApiRequest, + path: z.never().optional(), + query: z.never().optional() +}); + +/** + * Created + */ +export const zApiBecomePostResponse = zMeAjudaAiContractsModelsResponse1MeAjudaAiModulesProvidersApplicationDtosProviderDto_MeAjudaAiModulesProvidersApplication_Version_0000_Culture_neutral_PublicKeyToken_null; + +export const zApiByUserGetData = z.object({ + body: z.never().optional(), + path: z.object({ + userId: z.uuid() + }), + query: z.never().optional() +}); + +/** + * OK + */ +export const zApiByUserGetResponse = zMeAjudaAiContractsModelsResponse1MeAjudaAiModulesProvidersApplicationDtosProviderDto_MeAjudaAiModulesProvidersApplication_Version_0000_Culture_neutral_PublicKeyToken_null; + +export const zApiByCityGetData = z.object({ + body: z.never().optional(), + path: z.object({ + city: z.string() + }), + query: z.never().optional() +}); + +/** + * OK + */ +export const zApiByCityGetResponse = zMeAjudaAiContractsModelsResponse1SystemCollectionsGenericIReadOnlyList1MeAjudaAiModulesProvidersApplicationDtosProviderDto_MeAjudaAiModulesProvidersApplication_Version_0000_Culture_neutral_PublicKeyToken_null___SystemPrivateCoreLib_Version_10000_Culture_neutral_PublicKeyToken_7Cec85D7Bea7798E; + +export const zApiByStateGetData = z.object({ + body: z.never().optional(), + path: z.object({ + state: z.string() + }), + query: z.never().optional() +}); + +/** + * OK + */ +export const zApiByStateGetResponse = zMeAjudaAiContractsModelsResponse1SystemCollectionsGenericIReadOnlyList1MeAjudaAiModulesProvidersApplicationDtosProviderDto_MeAjudaAiModulesProvidersApplication_Version_0000_Culture_neutral_PublicKeyToken_null___SystemPrivateCoreLib_Version_10000_Culture_neutral_PublicKeyToken_7Cec85D7Bea7798E; + +export const zApiByTypeGetData = z.object({ + body: z.never().optional(), + path: z.object({ + type: z.union([ + z.literal(0), + z.literal(1), + z.literal(2), + z.literal(3), + z.literal(4) + ]) + }), + query: z.never().optional() +}); + +/** + * OK + */ +export const zApiByTypeGetResponse = zMeAjudaAiContractsModelsResponse1SystemCollectionsGenericIReadOnlyList1MeAjudaAiModulesProvidersApplicationDtosProviderDto_MeAjudaAiModulesProvidersApplication_Version_0000_Culture_neutral_PublicKeyToken_null___SystemPrivateCoreLib_Version_10000_Culture_neutral_PublicKeyToken_7Cec85D7Bea7798E; + +export const zApiVerificationStatusGetData = z.object({ + body: z.never().optional(), + path: z.object({ + status: z.union([ + z.literal(0), + z.literal(1), + z.literal(2), + z.literal(3), + z.literal(4), + z.literal(5) + ]) + }), + query: z.never().optional() +}); + +/** + * OK + */ +export const zApiVerificationStatusGetResponse = zMeAjudaAiContractsModelsResponse1SystemCollectionsGenericIReadOnlyList1MeAjudaAiModulesProvidersApplicationDtosProviderDto_MeAjudaAiModulesProvidersApplication_Version_0000_Culture_neutral_PublicKeyToken_null___SystemPrivateCoreLib_Version_10000_Culture_neutral_PublicKeyToken_7Cec85D7Bea7798E; + +export const zApiDocumentsPostData = z.object({ + body: zMeAjudaAiModulesProvidersApplicationDtosRequestsAddDocumentRequest, + path: z.object({ + id: z.uuid() + }), + query: z.never().optional() +}); + +/** + * OK + */ +export const zApiDocumentsPostResponse = zMeAjudaAiContractsModelsResponse1MeAjudaAiModulesProvidersApplicationDtosProviderDto_MeAjudaAiModulesProvidersApplication_Version_0000_Culture_neutral_PublicKeyToken_null; + +export const zApiDocumentsDeleteData = z.object({ + body: z.never().optional(), + path: z.object({ + id: z.uuid(), + documentType: z.union([ + z.literal(0), + z.literal(1), + z.literal(2), + z.literal(3), + z.literal(4), + z.literal(5), + z.literal(99) + ]) + }), + query: z.never().optional() +}); + +/** + * OK + */ +export const zApiDocumentsDeleteResponse = zMeAjudaAiContractsModelsResponse1MeAjudaAiModulesProvidersApplicationDtosProviderDto_MeAjudaAiModulesProvidersApplication_Version_0000_Culture_neutral_PublicKeyToken_null; + +export const zApiVerificationStatusPutData = z.object({ + body: zMeAjudaAiModulesProvidersApplicationDtosRequestsUpdateVerificationStatusRequest, + path: z.object({ + id: z.uuid() + }), + query: z.never().optional() +}); + +/** + * OK + */ +export const zApiVerificationStatusPutResponse = zMeAjudaAiContractsModelsResponse1MeAjudaAiModulesProvidersApplicationDtosProviderDto_MeAjudaAiModulesProvidersApplication_Version_0000_Culture_neutral_PublicKeyToken_null; + +export const zApiRequireBasicInfoCorrectionPostData = z.object({ + body: zMeAjudaAiModulesProvidersApplicationDtosRequestsRequireBasicInfoCorrectionRequest, + path: z.object({ + id: z.uuid() + }), + query: z.never().optional() +}); + +export const zApiMeGetData = z.object({ + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() +}); + +/** + * OK + */ +export const zApiMeGetResponse = zMeAjudaAiContractsModelsResponse1MeAjudaAiModulesProvidersApplicationDtosProviderDto_MeAjudaAiModulesProvidersApplication_Version_0000_Culture_neutral_PublicKeyToken_null; + +export const zApiMePutData = z.object({ + body: zMeAjudaAiModulesProvidersApplicationDtosRequestsUpdateProviderProfileRequest, + path: z.never().optional(), + query: z.never().optional() +}); + +/** + * OK + */ +export const zApiMePutResponse = zMeAjudaAiContractsModelsResponse1MeAjudaAiModulesProvidersApplicationDtosProviderDto_MeAjudaAiModulesProvidersApplication_Version_0000_Culture_neutral_PublicKeyToken_null; + +export const zApiDocumentsPost2Data = z.object({ + body: zMeAjudaAiModulesProvidersApplicationDtosRequestsAddDocumentRequest, + path: z.never().optional(), + query: z.never().optional() +}); + +/** + * OK + */ +export const zApiDocumentsPost2Response = zMeAjudaAiContractsModelsResponse1MeAjudaAiModulesProvidersApplicationDtosProviderDto_MeAjudaAiModulesProvidersApplication_Version_0000_Culture_neutral_PublicKeyToken_null; + +export const zApiStatusGet2Data = z.object({ + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() +}); + +/** + * OK + */ +export const zApiStatusGet2Response = zMeAjudaAiContractsModelsResponse1MeAjudaAiModulesProvidersApplicationDtosProviderStatusDto_MeAjudaAiModulesProvidersApplication_Version_0000_Culture_neutral_PublicKeyToken_null; + +export const zApiActivatePostData = z.object({ + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() +}); + +/** + * OK + */ +export const zApiActivatePostResponse = zMeAjudaAiContractsModelsResponse1SystemObject_SystemPrivateCoreLib_Version_10000_Culture_neutral_PublicKeyToken_7Cec85D7Bea7798E; + +export const zApiDeactivatePostData = z.object({ + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() +}); + +/** + * OK + */ +export const zApiDeactivatePostResponse = zMeAjudaAiContractsModelsResponse1SystemObject_SystemPrivateCoreLib_Version_10000_Culture_neutral_PublicKeyToken_7Cec85D7Bea7798E; + +export const zApiRegisterPostData = z.object({ + body: zMeAjudaAiModulesProvidersApplicationDtosRequestsRegisterProviderRequest, + path: z.never().optional(), + query: z.never().optional() +}); + +/** + * Created + */ +export const zApiRegisterPostResponse = zMeAjudaAiContractsModelsResponse1MeAjudaAiModulesProvidersApplicationDtosProviderDto_MeAjudaAiModulesProvidersApplication_Version_0000_Culture_neutral_PublicKeyToken_null; + +export const zApiServicesDeleteData = z.object({ + body: z.never().optional(), + path: z.object({ + providerId: z.uuid(), + serviceId: z.uuid() + }), + query: z.never().optional() +}); + +/** + * No Content + */ +export const zApiServicesDeleteResponse = z.void(); + +export const zApiServicesPostData = z.object({ + body: z.never().optional(), + path: z.object({ + providerId: z.uuid(), + serviceId: z.uuid() + }), + query: z.never().optional() +}); + +/** + * No Content + */ +export const zApiServicesPostResponse = z.void(); + +export const zApiProvidersGet4Data = z.object({ + body: z.never().optional(), + path: z.never().optional(), + query: z.object({ + latitude: z.number(), + longitude: z.number(), + radiusInKm: z.number(), + term: z.string().optional(), + serviceIds: z.array(z.uuid()).optional(), + minRating: z.number().optional(), + subscriptionTiers: z.array(z.union([ + z.literal(0), + z.literal(1), + z.literal(2), + z.literal(3) + ])).optional(), + page: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).optional().default(1), + pageSize: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).optional().default(20) + }) +}); + +/** + * OK + */ +export const zApiProvidersGet4Response = zMeAjudaAiContractsModelsPagedResult1MeAjudaAiModulesSearchProvidersApplicationDtosSearchableProviderDto_MeAjudaAiModulesSearchProvidersApplication_Version_0000_Culture_neutral_PublicKeyToken_null; + +export const zApiCspReportPostData = z.object({ + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() +}); + +export const zApiCategoriesGetData = z.object({ + body: z.never().optional(), + path: z.never().optional(), + query: z.object({ + activeOnly: z.boolean().optional() + }).optional() +}); + +/** + * OK + */ +export const zApiCategoriesGetResponse = zMeAjudaAiContractsModelsResponse1SystemCollectionsGenericIReadOnlyList1MeAjudaAiModulesServiceCatalogsApplicationDtosServiceCategoryDto_MeAjudaAiModulesServiceCatalogsApplication_Version_0000_Culture_neutral_PublicKeyToken_null___SystemPrivateCoreLib_Version_10000_Culture_neutral_PublicKeyToken_7Cec85D7Bea7798E; + +export const zApiCategoriesPostData = z.object({ + body: zMeAjudaAiModulesServiceCatalogsApiEndpointsServiceCategoryCreateServiceCategoryRequest, + path: z.never().optional(), + query: z.never().optional() +}); + +/** + * Created + */ +export const zApiCategoriesPostResponse = zMeAjudaAiContractsModelsResponse1MeAjudaAiModulesServiceCatalogsApplicationDtosServiceCategoryDto_MeAjudaAiModulesServiceCatalogsApplication_Version_0000_Culture_neutral_PublicKeyToken_null; + +export const zApiCategoriesDeleteData = z.object({ + body: z.never().optional(), + path: z.object({ + id: z.uuid() + }), + query: z.never().optional() +}); + +/** + * No Content + */ +export const zApiCategoriesDeleteResponse = z.void(); + +export const zApiCategoriesGet2Data = z.object({ + body: z.never().optional(), + path: z.object({ + id: z.uuid() + }), + query: z.never().optional() +}); + +/** + * OK + */ +export const zApiCategoriesGet2Response = zMeAjudaAiContractsModelsResponse1MeAjudaAiModulesServiceCatalogsApplicationDtosServiceCategoryDto_MeAjudaAiModulesServiceCatalogsApplication_Version_0000_Culture_neutral_PublicKeyToken_null; + +export const zApiCategoriesPutData = z.object({ + body: zMeAjudaAiModulesServiceCatalogsApiEndpointsServiceCategoryUpdateServiceCategoryRequest, + path: z.object({ + id: z.uuid() + }), + query: z.never().optional() +}); + +/** + * No Content + */ +export const zApiCategoriesPutResponse = z.void(); + +export const zApiActivatePost2Data = z.object({ + body: z.never().optional(), + path: z.object({ + id: z.uuid() + }), + query: z.never().optional() +}); + +/** + * No Content + */ +export const zApiActivatePost2Response = z.void(); + +export const zApiDeactivatePost2Data = z.object({ + body: z.never().optional(), + path: z.object({ + id: z.uuid() + }), + query: z.never().optional() +}); + +/** + * No Content + */ +export const zApiDeactivatePost2Response = z.void(); + +export const zApiServicesGetData = z.object({ + body: z.never().optional(), + path: z.never().optional(), + query: z.object({ + activeOnly: z.boolean().optional(), + name: z.string().optional() + }).optional() +}); + +/** + * OK + */ +export const zApiServicesGetResponse = zMeAjudaAiContractsModelsResponse1SystemCollectionsGenericIReadOnlyList1MeAjudaAiModulesServiceCatalogsApplicationDtosServiceListDto_MeAjudaAiModulesServiceCatalogsApplication_Version_0000_Culture_neutral_PublicKeyToken_null___SystemPrivateCoreLib_Version_10000_Culture_neutral_PublicKeyToken_7Cec85D7Bea7798E; + +export const zApiServicesPost2Data = z.object({ + body: zMeAjudaAiModulesServiceCatalogsApplicationDtosRequestsServiceCreateServiceRequest, + path: z.never().optional(), + query: z.never().optional() +}); + +/** + * Created + */ +export const zApiServicesPost2Response = zMeAjudaAiContractsModelsResponse1MeAjudaAiModulesServiceCatalogsApplicationDtosServiceDto_MeAjudaAiModulesServiceCatalogsApplication_Version_0000_Culture_neutral_PublicKeyToken_null; + +export const zApiServicesDelete2Data = z.object({ + body: z.never().optional(), + path: z.object({ + id: z.uuid() + }), + query: z.never().optional() +}); + +/** + * No Content + */ +export const zApiServicesDelete2Response = z.void(); + +export const zApiServicesGet2Data = z.object({ + body: z.never().optional(), + path: z.object({ + id: z.uuid() + }), + query: z.never().optional() +}); + +/** + * OK + */ +export const zApiServicesGet2Response = zMeAjudaAiContractsModelsResponse1MeAjudaAiModulesServiceCatalogsApplicationDtosServiceDto_MeAjudaAiModulesServiceCatalogsApplication_Version_0000_Culture_neutral_PublicKeyToken_null; + +export const zApiServicesPutData = z.object({ + body: zMeAjudaAiModulesServiceCatalogsApplicationDtosRequestsServiceUpdateServiceRequest, + path: z.object({ + id: z.uuid() + }), + query: z.never().optional() +}); + +/** + * No Content + */ +export const zApiServicesPutResponse = z.void(); + +export const zApiCategoryGetData = z.object({ + body: z.never().optional(), + path: z.object({ + categoryId: z.uuid() + }), + query: z.object({ + activeOnly: z.boolean().optional() + }).optional() +}); + +/** + * OK + */ +export const zApiCategoryGetResponse = zMeAjudaAiContractsModelsResponse1SystemCollectionsGenericIReadOnlyList1MeAjudaAiModulesServiceCatalogsApplicationDtosServiceListDto_MeAjudaAiModulesServiceCatalogsApplication_Version_0000_Culture_neutral_PublicKeyToken_null___SystemPrivateCoreLib_Version_10000_Culture_neutral_PublicKeyToken_7Cec85D7Bea7798E; + +export const zApiChangeCategoryPostData = z.object({ + body: zMeAjudaAiModulesServiceCatalogsApplicationDtosRequestsServiceChangeServiceCategoryRequest, + path: z.object({ + id: z.uuid() + }), + query: z.never().optional() +}); + +/** + * No Content + */ +export const zApiChangeCategoryPostResponse = z.void(); + +export const zApiActivatePost3Data = z.object({ + body: z.never().optional(), + path: z.object({ + id: z.uuid() + }), + query: z.never().optional() +}); + +/** + * No Content + */ +export const zApiActivatePost3Response = z.void(); + +export const zApiDeactivatePost3Data = z.object({ + body: z.never().optional(), + path: z.object({ + id: z.uuid() + }), + query: z.never().optional() +}); + +/** + * No Content + */ +export const zApiDeactivatePost3Response = z.void(); + +export const zApiValidatePostData = z.object({ + body: zMeAjudaAiModulesServiceCatalogsApplicationDtosRequestsServiceValidateServicesRequest, + path: z.never().optional(), + query: z.never().optional() +}); + +/** + * OK + */ +export const zApiValidatePostResponse = zMeAjudaAiContractsModelsResponse1MeAjudaAiModulesServiceCatalogsApplicationDtosRequestsServiceValidateServicesResponse_MeAjudaAiModulesServiceCatalogsApplication_Version_0000_Culture_neutral_PublicKeyToken_null; + +export const zApiUsersGetData = z.object({ + body: z.never().optional(), + path: z.never().optional(), + query: z.object({ + pageNumber: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).optional().default(1), + pageSize: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).optional().default(10), + searchTerm: z.string().optional() + }).optional() +}); + +/** + * OK + */ +export const zApiUsersGetResponse = zMeAjudaAiContractsModelsPagedResponse1SystemCollectionsGenericIEnumerable1MeAjudaAiModulesUsersApplicationDtosUserDto_MeAjudaAiModulesUsersApplication_Version_0000_Culture_neutral_PublicKeyToken_null___SystemPrivateCoreLib_Version_10000_Culture_neutral_PublicKeyToken_7Cec85D7Bea7798E; + +export const zApiUsersPostData = z.object({ + body: zMeAjudaAiModulesUsersApplicationDtosRequestsCreateUserRequest, + path: z.never().optional(), + query: z.never().optional() +}); + +/** + * Created + */ +export const zApiUsersPostResponse = zMeAjudaAiContractsModelsResponse1MeAjudaAiModulesUsersApplicationDtosUserDto_MeAjudaAiModulesUsersApplication_Version_0000_Culture_neutral_PublicKeyToken_null; + +export const zApiUsersDeleteData = z.object({ + body: z.never().optional(), + path: z.object({ + id: z.uuid() + }), + query: z.never().optional() +}); + +/** + * No Content + */ +export const zApiUsersDeleteResponse = z.void(); + +export const zApiUsersGet2Data = z.object({ + body: z.never().optional(), + path: z.object({ + id: z.uuid() + }), + query: z.never().optional() +}); + +/** + * OK + */ +export const zApiUsersGet2Response = zMeAjudaAiContractsModelsResponse1MeAjudaAiModulesUsersApplicationDtosUserDto_MeAjudaAiModulesUsersApplication_Version_0000_Culture_neutral_PublicKeyToken_null; + +export const zApiByEmailGetData = z.object({ + body: z.never().optional(), + path: z.object({ + email: z.string() + }), + query: z.never().optional() +}); + +/** + * OK + */ +export const zApiByEmailGetResponse = zMeAjudaAiContractsModelsResponse1MeAjudaAiModulesUsersApplicationDtosUserDto_MeAjudaAiModulesUsersApplication_Version_0000_Culture_neutral_PublicKeyToken_null; + +export const zApiProfilePutData = z.object({ + body: zMeAjudaAiModulesUsersApplicationDtosRequestsUpdateUserProfileRequest, + path: z.object({ + id: z.uuid() + }), + query: z.never().optional() +}); + +/** + * OK + */ +export const zApiProfilePutResponse = zMeAjudaAiContractsModelsResponse1MeAjudaAiModulesUsersApplicationDtosUserDto_MeAjudaAiModulesUsersApplication_Version_0000_Culture_neutral_PublicKeyToken_null; + +export const zApiRegisterPost2Data = z.object({ + body: zMeAjudaAiModulesUsersApiEndpointsPublicRegisterCustomerRequest, + path: z.never().optional(), + query: z.never().optional() +}); diff --git a/src/Web/MeAjudaAi.Web.Admin-React/src/lib/types.ts b/src/Web/MeAjudaAi.Web.Admin-React/src/lib/types.ts new file mode 100644 index 000000000..c4a53c28e --- /dev/null +++ b/src/Web/MeAjudaAi.Web.Admin-React/src/lib/types.ts @@ -0,0 +1,86 @@ +import type { + MeAjudaAiModulesProvidersApplicationDtosProviderDto, + MeAjudaAiModulesProvidersApplicationDtosBusinessProfileDto, + MeAjudaAiModulesProvidersApplicationDtosDocumentDto, + MeAjudaAiModulesProvidersApplicationDtosServiceCategoryDto, + MeAjudaAiModulesLocationsApplicationDtosAllowedCityDto, + MeAjudaAiModulesUsersApplicationDtosUserDto, +} from "./api/generated"; + +export type ProviderDto = MeAjudaAiModulesProvidersApplicationDtosProviderDto; +export type BusinessProfileDto = MeAjudaAiModulesProvidersApplicationDtosBusinessProfileDto; +export type DocumentDto = MeAjudaAiModulesProvidersApplicationDtosDocumentDto; +export type ServiceCategoryDto = MeAjudaAiModulesProvidersApplicationDtosServiceCategoryDto; +export type AllowedCityDto = MeAjudaAiModulesLocationsApplicationDtosAllowedCityDto; +export type UserDto = MeAjudaAiModulesUsersApplicationDtosUserDto; + +export type ProviderType = 0 | 1 | 2 | 3 | 4; +export type ProviderStatus = 0 | 1 | 2 | 3 | 4 | 5; +export type VerificationStatus = 0 | 1 | 2 | 3 | 4 | 5; +export type ProviderTier = 0 | 1 | 2 | 3; + +export const EProviderType = { + None: 0, + Individual: 1, + Company: 2, + Cooperative: 3, + Freelancer: 4, +} as const; + +export const EProviderStatus = { + Pending: 0, + BasicInfoRequired: 1, + BasicInfoSubmitted: 2, + DocumentsRequired: 3, + DocumentsSubmitted: 4, + Active: 5, +} as const; + +export const EVerificationStatus = { + Pending: 0, + UnderReview: 1, + Approved: 2, + Rejected: 3, + Suspended: 4, + BasicInfoCorrectionRequired: 5, +} as const; + +export const EProviderTier = { + Free: 0, + Basic: 1, + Premium: 2, + Enterprise: 3, +} as const; + +export const providerTypeLabels: Record = { + 0: "NĆ£o definido", + 1: "Pessoa FĆ­sica", + 2: "Empresa", + 3: "Cooperativa", + 4: "Freelancer", +}; + +export const providerStatusLabels: Record = { + 0: "Pendente", + 1: "Dados BĆ”sicos NecessĆ”rios", + 2: "Dados BĆ”sicos Enviados", + 3: "Documentos NecessĆ”rios", + 4: "Documentos Enviados", + 5: "Ativo", +}; + +export const verificationStatusLabels: Record = { + 0: "Pendente", + 1: "Em AnĆ”lise", + 2: "Aprovado", + 3: "Rejeitado", + 4: "Suspenso", + 5: "Correção de Dados NecessĆ”ria", +}; + +export const providerTierLabels: Record = { + 0: "GrĆ”tis", + 1: "BĆ”sico", + 2: "Premium", + 3: "Enterprise", +}; From b338be0f5ee072789b1e617148fac72c97ec2702 Mon Sep 17 00:00:00 2001 From: Filipe Frigini Date: Sat, 21 Mar 2026 14:24:10 -0300 Subject: [PATCH 05/19] feat(Admin): Add CRUD functionality to admin pages - Update dashboard with real API data and interactive charts - Add Dialog and Select components using @base-ui/react - Complete Allowed Cities CRUD with create, edit, delete - Complete Categories CRUD with create, edit, delete - Complete Services CRUD with create, edit, delete - Add dashboard stats hook for provider metrics - Add services hook for TanStack Query integration - Update documents page with placeholder info --- .../src/app/(admin)/allowed-cities/page.tsx | 358 +++++++++++++++++- .../src/app/(admin)/categories/page.tsx | 290 +++++++++++++- .../src/app/(admin)/dashboard/page.tsx | 106 +++++- .../src/app/(admin)/documents/page.tsx | 40 +- .../src/app/(admin)/services/page.tsx | 330 +++++++++++++++- .../src/components/ui/dialog.tsx | 115 ++++++ .../src/components/ui/select.tsx | 49 +++ .../src/hooks/admin/index.ts | 2 + .../src/hooks/admin/use-categories.ts | 7 +- .../src/hooks/admin/use-dashboard.ts | 61 +++ .../src/hooks/admin/use-services.ts | 83 ++++ 11 files changed, 1390 insertions(+), 51 deletions(-) create mode 100644 src/Web/MeAjudaAi.Web.Admin-React/src/components/ui/dialog.tsx create mode 100644 src/Web/MeAjudaAi.Web.Admin-React/src/components/ui/select.tsx create mode 100644 src/Web/MeAjudaAi.Web.Admin-React/src/hooks/admin/use-dashboard.ts create mode 100644 src/Web/MeAjudaAi.Web.Admin-React/src/hooks/admin/use-services.ts diff --git a/src/Web/MeAjudaAi.Web.Admin-React/src/app/(admin)/allowed-cities/page.tsx b/src/Web/MeAjudaAi.Web.Admin-React/src/app/(admin)/allowed-cities/page.tsx index 8659ee68e..24e592f08 100644 --- a/src/Web/MeAjudaAi.Web.Admin-React/src/app/(admin)/allowed-cities/page.tsx +++ b/src/Web/MeAjudaAi.Web.Admin-React/src/app/(admin)/allowed-cities/page.tsx @@ -1,28 +1,368 @@ "use client"; -import { MapPin, Plus } from "lucide-react"; +import { useState } from "react"; +import { MapPin, Plus, Pencil, Trash2, Loader2, Search } from "lucide-react"; import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; +import { Badge } from "@/components/ui/badge"; +import { Input } from "@/components/ui/input"; +import { + Dialog, + DialogContent, + DialogHeader, + DialogTitle, + DialogDescription, + DialogFooter, +} from "@/components/ui/dialog"; +import { + useAllowedCities, + useCreateAllowedCity, + useUpdateAllowedCity, + usePatchAllowedCity, + useDeleteAllowedCity, +} from "@/hooks/admin"; +import type { AllowedCityDto } from "@/lib/types"; + +const brazilianStates = [ + "AC", "AL", "AP", "AM", "BA", "CE", "DF", "ES", "GO", "MA", + "MT", "MS", "MG", "PA", "PB", "PR", "PE", "PI", "RJ", "RN", + "RS", "RO", "RR", "SC", "SP", "SE", "TO" +]; + +interface CityFormData { + city: string; + state: string; + serviceRadiusKm: number; + isActive: boolean; +} + +const initialFormData: CityFormData = { + city: "", + state: "", + serviceRadiusKm: 50, + isActive: true, +}; export default function AllowedCitiesPage() { + const [search, setSearch] = useState(""); + const [isCreateOpen, setIsCreateOpen] = useState(false); + const [isEditOpen, setIsEditOpen] = useState(false); + const [isDeleteOpen, setIsDeleteOpen] = useState(false); + const [selectedCity, setSelectedCity] = useState(null); + const [formData, setFormData] = useState(initialFormData); + + const { data: citiesResponse, isLoading, error } = useAllowedCities(); + const createMutation = useCreateAllowedCity(); + const updateMutation = useUpdateAllowedCity(); + const patchMutation = usePatchAllowedCity(); + const deleteMutation = useDeleteAllowedCity(); + + const cities = citiesResponse?.data?.value ?? []; + + const filteredCities = cities.filter( + (c) => + (c.cityName?.toLowerCase() ?? "").includes(search.toLowerCase()) || + (c.stateSigla?.toLowerCase() ?? "").includes(search.toLowerCase()) + ); + + const handleOpenCreate = () => { + setFormData(initialFormData); + setIsCreateOpen(true); + }; + + const handleOpenEdit = (city: AllowedCityDto) => { + setSelectedCity(city); + setFormData({ + city: city.cityName ?? "", + state: city.stateSigla ?? "", + serviceRadiusKm: city.serviceRadiusKm ?? 50, + isActive: city.isActive ?? true, + }); + setIsEditOpen(true); + }; + + const handleOpenDelete = (city: AllowedCityDto) => { + setSelectedCity(city); + setIsDeleteOpen(true); + }; + + const handleSubmitCreate = async () => { + await createMutation.mutateAsync({ + body: { + city: formData.city, + state: formData.state, + country: "Brasil", + serviceRadiusKm: formData.serviceRadiusKm, + isActive: formData.isActive, + }, + }); + setIsCreateOpen(false); + }; + + const handleSubmitEdit = async () => { + if (!selectedCity?.id) return; + await updateMutation.mutateAsync({ + id: selectedCity.id, + data: { + data: { + cityName: formData.city, + stateSigla: formData.state, + serviceRadiusKm: formData.serviceRadiusKm, + isActive: formData.isActive, + }, + }, + }); + setIsEditOpen(false); + }; + + const handleToggleActive = async (city: AllowedCityDto) => { + if (!city.id) return; + await patchMutation.mutateAsync({ + id: city.id, + data: { + isActive: !city.isActive, + }, + }); + }; + + const handleDelete = async () => { + if (!selectedCity?.id) return; + await deleteMutation.mutateAsync(selectedCity.id); + setIsDeleteOpen(false); + }; + return (

Cidades Permitidas

-

Gerencie cidades atendidas

+

Gerencie cidades atendidas pelos prestadores

- +
+ +
+
+ + setSearch(e.target.value)} + /> +
+
+
+ - - Cidades Ativas - - -

Funcionalidade em desenvolvimento.

-
+ {isLoading && ( +
+ +
+ )} + + {error && ( +
+ Erro ao carregar cidades. Tente novamente. +
+ )} + + {!isLoading && !error && ( +
+ + + + + + + + + + + + {filteredCities.map((city) => ( + + + + + + + + ))} + +
CidadeEstadoRaio de ServiƧoStatusAƧƵes
{city.cityName ?? "-"}{city.stateSigla ?? "-"}{city.serviceRadiusKm ?? 50} km + + {city.isActive ? "Ativa" : "Inativa"} + + +
+ + + +
+
+
+ )} + + {!isLoading && !error && filteredCities.length === 0 && ( +
Nenhuma cidade encontrada
+ )}
+ + + + + Nova Cidade Permitida + Adicione uma nova cidade para atendimento dos prestadores. + +
+
+ + setFormData({ ...formData, city: e.target.value })} + placeholder="Ex: SĆ£o Paulo" + /> +
+
+ + +
+
+ + setFormData({ ...formData, serviceRadiusKm: Number(e.target.value) })} + min={1} + max={500} + /> +
+
+ setFormData({ ...formData, isActive: e.target.checked })} + className="h-4 w-4" + /> + +
+
+ + + + +
+
+ + + + + Editar Cidade + Atualize os dados da cidade permitida. + +
+
+ + setFormData({ ...formData, city: e.target.value })} + /> +
+
+ + +
+
+ + setFormData({ ...formData, serviceRadiusKm: Number(e.target.value) })} + min={1} + max={500} + /> +
+
+ setFormData({ ...formData, isActive: e.target.checked })} + className="h-4 w-4" + /> + +
+
+ + + + +
+
+ + + + + Excluir Cidade + + Tem certeza que deseja excluir a cidade {selectedCity?.cityName}? + Esta ação não pode ser desfeita. + + + + + + + +
); } diff --git a/src/Web/MeAjudaAi.Web.Admin-React/src/app/(admin)/categories/page.tsx b/src/Web/MeAjudaAi.Web.Admin-React/src/app/(admin)/categories/page.tsx index 7ad339689..bbd1eee0f 100644 --- a/src/Web/MeAjudaAi.Web.Admin-React/src/app/(admin)/categories/page.tsx +++ b/src/Web/MeAjudaAi.Web.Admin-React/src/app/(admin)/categories/page.tsx @@ -1,10 +1,106 @@ "use client"; -import { FolderTree, Plus } from "lucide-react"; +import { useState } from "react"; +import { FolderTree, Plus, Pencil, Trash2, Loader2, Search } from "lucide-react"; import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; +import { Badge } from "@/components/ui/badge"; +import { Input } from "@/components/ui/input"; +import { + Dialog, + DialogContent, + DialogHeader, + DialogTitle, + DialogDescription, + DialogFooter, +} from "@/components/ui/dialog"; +import { + useCategories, + useCreateCategory, + useUpdateCategory, + useDeleteCategory, +} from "@/hooks/admin"; +import type { ServiceCategoryDto } from "@/lib/types"; + +interface CategoryFormData { + name: string; + description: string; + isActive: boolean; +} + +const initialFormData: CategoryFormData = { + name: "", + description: "", + isActive: true, +}; export default function CategoriesPage() { + const [search, setSearch] = useState(""); + const [isCreateOpen, setIsCreateOpen] = useState(false); + const [isEditOpen, setIsEditOpen] = useState(false); + const [isDeleteOpen, setIsDeleteOpen] = useState(false); + const [selectedCategory, setSelectedCategory] = useState(null); + const [formData, setFormData] = useState(initialFormData); + + const { data: categoriesResponse, isLoading, error } = useCategories(); + const createMutation = useCreateCategory(); + const updateMutation = useUpdateCategory(); + const deleteMutation = useDeleteCategory(); + + const categories = categoriesResponse?.data?.data ?? []; + + const filteredCategories = categories.filter( + (c) => (c.name?.toLowerCase() ?? "").includes(search.toLowerCase()) + ); + + const handleOpenCreate = () => { + setFormData(initialFormData); + setIsCreateOpen(true); + }; + + const handleOpenEdit = (category: ServiceCategoryDto) => { + setSelectedCategory(category); + setFormData({ + name: category.name ?? "", + description: category.description ?? "", + isActive: category.isActive ?? true, + }); + setIsEditOpen(true); + }; + + const handleOpenDelete = (category: ServiceCategoryDto) => { + setSelectedCategory(category); + setIsDeleteOpen(true); + }; + + const handleSubmitCreate = async () => { + await createMutation.mutateAsync({ + body: { + name: formData.name, + description: formData.description, + isActive: formData.isActive, + }, + }); + setIsCreateOpen(false); + }; + + const handleSubmitEdit = async () => { + if (!selectedCategory?.id) return; + await updateMutation.mutateAsync({ + id: selectedCategory.id, + name: formData.name, + description: formData.description, + isActive: formData.isActive, + }); + setIsEditOpen(false); + }; + + const handleDelete = async () => { + if (!selectedCategory?.id) return; + await deleteMutation.mutateAsync(selectedCategory.id); + setIsDeleteOpen(false); + }; + return (
@@ -12,17 +108,195 @@ export default function CategoriesPage() {

Categorias

Gerencie categorias de serviƧos

- +
+ +
+
+ + setSearch(e.target.value)} + /> +
+
+
+ - - Categorias de ServiƧos - - -

Funcionalidade em desenvolvimento.

-
+ {isLoading && ( +
+ +
+ )} + + {error && ( +
+ Erro ao carregar categorias. Tente novamente. +
+ )} + + {!isLoading && !error && ( +
+ + + + + + + + + + + + {filteredCategories.map((category) => ( + + + + + + + + ))} + +
NomeDescriçãoOrdemStatusAções
{category.name ?? "-"} + {category.description ?? "-"} + + {category.displayOrder ?? 0} + + + {category.isActive ? "Ativa" : "Inativa"} + + +
+ + +
+
+
+ )} + + {!isLoading && !error && filteredCategories.length === 0 && ( +
Nenhuma categoria encontrada
+ )}
+ + + + + Nova Categoria + Adicione uma nova categoria de serviƧo. + +
+
+ + setFormData({ ...formData, name: e.target.value })} + placeholder="Ex: Eletricista" + /> +
+
+ + setFormData({ ...formData, description: e.target.value })} + placeholder="Descrição da categoria..." + /> +
+
+ setFormData({ ...formData, isActive: e.target.checked })} + className="h-4 w-4" + /> + +
+
+ + + + +
+
+ + + + + Editar Categoria + Atualize os dados da categoria. + +
+
+ + setFormData({ ...formData, name: e.target.value })} + /> +
+
+ + setFormData({ ...formData, description: e.target.value })} + /> +
+
+ setFormData({ ...formData, isActive: e.target.checked })} + className="h-4 w-4" + /> + +
+
+ + + + +
+
+ + + + + Excluir Categoria + + Tem certeza que deseja excluir a categoria {selectedCategory?.name}? + Esta ação não pode ser desfeita. + + + + + + + +
); } diff --git a/src/Web/MeAjudaAi.Web.Admin-React/src/app/(admin)/dashboard/page.tsx b/src/Web/MeAjudaAi.Web.Admin-React/src/app/(admin)/dashboard/page.tsx index f78430aa4..299988288 100644 --- a/src/Web/MeAjudaAi.Web.Admin-React/src/app/(admin)/dashboard/page.tsx +++ b/src/Web/MeAjudaAi.Web.Admin-React/src/app/(admin)/dashboard/page.tsx @@ -1,16 +1,62 @@ "use client"; -import { Users, Clock, CheckCircle, AlertCircle } from "lucide-react"; +import { Users, Clock, CheckCircle, AlertCircle, TrendingUp, Loader2 } from "lucide-react"; import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card"; -import { PieChart, Pie, Cell, ResponsiveContainer } from "recharts"; +import { PieChart, Pie, Cell, ResponsiveContainer, Legend, Tooltip } from "recharts"; +import { useDashboardStats } from "@/hooks/admin"; -const statusData = [ - { name: "Aprovados", value: 145, color: "#22c55e" }, - { name: "Pendentes", value: 32, color: "#f59e0b" }, - { name: "Rejeitados", value: 8, color: "#ef4444" }, -]; +const verificationColors = { + approved: "#22c55e", + pending: "#f59e0b", + underReview: "#3b82f6", + rejected: "#ef4444", + suspended: "#6b7280", +}; + +const typeColors = { + individual: "#8b5cf6", + company: "#06b6d4", + freelancer: "#f97316", + cooperative: "#ec4899", +}; export default function DashboardPage() { + const { data: stats, isLoading, error } = useDashboardStats(); + + const verificationData = [ + { name: "Aprovados", value: stats?.approved ?? 0, color: verificationColors.approved }, + { name: "Em AnƔlise", value: stats?.underReview ?? 0, color: verificationColors.underReview }, + { name: "Pendentes", value: stats?.pending ?? 0, color: verificationColors.pending }, + { name: "Rejeitados", value: stats?.rejected ?? 0, color: verificationColors.rejected }, + { name: "Suspensos", value: stats?.suspended ?? 0, color: verificationColors.suspended }, + ].filter((d) => d.value > 0); + + const typeData = [ + { name: "Pessoa Fƭsica", value: stats?.individual ?? 0, color: typeColors.individual }, + { name: "Empresa", value: stats?.company ?? 0, color: typeColors.company }, + { name: "Freelancer", value: stats?.freelancer ?? 0, color: typeColors.freelancer }, + { name: "Cooperativa", value: stats?.cooperative ?? 0, color: typeColors.cooperative }, + ].filter((d) => d.value > 0); + + const approvedPercentage = stats?.total ? ((stats.approved / stats.total) * 100).toFixed(0) : 0; + const rejectedPercentage = stats?.total ? ((stats.rejected / stats.total) * 100).toFixed(0) : 0; + + if (isLoading) { + return ( +
+ +
+ ); + } + + if (error) { + return ( +
+ Erro ao carregar dados do dashboard. Tente novamente. +
+ ); + } + return (
@@ -27,8 +73,11 @@ export default function DashboardPage() { -
185
-

+12 este mĆŖs

+
{stats?.total ?? 0}
+

+ + Atualizado agora +

@@ -40,7 +89,7 @@ export default function DashboardPage() { -
32
+
{(stats?.pending ?? 0) + (stats?.underReview ?? 0)}

Revisão pendente

@@ -53,8 +102,8 @@ export default function DashboardPage() { -
145
-

78% do total

+
{stats?.approved ?? 0}
+

{approvedPercentage}% do total

@@ -66,8 +115,8 @@ export default function DashboardPage() { -
8
-

4% do total

+
{stats?.rejected ?? 0}
+

{rejectedPercentage}% do total

@@ -82,7 +131,7 @@ export default function DashboardPage() { `${name} ${(percent * 100).toFixed(0)}%`} > - {statusData.map((entry, index) => ( + {verificationData.map((entry, index) => ( ))} + +
@@ -106,7 +157,28 @@ export default function DashboardPage() { Prestadores por Tipo -

GrƔfico em desenvolvimento

+
+ + + `${name} ${(percent * 100).toFixed(0)}%`} + > + {typeData.map((entry, index) => ( + + ))} + + + + + +
diff --git a/src/Web/MeAjudaAi.Web.Admin-React/src/app/(admin)/documents/page.tsx b/src/Web/MeAjudaAi.Web.Admin-React/src/app/(admin)/documents/page.tsx index 1a78ec13a..ac6c8e58a 100644 --- a/src/Web/MeAjudaAi.Web.Admin-React/src/app/(admin)/documents/page.tsx +++ b/src/Web/MeAjudaAi.Web.Admin-React/src/app/(admin)/documents/page.tsx @@ -1,6 +1,6 @@ "use client"; -import { FileText, Upload } from "lucide-react"; +import { FileText, Upload, Info } from "lucide-react"; import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; @@ -12,17 +12,49 @@ export default function DocumentsPage() {

Documentos

Gerencie documentos dos prestadores

- - Documentos Recentes + Gestão de Documentos -

Funcionalidade em desenvolvimento.

+
+
+ +
+

Documentos por Prestador

+

+ A gestão de documentos é feita através da visualização detalhada de cada prestador. + Acesse a lista de prestadores e clique em um deles para ver e gerenciar seus documentos. +

+ +
+ +
+ + +
CNPJ
+

Documento de empresa

+
+
+ + +
RG/CPF
+

Documento de identidade

+
+
+ + +
Comprovante
+

Comprovante de residĆŖncia

+
+
+
); } diff --git a/src/Web/MeAjudaAi.Web.Admin-React/src/app/(admin)/services/page.tsx b/src/Web/MeAjudaAi.Web.Admin-React/src/app/(admin)/services/page.tsx index ff026b4cf..bd7b6840e 100644 --- a/src/Web/MeAjudaAi.Web.Admin-React/src/app/(admin)/services/page.tsx +++ b/src/Web/MeAjudaAi.Web.Admin-React/src/app/(admin)/services/page.tsx @@ -1,10 +1,118 @@ "use client"; -import { Wrench, Plus } from "lucide-react"; +import { useState } from "react"; +import { Wrench, Plus, Pencil, Trash2, Loader2, Search } from "lucide-react"; import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; +import { Badge } from "@/components/ui/badge"; +import { Input } from "@/components/ui/input"; +import { + Dialog, + DialogContent, + DialogHeader, + DialogTitle, + DialogDescription, + DialogFooter, +} from "@/components/ui/dialog"; +import { + useServices, + useCategories, + useCreateService, + useUpdateService, + useDeleteService, +} from "@/hooks/admin"; + +interface ServiceFormData { + name: string; + description: string; + categoryId: string; + isActive: boolean; +} + +const initialFormData: ServiceFormData = { + name: "", + description: "", + categoryId: "", + isActive: true, +}; export default function ServicesPage() { + const [search, setSearch] = useState(""); + const [isCreateOpen, setIsCreateOpen] = useState(false); + const [isEditOpen, setIsEditOpen] = useState(false); + const [isDeleteOpen, setIsDeleteOpen] = useState(false); + const [selectedService, setSelectedService] = useState<{ id?: string; name?: string | null } | null>(null); + const [formData, setFormData] = useState(initialFormData); + + const { data: servicesResponse, isLoading, error } = useServices(); + const { data: categoriesResponse } = useCategories(); + const createMutation = useCreateService(); + const updateMutation = useUpdateService(); + const deleteMutation = useDeleteService(); + + const services = servicesResponse?.data?.data ?? []; + const categories = categoriesResponse?.data?.data ?? []; + + const filteredServices = services.filter( + (s) => (s.name?.toLowerCase() ?? "").includes(search.toLowerCase()) + ); + + const getCategoryName = (categoryId?: string) => { + const category = categories.find((c) => c.id === categoryId); + return category?.name ?? "-"; + }; + + const handleOpenCreate = () => { + setFormData(initialFormData); + setIsCreateOpen(true); + }; + + const handleOpenEdit = (service: { id?: string; name?: string | null; description?: string | null; categoryId?: string; isActive?: boolean }) => { + setSelectedService(service); + setFormData({ + name: service.name ?? "", + description: service.description ?? "", + categoryId: service.categoryId ?? "", + isActive: service.isActive ?? true, + }); + setIsEditOpen(true); + }; + + const handleOpenDelete = (service: { id?: string; name?: string | null }) => { + setSelectedService(service); + setIsDeleteOpen(true); + }; + + const handleSubmitCreate = async () => { + await createMutation.mutateAsync({ + body: { + name: formData.name, + description: formData.description, + categoryId: formData.categoryId, + isActive: formData.isActive, + }, + }); + setIsCreateOpen(false); + }; + + const handleSubmitEdit = async () => { + if (!selectedService?.id) return; + await updateMutation.mutateAsync({ + id: selectedService.id, + name: formData.name, + description: formData.description, + categoryId: formData.categoryId, + isActive: formData.isActive, + }); + setIsEditOpen(false); + }; + + const handleDelete = async () => { + if (!selectedService?.id) return; + await deleteMutation.mutateAsync(selectedService.id); + setIsDeleteOpen(false); + }; + return (
@@ -12,17 +120,223 @@ export default function ServicesPage() {

ServiƧos

Gerencie serviƧos disponƭveis

- +
+ +
+
+ + setSearch(e.target.value)} + /> +
+
+
+ - - CatƔlogo de ServiƧos - - -

Funcionalidade em desenvolvimento.

-
+ {isLoading && ( +
+ +
+ )} + + {error && ( +
+ Erro ao carregar serviƧos. Tente novamente. +
+ )} + + {!isLoading && !error && ( +
+ + + + + + + + + + + + {filteredServices.map((service) => ( + + + + + + + + ))} + +
NomeCategoriaDescriçãoStatusAções
{service.name ?? "-"} + {getCategoryName(service.categoryId)} + + {service.description ?? "-"} + + + {service.isActive ? "Ativo" : "Inativo"} + + +
+ + +
+
+
+ )} + + {!isLoading && !error && filteredServices.length === 0 && ( +
Nenhum serviƧo encontrado
+ )}
+ + + + + Novo ServiƧo + Adicione um novo serviƧo. + +
+
+ + setFormData({ ...formData, name: e.target.value })} + placeholder="Ex: Instalação de Tomada" + /> +
+
+ + +
+
+ + setFormData({ ...formData, description: e.target.value })} + placeholder="Descrição do serviço..." + /> +
+
+ setFormData({ ...formData, isActive: e.target.checked })} + className="h-4 w-4" + /> + +
+
+ + + + +
+
+ + + + + Editar ServiƧo + Atualize os dados do serviƧo. + +
+
+ + setFormData({ ...formData, name: e.target.value })} + /> +
+
+ + +
+
+ + setFormData({ ...formData, description: e.target.value })} + /> +
+
+ setFormData({ ...formData, isActive: e.target.checked })} + className="h-4 w-4" + /> + +
+
+ + + + +
+
+ + + + + Excluir Serviço + + Tem certeza que deseja excluir o serviço {selectedService?.name}? + Esta ação não pode ser desfeita. + + + + + + + + ); } diff --git a/src/Web/MeAjudaAi.Web.Admin-React/src/components/ui/dialog.tsx b/src/Web/MeAjudaAi.Web.Admin-React/src/components/ui/dialog.tsx new file mode 100644 index 000000000..b06f3ccb9 --- /dev/null +++ b/src/Web/MeAjudaAi.Web.Admin-React/src/components/ui/dialog.tsx @@ -0,0 +1,115 @@ +"use client"; + +import * as DialogPrimitive from "@base-ui/react"; +import { X } from "lucide-react"; +import { Button } from "./button"; + +export interface DialogProps { + open?: boolean; + onOpenChange?: (open: boolean) => void; + children: React.ReactNode; +} + +export function Dialog({ open, onOpenChange, children }: DialogProps) { + return ( + + {children} + + ); +} + +export interface DialogTriggerProps { + children: React.ReactNode; + className?: string; + asChild?: boolean; +} + +export function DialogTrigger({ children, className, asChild }: DialogTriggerProps) { + return ( + + {children} + + ); +} + +export interface DialogContentProps { + children: React.ReactNode; + className?: string; +} + +export function DialogContent({ children, className = "" }: DialogContentProps) { + return ( + + + + {children} + + + Close + + + + ); +} + +export interface DialogHeaderProps { + children: React.ReactNode; + className?: string; +} + +export function DialogHeader({ children, className = "" }: DialogHeaderProps) { + return ( +
+ {children} +
+ ); +} + +export interface DialogFooterProps { + children: React.ReactNode; + className?: string; +} + +export function DialogFooter({ children, className = "" }: DialogFooterProps) { + return ( +
+ {children} +
+ ); +} + +export interface DialogTitleProps { + children: React.ReactNode; + className?: string; +} + +export function DialogTitle({ children, className = "" }: DialogTitleProps) { + return ( + + {children} + + ); +} + +export interface DialogDescriptionProps { + children: React.ReactNode; + className?: string; +} + +export function DialogDescription({ children, className = "" }: DialogDescriptionProps) { + return ( + + {children} + + ); +} + +export function DialogClose({ children, onClick }: { children?: React.ReactNode; onClick?: () => void }) { + return ( + + {children ? children : } + + ); +} diff --git a/src/Web/MeAjudaAi.Web.Admin-React/src/components/ui/select.tsx b/src/Web/MeAjudaAi.Web.Admin-React/src/components/ui/select.tsx new file mode 100644 index 000000000..88ef865af --- /dev/null +++ b/src/Web/MeAjudaAi.Web.Admin-React/src/components/ui/select.tsx @@ -0,0 +1,49 @@ +"use client"; + +import * as SelectPrimitive from "@base-ui/react"; +import { Check, ChevronDown } from "lucide-react"; + +export interface SelectProps { + value?: string; + onValueChange?: (value: string) => void; + children: React.ReactNode; + placeholder?: string; + className?: string; +} + +export function Select({ value, onValueChange, children, placeholder, className = "" }: SelectProps) { + return ( + + + + + + + + + + {children} + + + + ); +} + +export interface SelectItemProps { + value: string; + children: React.ReactNode; + className?: string; +} + +export function SelectItem({ value, children, className = "" }: SelectItemProps) { + return ( + + + + + + + {children} + + ); +} diff --git a/src/Web/MeAjudaAi.Web.Admin-React/src/hooks/admin/index.ts b/src/Web/MeAjudaAi.Web.Admin-React/src/hooks/admin/index.ts index 9dba5a2e9..e573b7984 100644 --- a/src/Web/MeAjudaAi.Web.Admin-React/src/hooks/admin/index.ts +++ b/src/Web/MeAjudaAi.Web.Admin-React/src/hooks/admin/index.ts @@ -2,3 +2,5 @@ export * from "./use-providers"; export * from "./use-allowed-cities"; export * from "./use-categories"; export * from "./use-users"; +export * from "./use-dashboard"; +export * from "./use-services"; diff --git a/src/Web/MeAjudaAi.Web.Admin-React/src/hooks/admin/use-categories.ts b/src/Web/MeAjudaAi.Web.Admin-React/src/hooks/admin/use-categories.ts index 6dcc77be1..72abaa146 100644 --- a/src/Web/MeAjudaAi.Web.Admin-React/src/hooks/admin/use-categories.ts +++ b/src/Web/MeAjudaAi.Web.Admin-React/src/hooks/admin/use-categories.ts @@ -58,13 +58,10 @@ export function useUpdateCategory() { const queryClient = useQueryClient(); return useMutation({ - mutationFn: ({ - id, - ...data - }: ApiCategoriesPutData["path"] & { data: ApiCategoriesPutData["body"] }) => + mutationFn: ({ id, ...body }: { id: string } & ApiCategoriesPutData["body"]) => apiCategoriesPut({ path: { id }, - body: data.data as ApiCategoriesPutData["body"], + body: body as ApiCategoriesPutData["body"], }), onSuccess: (_, variables) => { queryClient.invalidateQueries({ queryKey: categoryKeys.detail(variables.id) }); diff --git a/src/Web/MeAjudaAi.Web.Admin-React/src/hooks/admin/use-dashboard.ts b/src/Web/MeAjudaAi.Web.Admin-React/src/hooks/admin/use-dashboard.ts new file mode 100644 index 000000000..794b4d8de --- /dev/null +++ b/src/Web/MeAjudaAi.Web.Admin-React/src/hooks/admin/use-dashboard.ts @@ -0,0 +1,61 @@ +"use client"; + +import { useQuery } from "@tanstack/react-query"; +import { apiProvidersGet } from "@/lib/api/generated"; +import type { ApiProvidersGetData } from "@/lib/api/generated"; + +export interface DashboardStats { + total: number; + pending: number; + approved: number; + rejected: number; + suspended: number; + underReview: number; + individual: number; + company: number; + freelancer: number; + cooperative: number; +} + +export function useDashboardStats() { + return useQuery({ + queryKey: ["dashboard", "stats"], + queryFn: async (): Promise => { + const response = await apiProvidersGet({} as ApiProvidersGetData); + const providers = response.data?.data ?? []; + + const stats: DashboardStats = { + total: providers.length, + pending: 0, + approved: 0, + rejected: 0, + suspended: 0, + underReview: 0, + individual: 0, + company: 0, + freelancer: 0, + cooperative: 0, + }; + + providers.forEach((p) => { + switch (p.verificationStatus) { + case 0: stats.pending++; break; + case 1: stats.underReview++; break; + case 2: stats.approved++; break; + case 3: stats.rejected++; break; + case 4: stats.suspended++; break; + } + + switch (p.type) { + case 1: stats.individual++; break; + case 2: stats.company++; break; + case 3: stats.cooperative++; break; + case 4: stats.freelancer++; break; + } + }); + + return stats; + }, + staleTime: 1000 * 60 * 5, + }); +} diff --git a/src/Web/MeAjudaAi.Web.Admin-React/src/hooks/admin/use-services.ts b/src/Web/MeAjudaAi.Web.Admin-React/src/hooks/admin/use-services.ts new file mode 100644 index 000000000..6168eaf00 --- /dev/null +++ b/src/Web/MeAjudaAi.Web.Admin-React/src/hooks/admin/use-services.ts @@ -0,0 +1,83 @@ +"use client"; + +import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"; +import { + apiServicesGet, + apiServicesGet2, + apiServicesPost, + apiServicesPut, + apiServicesDelete, +} from "@/lib/api/generated"; +import type { + ApiServicesGetData, + ApiServicesGet2Data, + ApiServicesPostData, + ApiServicesPutData, + ApiServicesDeleteData, +} from "@/lib/api/generated"; + +export const serviceKeys = { + all: ["services"] as const, + lists: () => [...serviceKeys.all, "list"] as const, + list: (filters?: ApiServicesGetData["query"]) => + [...serviceKeys.lists(), filters] as const, + details: () => [...serviceKeys.all, "detail"] as const, + detail: (id: string) => [...serviceKeys.details(), id] as const, +}; + +export function useServices(categoryId?: string) { + return useQuery({ + queryKey: serviceKeys.list({ categoryId }), + queryFn: () => apiServicesGet({ query: { categoryId } } as ApiServicesGetData), + select: (data) => data.data, + }); +} + +export function useServiceById(id: string) { + return useQuery({ + queryKey: serviceKeys.detail(id), + queryFn: () => apiServicesGet2({ path: { id } } as ApiServicesGet2Data), + select: (data) => data.data, + enabled: !!id, + }); +} + +export function useCreateService() { + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: (data: ApiServicesPostData["body"]) => + apiServicesPost({ body: data }), + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: serviceKeys.lists() }); + }, + }); +} + +export function useUpdateService() { + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: ({ id, ...body }: { id: string } & ApiServicesPutData["body"]) => + apiServicesPut({ + path: { id }, + body: body as ApiServicesPutData["body"], + }), + onSuccess: (_, variables) => { + queryClient.invalidateQueries({ queryKey: serviceKeys.detail(variables.id) }); + queryClient.invalidateQueries({ queryKey: serviceKeys.lists() }); + }, + }); +} + +export function useDeleteService() { + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: (id: string) => + apiServicesDelete({ path: { id } } as ApiServicesDeleteData), + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: serviceKeys.lists() }); + }, + }); +} From 5c1ea5394ec40eb242a1ec28e9801ed11e1388aa Mon Sep 17 00:00:00 2001 From: Filipe Frigini Date: Sat, 21 Mar 2026 14:25:37 -0300 Subject: [PATCH 06/19] feat(Admin): Add provider detail page with approve/reject actions - Create dynamic route /providers/[id] for provider details - Display provider contact info, address, documents, and services - Add approve/suspend actions in detail page - Link provider names to detail view in list page --- .../src/app/(admin)/providers/[id]/page.tsx | 282 ++++++++++++++++++ .../src/app/(admin)/providers/page.tsx | 11 +- 2 files changed, 291 insertions(+), 2 deletions(-) create mode 100644 src/Web/MeAjudaAi.Web.Admin-React/src/app/(admin)/providers/[id]/page.tsx diff --git a/src/Web/MeAjudaAi.Web.Admin-React/src/app/(admin)/providers/[id]/page.tsx b/src/Web/MeAjudaAi.Web.Admin-React/src/app/(admin)/providers/[id]/page.tsx new file mode 100644 index 000000000..8bea51236 --- /dev/null +++ b/src/Web/MeAjudaAi.Web.Admin-React/src/app/(admin)/providers/[id]/page.tsx @@ -0,0 +1,282 @@ +"use client"; + +import { use, useState } from "react"; +import Link from "next/link"; +import { ArrowLeft, Mail, Phone, MapPin, FileText, CheckCircle, XCircle, Loader2 } from "lucide-react"; +import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card"; +import { Button } from "@/components/ui/button"; +import { Badge } from "@/components/ui/badge"; +import { + Dialog, + DialogContent, + DialogHeader, + DialogTitle, + DialogDescription, + DialogFooter, +} from "@/components/ui/dialog"; +import { useProviderById, useActivateProvider, useDeactivateProvider } from "@/hooks/admin"; +import { + providerTypeLabels, + providerStatusLabels, + verificationStatusLabels, + providerTierLabels, + type VerificationStatus, + type ProviderTier, +} from "@/lib/types"; + +const getVerificationBadgeVariant = (status?: VerificationStatus) => { + switch (status) { + case 2: return "success" as const; + case 0: return "warning" as const; + case 3: + case 4: return "destructive" as const; + default: return "secondary" as const; + } +}; + +interface PageProps { + params: Promise<{ id: string }>; +} + +export default function ProviderDetailPage({ params }: PageProps) { + const { id } = use(params); + const [isApproveOpen, setIsApproveOpen] = useState(false); + const [isRejectOpen, setIsRejectOpen] = useState(false); + + const { data: provider, isLoading, error } = useProviderById(id); + const activateMutation = useActivateProvider(); + const deactivateMutation = useDeactivateProvider(); + + const handleApprove = async () => { + await activateMutation.mutateAsync(id); + setIsApproveOpen(false); + }; + + const handleReject = async () => { + await deactivateMutation.mutateAsync(id); + setIsRejectOpen(false); + }; + + if (isLoading) { + return ( +
+ +
+ ); + } + + if (error || !provider) { + return ( +
+

Erro ao carregar prestador. Tente novamente.

+ + + +
+ ); + } + + const businessProfile = provider.businessProfile; + const contact = businessProfile?.contactInfo; + const address = businessProfile?.primaryAddress; + + return ( +
+
+ + + Voltar para lista + +
+
+

{provider.name ?? "Prestador"}

+
+ + {verificationStatusLabels[provider.verificationStatus as keyof typeof verificationStatusLabels] ?? "-"} + + + {providerTypeLabels[provider.type as keyof typeof providerTypeLabels] ?? "-"} + + + {providerTierLabels[provider.tier as keyof typeof providerTierLabels] ?? "-"} + +
+
+
+ + +
+
+
+ +
+ + + + InformaƧƵes de Contato + + + +
+ +

{contact?.email ?? "-"}

+
+
+ +

{contact?.phoneNumber ?? "-"}

+
+ {contact?.additionalPhones && contact.additionalPhones.length > 0 && ( +
+ +

{contact.additionalPhones.join(", ")}

+
+ )} +
+
+ + + + + EndereƧo + + + +
+ +

{address?.city ?? "-"}

+
+
+ +

{address?.state ?? "-"}

+
+
+ +

+ {[ + address?.street, + address?.number, + address?.neighborhood, + address?.zipCode, + ].filter(Boolean).join(", ") || "-"} +

+
+
+
+ + + + + Documentos + + + + {provider.documents && provider.documents.length > 0 ? ( +
+ {provider.documents.map((doc, index) => ( +
+
+

{doc.documentType ?? "Documento"}

+

{doc.fileName ?? "-"}

+
+ + {doc.verificationStatus === 2 ? "Verificado" : "Pendente"} + +
+ ))} +
+ ) : ( +

Nenhum documento enviado.

+ )} +
+
+ + {provider.services && provider.services.length > 0 && ( + + + ServiƧos + + +
+ {provider.services.map((service, index) => ( + + {service.serviceName ?? "ServiƧo"} + + ))} +
+
+
+ )} + + + + InformaƧƵes Adicionais + + +
+ +

+ {providerStatusLabels[provider.status as keyof typeof providerStatusLabels] ?? "-"} +

+
+
+ +

+ {provider.createdAt ? new Date(provider.createdAt).toLocaleDateString("pt-BR") : "-"} +

+
+
+ +

+ {provider.updatedAt ? new Date(provider.updatedAt).toLocaleDateString("pt-BR") : "-"} +

+
+
+
+
+ + + + + Aprovar Prestador + + Tem certeza que deseja aprovar o prestador {provider.name}? + Ele poderÔ começar a operar na plataforma. + + + + + + + + + + + + + Suspender Prestador + + Tem certeza que deseja suspender o prestador {provider.name}? + Ele não poderÔ mais operar na plataforma. + + + + + + + + +
+ ); +} diff --git a/src/Web/MeAjudaAi.Web.Admin-React/src/app/(admin)/providers/page.tsx b/src/Web/MeAjudaAi.Web.Admin-React/src/app/(admin)/providers/page.tsx index df6711a62..9beb5b741 100644 --- a/src/Web/MeAjudaAi.Web.Admin-React/src/app/(admin)/providers/page.tsx +++ b/src/Web/MeAjudaAi.Web.Admin-React/src/app/(admin)/providers/page.tsx @@ -1,6 +1,7 @@ "use client"; import { useState } from "react"; +import Link from "next/link"; import { Search, Plus, Pencil, Trash2, Eye, CheckCircle, XCircle, Loader2 } from "lucide-react"; import { Card } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; @@ -99,7 +100,11 @@ export default function ProvidersPage() { {filteredProviders.map((provider) => ( - {provider.name ?? "-"} + + + {provider.name ?? "-"} + + {provider.businessProfile?.contactInfo?.email ?? "-"} @@ -115,7 +120,9 @@ export default function ProvidersPage() { {getProviderCity(provider)}
- + + + From 9c7d2ade4745752fe46e30c2c3b8b20dcf4fb0ef Mon Sep 17 00:00:00 2001 From: Filipe Frigini Date: Sat, 21 Mar 2026 14:27:01 -0300 Subject: [PATCH 07/19] feat(Admin): Add dark/light theme toggle - Create custom ThemeProvider with localStorage persistence - Create ThemeToggle button component - Add theme toggle to sidebar - Update global.css with dark mode CSS variables --- .../src/components/layout/sidebar.tsx | 22 ++++--- .../components/providers/app-providers.tsx | 4 +- .../components/providers/theme-provider.tsx | 58 +++++++++++++++++++ .../src/components/ui/theme-toggle.tsx | 25 ++++++++ 4 files changed, 98 insertions(+), 11 deletions(-) create mode 100644 src/Web/MeAjudaAi.Web.Admin-React/src/components/providers/theme-provider.tsx create mode 100644 src/Web/MeAjudaAi.Web.Admin-React/src/components/ui/theme-toggle.tsx diff --git a/src/Web/MeAjudaAi.Web.Admin-React/src/components/layout/sidebar.tsx b/src/Web/MeAjudaAi.Web.Admin-React/src/components/layout/sidebar.tsx index 6f61357de..f2b749559 100644 --- a/src/Web/MeAjudaAi.Web.Admin-React/src/components/layout/sidebar.tsx +++ b/src/Web/MeAjudaAi.Web.Admin-React/src/components/layout/sidebar.tsx @@ -14,6 +14,7 @@ import { } from "lucide-react"; import { signOut, useSession } from "next-auth/react"; import { twMerge } from "tailwind-merge"; +import { ThemeToggle } from "@/components/ui/theme-toggle"; const navItems = [ { href: "/dashboard", label: "Dashboard", icon: LayoutDashboard }, @@ -62,16 +63,19 @@ export function Sidebar() {
-
-
- {session?.user?.name?.charAt(0).toUpperCase() ?? "A"} -
-
-

{session?.user?.name ?? "Admin"}

-

- {session?.user?.roles?.includes("admin") ? "Administrador" : "UsuƔrio"} -

+
+
+
+ {session?.user?.name?.charAt(0).toUpperCase() ?? "A"} +
+
+

{session?.user?.name ?? "Admin"}

+

+ {session?.user?.roles?.includes("admin") ? "Administrador" : "UsuƔrio"} +

+
+
+ ); +} From ff7a084cd360f763d975993e15af88319f9f32e4 Mon Sep 17 00:00:00 2001 From: Filipe Frigini Date: Sat, 21 Mar 2026 16:20:37 -0300 Subject: [PATCH 08/19] feat(Admin): Complete auth integration, form validation, toasts, and pagination - Add middleware for route protection with next-auth - Add Keycloak login page with error handling - Add Zod validation to all CRUD forms - Add Sonner toast notifications for CRUD operations - Add pagination to providers, services, cities, and documents pages - Complete settings page with tabs (profile, notifications, security, appearance) - Complete documents page with document status tracking - Update auth.ts with JWT callbacks for role extraction --- docs/customer-frontend-documentation.md | 2796 +++++++++++++++++ docs/provider-frontend-documentation.md | 1803 +++++++++++ .../src/app/(admin)/allowed-cities/page.tsx | 347 +- .../src/app/(admin)/categories/page.tsx | 154 +- .../src/app/(admin)/documents/page.tsx | 246 +- .../src/app/(admin)/providers/page.tsx | 163 +- .../src/app/(admin)/services/page.tsx | 319 +- .../src/app/(admin)/settings/page.tsx | 207 +- .../src/app/login/page.tsx | 59 + .../components/providers/app-providers.tsx | 2 + .../components/providers/toast-provider.tsx | 18 + .../src/lib/auth/auth.ts | 28 +- .../src/middleware.ts | 5 + 13 files changed, 5682 insertions(+), 465 deletions(-) create mode 100644 docs/customer-frontend-documentation.md create mode 100644 docs/provider-frontend-documentation.md create mode 100644 src/Web/MeAjudaAi.Web.Admin-React/src/app/login/page.tsx create mode 100644 src/Web/MeAjudaAi.Web.Admin-React/src/components/providers/toast-provider.tsx create mode 100644 src/Web/MeAjudaAi.Web.Admin-React/src/middleware.ts diff --git a/docs/customer-frontend-documentation.md b/docs/customer-frontend-documentation.md new file mode 100644 index 000000000..cf8e56fce --- /dev/null +++ b/docs/customer-frontend-documentation.md @@ -0,0 +1,2796 @@ +# MeAjudaAi.Web.Customer - Documentação Completa de Frontend + +Este documento contĆ©m toda a estrutura HTML, CSS e informaƧƵes de design do projeto MeAjudaAi.Web.Customer. + +--- + +# ƍNDICE + +1. [CSS Global](#1-css-global) +2. [Pages (Rotas)](#2-pages-rotas) +3. [Components - UI](#3-components---ui) +4. [Components - Layout](#4-components---layout) +5. [Components - Features](#5-components---features) +6. [Imagens e Assets](#6-imagens-e-assets) +7. [Sistema de Design](#7-sistema-de-design) + +--- + +# 1. CSS GLOBAL + +## Arquivo: `app/globals.css` + +```css +@import "tailwindcss"; + +:root { + --background: #ffffff; + --foreground: #2e2e2e; + + /* Light mode tokens */ + --surface: #ffffff; + --surface-raised: #f5f5f5; + --foreground-subtle: #666666; + --border: #e0e0e0; + --input: #e0e0e0; + --popover: #ffffff; + --popover-foreground: var(--foreground); + --card: #ffffff; + --card-foreground: var(--foreground); + --muted: #f5f5f5; + --muted-foreground: #666666; + --accent: #f5f5f5; + --accent-foreground: var(--foreground); +} + +@media (prefers-color-scheme: dark) { + :root { + --background: #0a0a0a; + --foreground: #ededed; + + /* Dark mode overrides */ + --surface: #1a1a1a; + --surface-raised: #262626; + --foreground-subtle: #a3a3a3; + --border: #404040; + --input: #404040; + --popover: #1a1a1a; + --popover-foreground: var(--foreground); + --card: #1a1a1a; + --card-foreground: var(--foreground); + --muted: #262626; + --muted-foreground: #a3a3a3; + --accent: #262626; + --accent-foreground: var(--foreground); + } +} + +@theme inline { + /* Colors from Figma */ + --color-primary: #395873; + --color-primary-foreground: #ffffff; + --color-primary-hover: #2E4760; + + --color-secondary: #D96704; + --color-secondary-light: #F2AE72; + --color-secondary-foreground: #ffffff; + --color-secondary-hover: #B85703; + + --color-surface: var(--surface); + --color-surface-raised: var(--surface-raised); + + --color-foreground: var(--foreground); + --color-foreground-subtle: var(--foreground-subtle); + + --color-border: var(--border); + --color-input: var(--input); + --color-ring: #D96704; + + --color-brand: #E0702B; + --color-brand-hover: #c56226; + + --color-destructive: #dc2626; + --color-destructive-foreground: #ffffff; + + --color-popover: var(--popover); + --color-popover-foreground: var(--popover-foreground); + + --color-card: var(--card); + --color-card-foreground: var(--card-foreground); + + --color-muted: var(--muted); + --color-muted-foreground: var(--muted-foreground); + + --color-accent: var(--accent); + --color-accent-foreground: var(--accent-foreground); + + --color-background: var(--background); + --font-sans: 'Roboto', Arial, Helvetica, sans-serif; +} + +body { + background: var(--background); + color: var(--foreground); + font-family: var(--font-sans); +} +``` + +--- + +# 2. PAGES (ROTAS) + +## ROTA: `/` (Home) +**Arquivo:** `app/(main)/page.tsx` + +```tsx +import { CheckCircle2 } from "lucide-react"; +import { Button } from "@/components/ui/button"; +import { AdBanner } from "@/components/ui/ad-banner"; +import { CitySearch } from "@/components/search/city-search"; +import Image from "next/image"; +import { HowItWorks } from "@/components/home/how-it-works"; + +export default function HomePage() { + return ( +
+ + + {/* Hero Section - White Background */} +
+
+
+

+ Conectando quem precisa com + quem sabe fazer. +

+
+ + {/* City Search - Center aligned */} +
+ +
+
+
+ + {/* Blue Section - ConheƧa */} +
+
+
+

+ ConheƧa o MeAjudaAƭ +

+

+ Você jÔ precisou de algum serviço e não sabia de nenhuma referência + ou alguém que conhecia alguém que faça esse serviço que você estÔ + precisando? +

+

+ Nós nascemos para solucionar esse problema, uma plataforma que + conecta quem estÔ oferecendo serviço com quem estÔ prestando + serviço. Oferecemos métodos de avaliação dos serviços prestados, + você consegue saber se o prestador possui boas indicações com + base nos serviços jÔ prestados por ele pela nossa plataforma. +

+
+ +
+ ConheƧa o MeAjudaAƭ +
+
+
+ + {/* How It Works Section */} +
+
+ +
+
+ + {/* CTA Prestadores */} +
+
+
+ +
+ Seja um prestador +
+ +
+
+
+ +
+

+ Você é prestador de serviço? +

+
+ +

+ FaƧa seu cadastro na nossa plataforma, cadastre seus serviƧos, + meios de contato e apareƧa para seus clientes, tenha boas + recomendaƧƵes e destaque-se frente aos seus concorrentes. +

+ +

+ Não importa qual tipo de serviço você presta, sempre tem alguém + precisando de uma ajuda! Conseguimos fazer com que o seu cliente + te encontre, você estarÔ na vitrine virtual mais cobiçada do Brasil. +

+ + +
+
+
+
+
+ ); +} +``` + +--- + +## ROTA: `/buscar` +**Arquivo:** `app/(main)/buscar/page.tsx` + +```tsx +import { Suspense } from "react"; +import { Search } from "lucide-react"; +import { Button } from "@/components/ui/button"; +import { ServiceCard } from "@/components/service/service-card"; +import { AdCard } from "@/components/search/ad-card"; +import { ServiceTags } from "@/components/search/service-tags"; +import { SearchFilters } from "@/components/search/search-filters"; + +export default async function SearchPage({ searchParams }) { + // ... (server component com fetch de providers) + + return ( +
+ {/* Search Bar Centered */} +
+
+
+ + +
+
+
+ +
+ {/* Sidebar Filters */} + + +
+ {/* Service Tags */} +
+ }> + + +
+ + {/* Provider Grid */} + {providers.length > 0 ? ( +
+ {gridItems.map((item, index) => { + if (item.type === 'ad') { + return ; + } + return ( + s.serviceName).filter((s): s is string => !!s)} + rating={provider.averageRating ?? 0} + reviewCount={provider.reviewCount ?? 0} + /> + ); + })} +
+ ) : ( +
+ +

+ Nenhum prestador encontrado +

+
+ )} +
+
+
+ ); +} +``` + +--- + +## ROTA: `/prestador/[id]` +**Arquivo:** `app/(main)/prestador/[id]/page.tsx` + +```tsx +import { Avatar } from "@/components/ui/avatar"; +import { Rating } from "@/components/ui/rating"; +import { ReviewList } from "@/components/reviews/review-list"; +import { ReviewForm } from "@/components/reviews/review-form"; +import { Badge } from "@/components/ui/badge"; +import { MessageCircle } from "lucide-react"; +import { VerifiedBadge } from "@/components/ui/verified-badge"; +import { getWhatsappLink } from "@/lib/utils/phone"; + +export default async function ProviderProfilePage({ params }) { + const { id } = await params; + const providerData = await getCachedProvider(id); + + return ( +
+
+
+ {/* Left Column: Avatar, Rating, Phones */} +
+ + +
+ + {reviewCount > 0 && ( + ({reviewCount} avaliaƧƵes) + )} +
+ + {phones.length > 0 ? ( +
+ {phones.map((phone, i) => ( +
+ {phone} + + + +
+ ))} +
+ ) : isAuthenticated ? ( +
+

Este prestador não informou contatos.

+
+ ) : ( +
+

FaƧa login para visualizar os contatos.

+
+ )} +
+ + {/* Right Column: Name, Email, Description, Services */} +
+
+

{displayName}

+ +
+ + {providerData.email && ( +

{providerData.email}

+ )} + +
+

{description}

+
+ + {services.length > 0 && ( +
+

ServiƧos

+
+ {services.map((service, i) => ( + + {service} + + ))} +
+
+ )} +
+
+
+ + {/* Comments Section */} +
+
+

ComentƔrios

+
+
+
+ +
+ +
+
+
+ ); +} +``` + +--- + +## ROTA: `/prestador` (Dashboard Provider) +**Arquivo:** `app/(main)/prestador/page.tsx` + +```tsx +import DashboardClient from "@/components/providers/dashboard-client"; + +export default async function DashboardPage() { + // Server component que busca dados do provider e renderiza DashboardClient + return ; +} +``` + +--- + +## ROTA: `/perfil` +**Arquivo:** `app/(main)/perfil/page.tsx` + +```tsx +import { Button } from "@/components/ui/button"; +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; +import { User, Mail, Phone, MapPin, Pencil } from "lucide-react"; +import Link from "next/link"; + +export default async function ProfilePage() { + return ( +
+
+

Meu Perfil

+ +
+ + + + InformaƧƵes Pessoais + + +
+
+

+ Nome Completo +

+

{user.fullName}

+
+ +
+

+ Email +

+

{user.email}

+
+ +
+

+ Telefone +

+

{"NĆ£o informado"}

+
+ +
+

+ Localização +

+

{"NĆ£o informado"}

+
+
+
+
+
+ ); +} +``` + +--- + +## ROTA: `/perfil/editar` +**Arquivo:** `app/(main)/perfil/editar/page.tsx` + +```tsx +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; +import { EditProfileForm } from "@/components/profile/edit-profile-form"; + +export default async function EditProfilePage() { + return ( +
+

Editar Perfil

+ + + + Dados Pessoais + + + + + +
+ ); +} +``` + +--- + +## ROTA: `/cadastro/prestador` +**Arquivo:** `app/(main)/cadastro/prestador/page.tsx` + +```tsx +import { useForm } from "react-hook-form"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form"; +import { Checkbox } from "@/components/ui/checkbox"; +import { ShieldCheck, Info } from "lucide-react"; +import Link from "next/link"; + +export default function RegisterProviderPage() { + const form = useForm({ + resolver: zodResolver(registerProviderSchema), + defaultValues: { + name: "", + type: EProviderType.Individual, + documentNumber: "", + phoneNumber: "", + email: "", + acceptedTerms: false, + acceptedPrivacyPolicy: false, + }, + }); + + return ( +
+ {/* Stepper */} +
+
+ +
+
+ 1 +
+ Dados Iniciais +
+ +
+
+ 2 +
+ EndereƧo +
+ +
+
+ 3 +
+ Documentos +
+
+ +
+

+ Passo 1: Crie sua conta +

+

+ Inicie seu credenciamento. Nas próximas etapas, pediremos seu endereço e documentos. +

+
+ +
+ + ( + + Nome Completo (ou Razão Social) + + + + + + )} /> + + ( + + Tipo de Pessoa + +
+ + + + +
+
+
+ )} /> + + {/* Checkboxes de termos */} + ( + + + + +
+ + Aceito os Termos de Uso + +
+
+ )} /> + + + + + + {/* Privacy Badge */} +
+ +
+
+ ); +} +``` + +--- + +## ROTA: `/cadastro/prestador/perfil` +**Arquivo:** `app/(main)/cadastro/prestador/perfil/page.tsx` + +```tsx +import { BasicInfoForm } from "@/components/providers/basic-info-form"; + +export default function BasicInfoPage() { + return ( +
+ {/* Stepper com passo 1 ativo */} + {/* FormulƔrio BasicInfoForm */} + +
+ ); +} +``` + +--- + +## ROTA: `/cadastro/prestador/perfil/endereco` +**Arquivo:** `app/(main)/cadastro/prestador/perfil/endereco/page.tsx` + +```tsx +import { AddressForm } from "@/components/providers/address-form"; + +export default function AddressPage() { + return ( +
+ {/* Stepper com passo 2 ativo */} + +
+ ); +} +``` + +--- + +## ROTA: `/cadastro/prestador/perfil/documentos` +**Arquivo:** `app/(main)/cadastro/prestador/perfil/documentos/page.tsx` + +```tsx +import { DocumentUpload } from "@/components/providers/document-upload"; + +export default function DocumentsPage() { + return ( +
+ {/* Stepper com passo 3 ativo */} + +
+ ); +} +``` + +--- + +## ROTA: `/auth/signin` +**Arquivo:** `app/(auth)/auth/signin/page.tsx` + +```tsx +import { LoginForm } from "@/components/auth/login-form"; +import { AuthSelectionDropdown } from "@/components/auth/auth-selection-dropdown"; + +export default function SignInPage() { + return ( +
+
+ + +
+
+ ); +} +``` + +--- + +## ROTA: `/auth/cadastro/cliente` +**Arquivo:** `app/(auth)/cadastro/cliente/page.tsx` + +```tsx +import { CustomerRegisterForm } from "@/components/auth/customer-register-form"; + +export default function CustomerRegisterPage() { + return ( +
+
+ +
+
+ ); +} +``` + +--- + +# 3. COMPONENTS - UI + +## `components/ui/button.tsx` + +```tsx +import * as React from "react"; +import { Slot } from "@radix-ui/react-slot"; +import { cva, type VariantProps } from "class-variance-authority"; + +const buttonVariants = cva( + "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0", + { + variants: { + variant: { + default: "bg-primary text-primary-foreground hover:bg-primary-hover", + destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90", + outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground", + secondary: "bg-secondary text-secondary-foreground hover:bg-secondary-hover", + ghost: "hover:bg-accent hover:text-accent-foreground", + link: "text-primary underline-offset-4 hover:underline", + primary: "bg-primary text-primary-foreground hover:bg-primary-hover", + }, + size: { + default: "h-10 px-4 py-2", + sm: "h-9 rounded-md px-3", + lg: "h-11 rounded-md px-8", + icon: "h-10 w-10", + }, + }, + defaultVariants: { + variant: "default", + size: "default", + }, + } +); + +export interface ButtonProps + extends React.ButtonHTMLAttributes, + VariantProps { + asChild?: boolean; +} + +const Button = React.forwardRef( + ({ className, variant, size, asChild = false, ...props }, ref) => { + const Comp = asChild ? Slot : "button"; + return ( + + ); + } +); +Button.displayName = "Button"; + +export { Button, buttonVariants }; +``` + +--- + +## `components/ui/card.tsx` + +```tsx +import * as React from "react"; +import { cn } from "@/lib/utils"; + +const Card = React.forwardRef>( + ({ className, ...props }, ref) => ( +
+ ) +); +Card.displayName = "Card"; + +const CardHeader = React.forwardRef>( + ({ className, ...props }, ref) => ( +
+ ) +); +CardHeader.displayName = "CardHeader"; + +const CardTitle = React.forwardRef>( + ({ className, ...props }, ref) => ( +

+ ) +); +CardTitle.displayName = "CardTitle"; + +const CardContent = React.forwardRef>( + ({ className, ...props }, ref) => ( +
+ ) +); +CardContent.displayName = "CardContent"; + +export { Card, CardHeader, CardTitle, CardContent }; +``` + +--- + +## `components/ui/badge.tsx` + +```tsx +import * as React from "react"; +import { cva, type VariantProps } from "class-variance-authority"; +import { cn } from "@/lib/utils"; + +const badgeVariants = cva( + "inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2", + { + variants: { + variant: { + default: "border-transparent bg-primary text-primary-foreground hover:bg-primary/80", + secondary: "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80", + destructive: "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80", + outline: "text-foreground", + }, + }, + defaultVariants: { + variant: "default", + }, + } +); + +export interface BadgeProps + extends React.HTMLAttributes, + VariantProps {} + +function Badge({ className, variant, ...props }: BadgeProps) { + return
; +} + +export { Badge, badgeVariants }; +``` + +--- + +## `components/ui/input.tsx` + +```tsx +import * as React from "react"; +import { cn } from "@/lib/utils"; + +export interface InputProps extends React.InputHTMLAttributes {} + +const Input = React.forwardRef( + ({ className, type, ...props }, ref) => { + return ( + + ); + } +); +Input.displayName = "Input"; + +export { Input }; +``` + +--- + +## `components/ui/textarea.tsx` + +```tsx +import * as React from "react"; +import { cn } from "@/lib/utils"; + +export interface TextareaProps extends React.TextareaHTMLAttributes {} + +const Textarea = React.forwardRef( + ({ className, ...props }, ref) => { + return ( +