Skip to content

Commit f7971ac

Browse files
committed
feat: introduz arquitetura por dominios no forntend
1 parent f20a738 commit f7971ac

123 files changed

Lines changed: 3982 additions & 3855 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

frontend/ARCHITECTURE.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# Frontend Architecture
2+
3+
The frontend is organized around domain boundaries instead of technical file types.
4+
5+
## Layers
6+
7+
- `src/app`: application composition, providers, routing, and app-level pages.
8+
- `src/domains/<domain>/domain`: business types and pure rules without React or HTTP.
9+
- `src/domains/<domain>/application`: React hooks and use-cases that orchestrate domain rules.
10+
- `src/domains/<domain>/infrastructure`: API gateways and transport-specific code.
11+
- `src/domains/<domain>/presentation`: pages and components owned by that domain.
12+
- `src/shared`: reusable UI primitives, assets, hooks, and technical utilities.
13+
14+
## Domains
15+
16+
- `auth`: session state, credentials/OAuth API access, login/register/callback screens.
17+
- `jobs`: job entities, filtering/deduplication/pagination rules, scraper/job API access, dashboard UI.
18+
- `marketing`: public landing page sections.
19+
20+
## Compatibility
21+
22+
Legacy paths such as `@/components`, `@/hooks`, `@/services`, `@/types`, and `@/pages` are kept as thin re-export shims. New code should import from `@/app`, `@/domains`, or `@/shared`.

frontend/components.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,11 @@
1313
"iconLibrary": "lucide",
1414
"rtl": false,
1515
"aliases": {
16-
"components": "@/components",
17-
"utils": "@/lib/utils",
18-
"ui": "@/components/ui",
19-
"lib": "@/lib",
20-
"hooks": "@/hooks"
16+
"components": "@/shared/ui",
17+
"utils": "@/shared/lib/utils",
18+
"ui": "@/shared/ui",
19+
"lib": "@/shared/lib",
20+
"hooks": "@/shared/hooks"
2121
},
2222
"menuColor": "default",
2323
"menuAccent": "subtle",

frontend/src/App.tsx

Lines changed: 1 addition & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,60 +1 @@
1-
import { useState, useEffect } from "react";
2-
import { Navigate, Route, Routes } from "react-router-dom";
3-
import LandingPage from "./pages/dashboard/LandingPage";
4-
import Dashboard from "./pages/dashboard/Dashboard";
5-
import NotFound from "./not_found";
6-
import Loading from "./Loading";
7-
import LoginPage from "./pages/login/LoginPage";
8-
import RegisterPage from "./pages/register/RegisterPage";
9-
import AuthCallback from "./pages/auth/AuthCallback";
10-
import { useAuth } from "@/context/AuthContext";
11-
12-
function ProtectedRoute({ children }: { children: React.ReactNode }) {
13-
const { user, isLoading } = useAuth();
14-
if (isLoading) return <Loading />;
15-
if (!user) return <Navigate to="/login" replace />;
16-
return <>{children}</>;
17-
}
18-
19-
function PublicRoute({ children }: { children: React.ReactNode }) {
20-
const { user, isLoading } = useAuth();
21-
if (isLoading) return <Loading />;
22-
if (user) return <Navigate to="/app" replace />;
23-
return <>{children}</>;
24-
}
25-
26-
function App() {
27-
const [appCarregando, setAppCarregando] = useState(true);
28-
29-
useEffect(() => {
30-
const timer = setTimeout(() => {
31-
setAppCarregando(false);
32-
}, 2000);
33-
34-
return () => clearTimeout(timer);
35-
}, []);
36-
37-
if (appCarregando) {
38-
return <Loading />;
39-
}
40-
41-
return (
42-
<Routes>
43-
<Route path="/" element={<LandingPage />} />
44-
<Route
45-
path="/app"
46-
element={
47-
<ProtectedRoute>
48-
<Dashboard />
49-
</ProtectedRoute>
50-
}
51-
/>
52-
<Route path="/login" element={<PublicRoute><LoginPage /></PublicRoute>} />
53-
<Route path="/register" element={<PublicRoute><RegisterPage /></PublicRoute>} />
54-
<Route path="/auth/callback" element={<AuthCallback />} />
55-
<Route path="*" element={<NotFound />} />
56-
</Routes>
57-
);
58-
}
59-
60-
export default App;
1+
export { default } from "@/app/App";

frontend/src/Loading.tsx

Lines changed: 1 addition & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1 @@
1-
import { DotLottieReact } from "@lottiefiles/dotlottie-react";
2-
import loadingAnimation from "./assets/teste.json";
3-
4-
export default function Loading() {
5-
return (
6-
<div className="fixed inset-0 z-50 flex flex-col items-center justify-center bg-background px-6">
7-
<div className="w-64 h-64 flex items-center justify-center select-none pointer-events-none">
8-
<DotLottieReact
9-
data={loadingAnimation}
10-
loop
11-
autoplay
12-
className="w-full h-full object-contain"
13-
/>
14-
</div>
15-
<p className="mt-4 text-lg font-medium text-muted-foreground animate-pulse">
16-
Carregando...
17-
</p>
18-
</div>
19-
);
20-
}
1+
export { default } from "@/shared/ui/Loading";

frontend/src/app/App.tsx

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { useState, useEffect } from "react";
2+
import { AppRoutes } from "@/app/AppRoutes";
3+
import Loading from "@/shared/ui/Loading";
4+
5+
function App() {
6+
const [appCarregando, setAppCarregando] = useState(true);
7+
8+
useEffect(() => {
9+
const timer = setTimeout(() => {
10+
setAppCarregando(false);
11+
}, 2000);
12+
13+
return () => clearTimeout(timer);
14+
}, []);
15+
16+
if (appCarregando) {
17+
return <Loading />;
18+
}
19+
20+
return (
21+
<AppRoutes />
22+
);
23+
}
24+
25+
export default App;

