Skip to content

Commit a8e10c2

Browse files
authored
Merge pull request #686 from vintasoftware/597-update-react-router
Upgrade React Router to v7
2 parents f49b1d1 + 5ccc9f5 commit a8e10c2

File tree

22 files changed

+233
-74
lines changed

22 files changed

+233
-74
lines changed

backend/common/urls.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,5 @@
66
app_name = "common"
77
urlpatterns = [
88
path("", views.IndexView.as_view(), name="index"),
9+
path("users", views.IndexView.as_view(), name="index"),
910
]
Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
{% extends 'base.html' %}
22

3-
43
{% block body %}
5-
<div class="container">
6-
<h1 class="heading-1">Django React Boilerplate Example App</h1>
7-
<p class="paragraph">
4+
<div class="max-w-5xl mx-auto px-4">
5+
<h1 class="text-5xl mb-2">Django React Boilerplate Example App</h1>
6+
<p class="mb-2">
87
Below is an example of a React app included in the Django template.<br/>
9-
Check <code class="inline-code">backend/templates/common/index.html</code> and <code class="inline-code">frontend/js/index.js</code> to understand how they're linked:
8+
Check <code class="px-1.5 py-0.5 text-sm font-mono text-pink-600 bg-gray-100 rounded">backend/templates/common/index.html</code> and <code class="px-1.5 py-0.5 text-sm font-mono text-pink-600 bg-gray-100 rounded">frontend/js/index.js</code> to understand how they're linked:
109
</p>
1110
</div>
12-
<div class="container" id="react-app"></div>
11+
<div class="max-w-5xl mx-auto px-4" id="react-app"></div>
1312
{% endblock %}
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{% extends 'base.html' %}
22

33
{% block body %}
4-
<div class="container">
4+
<div class="max-w-5xl mx-auto px-4">
55
<h1>Temporary User Lockout</h1>
66
<p>
77
You have been locked out due to too many failed attempts. You have reached the failure limit of {{ failure_limit }} attempts.
@@ -11,4 +11,4 @@ <h1>Temporary User Lockout</h1>
1111
</p>
1212
<p>Please try again after the cool off period.</p>
1313
</div>
14-
{% endblock %}
14+
{% endblock %}

frontend/css/style.css

Lines changed: 0 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1 @@
11
@import "tailwindcss";
2-
3-
/* Django background */
4-
#django-background {
5-
@apply text-[#092e20] text-[11pt] bg-no-repeat bg-[auto_200px] bg-center h-[300px] bg-[url('../assets/images/django-logo-positive.png')];
6-
}
7-
8-
/* Logo wrapper */
9-
#django-logo-wrapper {
10-
@apply text-[#092e20] mb-4;
11-
}
12-
13-
#django-logo-wrapper > img {
14-
@apply w-[100px];
15-
}
16-
17-
/* Page container */
18-
.container {
19-
@apply max-w-5xl mx-auto px-4;
20-
}
21-
22-
/* Inline code */
23-
.inline-code {
24-
@apply px-1.5 py-0.5 text-sm font-mono text-pink-600 bg-gray-100 rounded;
25-
}
26-
27-
/* Headings */
28-
.heading-1 {
29-
@apply text-5xl mb-2;
30-
}
31-
32-
.heading-2 {
33-
@apply text-4xl mb-2;
34-
}
35-
36-
/* Paragraphs */
37-
.paragraph {
38-
@apply mb-2;
39-
}
40-
41-
/* Button */
42-
.btn {
43-
@apply px-2 py-1 border border-black text-black rounded-md
44-
hover:bg-black hover:text-white transition duration-200 cursor-pointer;
45-
}

frontend/js/App.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import * as Sentry from "@sentry/react";
22
import cookie from "cookie";
3+
import { RouterProvider } from "react-router/dom";
34

45
import { OpenAPI } from "./api";
5-
import Home from "./pages/Home";
6+
import router from "./routes";
67

78
OpenAPI.interceptors.request.use((request) => {
89
const { csrftoken } = cookie.parse(document.cookie);
@@ -14,7 +15,7 @@ OpenAPI.interceptors.request.use((request) => {
1415

1516
const App = () => (
1617
<Sentry.ErrorBoundary fallback={<p>An error has occurred</p>}>
17-
<Home />
18+
<RouterProvider router={router} />
1819
</Sentry.ErrorBoundary>
1920
);
2021

frontend/js/components/TopNav.tsx

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import { NavLink } from "react-router";
2+
3+
const TopNav = () => {
4+
return (
5+
<header className="sticky top-0 z-50">
6+
<nav
7+
aria-label="Primary"
8+
className="mx-auto mt-4 mb-6 max-w-6xl rounded-xl bg-zinc-900/80 backdrop-blur ring-1 ring-white/10"
9+
>
10+
<div className="flex items-center gap-2 px-4 py-2">
11+
<a className="mr-2 font-semibold tracking-tight text-white" href="/">
12+
django-react-boilerplate
13+
</a>
14+
15+
<NavLink
16+
className={({ isActive }) =>
17+
[
18+
"px-3 py-2 rounded-lg text-sm font-medium text-zinc-300 transition",
19+
"hover:text-white hover:bg-white/5",
20+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white/40",
21+
isActive ? "text-white bg-white/10" : "",
22+
].join(" ")
23+
}
24+
end
25+
to="/"
26+
>
27+
Home
28+
</NavLink>
29+
30+
<NavLink
31+
className={({ isActive }) =>
32+
[
33+
"px-3 py-2 rounded-lg text-sm font-medium text-zinc-300 transition",
34+
"hover:text-white hover:bg-white/5",
35+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white/40",
36+
isActive ? "text-white bg-white/10" : "",
37+
].join(" ")
38+
}
39+
to="/users"
40+
>
41+
Users
42+
</NavLink>
43+
</div>
44+
</nav>
45+
</header>
46+
);
47+
};
48+
export default TopNav;

frontend/js/components/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import TopNav from "./TopNav";
2+
3+
export { TopNav };

frontend/js/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { createRoot } from "react-dom/client";
44

55
import App from "./App";
66

7-
import "../css/style.css";
7+
import "@/css/style.css";
88

99
Sentry.init({
1010
dsn: window.SENTRY_DSN,

frontend/js/loaders/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from "./users";

frontend/js/loaders/users.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { redirectDocument } from "react-router";
2+
3+
import { ApiError, UsersService } from "@/js/api";
4+
5+
export async function usersLoader({ request }: { request: Request }) {
6+
const url = new URL(request.url);
7+
const limit = Number(url.searchParams.get("limit") || 10);
8+
const offset = Number(url.searchParams.get("offset") || 0);
9+
try {
10+
return await UsersService.usersList({ limit, offset });
11+
} catch (error) {
12+
if (
13+
error instanceof ApiError &&
14+
(error?.status === 401 || error?.status === 403)
15+
) {
16+
const url = new URL(request.url);
17+
const next = url.pathname + url.search + url.hash;
18+
throw redirectDocument(`/admin/login/?next=${encodeURIComponent(next)}`);
19+
}
20+
throw error;
21+
}
22+
}

0 commit comments

Comments
 (0)