frontend/src/app/AppProviders.tsx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { AuthProvider } from "@/domains/auth/application/AuthContext";
2+
import type { ReactNode } from "react";
3+
import { BrowserRouter } from "react-router-dom";
4+
5+
export function AppProviders({ children }: { children: ReactNode }) {
6+
return (
7+
<BrowserRouter>
8+
<AuthProvider>{children}</AuthProvider>
9+
</BrowserRouter>
10+
);
11+
}

frontend/src/app/AppRoutes.tsx

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import { useAuth } from "@/domains/auth/application/AuthContext";
2+
import AuthCallbackPage from "@/domains/auth/presentation/pages/AuthCallbackPage";
3+
import LoginPage from "@/domains/auth/presentation/pages/LoginPage";
4+
import RegisterPage from "@/domains/auth/presentation/pages/RegisterPage";
5+
import DashboardPage from "@/domains/jobs/presentation/pages/DashboardPage";
6+
import LandingPage from "@/domains/marketing/presentation/pages/LandingPage";
7+
import NotFound from "@/app/NotFound";
8+
import Loading from "@/shared/ui/Loading";
9+
import { Navigate, Route, Routes } from "react-router-dom";
10+
11+
function ProtectedRoute({ children }: { children: React.ReactNode }) {
12+
const { user, isLoading } = useAuth();
13+
if (isLoading) return <Loading />;
14+
if (!user) return <Navigate to="/login" replace />;
15+
return <>{children}</>;
16+
}
17+
18+
function PublicRoute({ children }: { children: React.ReactNode }) {
19+
const { user, isLoading } = useAuth();
20+
if (isLoading) return <Loading />;
21+
if (user) return <Navigate to="/app" replace />;
22+
return <>{children}</>;
23+
}
24+
25+
export function AppRoutes() {
26+
return (
27+
<Routes>
28+
<Route path="/" element={<LandingPage />} />
29+
<Route
30+
path="/dashboard"
31+
element={
32+
<ProtectedRoute>
33+
<DashboardPage />
34+
</ProtectedRoute>
35+
}
36+
/>
37+
<Route
38+
path="/login"
39+
element={
40+
<PublicRoute>
41+
<LoginPage />
42+
</PublicRoute>
43+
}
44+
/>
45+
<Route
46+
path="/register"
47+
element={
48+
<PublicRoute>
49+
<RegisterPage />
50+
</PublicRoute>
51+
}
52+
/>
53+
<Route path="/auth/callback" element={<AuthCallbackPage />} />
54+
<Route path="*" element={<NotFound />} />
55+
</Routes>
56+
);
57+
}

frontend/src/app/NotFound.tsx

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import { Link } from "react-router-dom";
2+
import { motion } from "framer-motion";
3+
import { DotLottieReact } from "@lottiefiles/dotlottie-react";
4+
5+
import lottieAnimation from "@/shared/assets/lottie.json";
6+
7+
export default function NotFound() {
8+
return (
9+
<section className="min-h-screen flex flex-col items-center justify-center relative bg-white dark:bg-[#0d1a14] font-sans px-6">
10+
11+
<div className="absolute w-[500px] h-[500px] bg-emerald-100/20 dark:bg-emerald-950/10 blur-[100px] rounded-full pointer-events-none top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2" />
12+
13+
<div className="relative z-10 text-center max-w-md mx-auto flex flex-col items-center">
14+
15+
<motion.div
16+
initial={{ opacity: 0, scale: 0.95 }}
17+
animate={{ opacity: 1, scale: 1 }}
18+
transition={{ duration: 0.4 }}
19+
className="w-80 h-80 md:w-96 md:h-96 flex items-center justify-center select-none pointer-events-none -mb-2"
20+
>
21+
<DotLottieReact
22+
data={lottieAnimation}
23+
loop
24+
autoplay
25+
/>
26+
</motion.div>
27+
28+
<motion.h2
29+
initial={{ opacity: 0, y: 10 }}
30+
animate={{ opacity: 1, y: 0 }}
31+
transition={{ duration: 0.4, delay: 0.05 }}
32+
className="text-2xl md:text-3xl font-extrabold text-gray-900 dark:text-white tracking-tight mb-2"
33+
>
34+
Ops! Página não encontrada
35+
</motion.h2>
36+
37+
38+
<motion.p
39+
initial={{ opacity: 0, y: 10 }}
40+
animate={{ opacity: 1, y: 0 }}
41+
transition={{ duration: 0.4, delay: 0.1 }}
42+
className="text-gray-400 dark:text-neutral-400 text-sm md:text-base mb-6 font-normal"
43+
>
44+
Parece que o panda se perdeu no caminho.
45+
</motion.p>
46+
47+
<motion.div
48+
initial={{ opacity: 0, y: 10 }}
49+
animate={{ opacity: 1, y: 0 }}
50+
transition={{ duration: 0.4, delay: 0.15 }}
51+
>
52+
<Link
53+
to="/"
54+
className="inline-flex items-center justify-center bg-white dark:bg-white text-black dark:text-black font-semibold text-sm px-6 py-2.5 rounded-xl transition-all shadow-sm hover:bg-gray-100"
55+
>
56+
Voltar para o Início
57+
</Link>
58+
</motion.div>
59+
</div>
60+
</section>
61+
);
62+
}

0 commit comments

Comments
 (0)