Skip to content

Commit

Permalink
Add-react-router-to-web-app (#227)
Browse files Browse the repository at this point in the history
  • Loading branch information
tjementum authored Nov 22, 2023
2 parents 7395b2f + 43a0bf9 commit 98ebf00
Show file tree
Hide file tree
Showing 19 changed files with 227 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "development",
"PUBLIC_URL": "https://localhost:8443",
"CDN_URL": "http://localhost:8080"
"CDN_URL": "https://localhost:8080"
},
"applicationUrl": "https://localhost:8443"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,13 @@ public async Task CustomExceptionHandling_WhenThrowingException_ShouldHandleExce
builder.UseSetting(WebHostDefaults.EnvironmentKey, environment);
builder.ConfigureAppConfiguration((_, _) =>
{
// Set the environment variable to enable the test-specific /throwException endpoint.
// Set the environment variable to enable the test-specific /api/throwException endpoint.
Environment.SetEnvironmentVariable("TestEndpointsEnabled", "true");
});
}).CreateClient();

// Act
var response = await client.GetAsync("/throwException");
var response = await client.GetAsync("/api/throwException");

// Assert
if (environment == "Development")
Expand Down
Binary file modified application/account-management/WebApp/bun.lockb
Binary file not shown.
3 changes: 3 additions & 0 deletions application/account-management/WebApp/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,14 @@
"react": "18.3.0-canary-c47c306a7-20231109",
"react-aria-components": "^1.0.0-rc.0",
"react-dom": "18.3.0-canary-c47c306a7-20231109",
"react-dom-confetti": "^0.2.0",
"react-router-dom": "^6.19.0",
"zod": "^3.22.4"
},
"devDependencies": {
"@rspack/cli": "^0.3.11",
"@rspack/core": "^0.3.11",
"@svgr/webpack": "^8.1.0",
"@types/react": "18.2.36",
"@types/react-dom": "18.2.13",
"autoprefixer": "^10.4.16",
Expand Down
44 changes: 42 additions & 2 deletions application/account-management/WebApp/rspack.config.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { resolve } from "path";
import os from "os";
import { join, resolve } from "path";
import { Configuration, DefinePlugin } from "@rspack/core";
import HtmlWebpackPlugin from "html-webpack-plugin";
import HtmlWebpackHarddiskPlugin from "html-webpack-harddisk-plugin";
Expand All @@ -13,6 +14,7 @@ const configuration: Configuration = {
main: ["./src/lib/rspack/runtime.ts", "./src/main.tsx"],
},
output: {
publicPath: "auto",
path: outputPath,
filename: process.env.NODE_ENV === "production" ? "[name].[contenthash].bundle.js" : undefined,
},
Expand All @@ -22,8 +24,33 @@ const configuration: Configuration = {
module: {
rules: [
{
test: /\.svg$/,
test: /\.svg$/i,
type: "asset",
resourceQuery: /url/, // *.svg?url
},
{
test: /\.svg$/i,
issuer: /\.tsx?$/,
resourceQuery: "", // exclude react component if *.svg?url
use: [
{
loader: "@svgr/webpack",
options: {
svgoConfig: {
plugins: [
{
name: "preset-default",
params: {
overrides: {
removeViewBox: false,
},
},
},
],
},
},
},
],
},
{
test: /\.css$/,
Expand Down Expand Up @@ -63,6 +90,19 @@ const configuration: Configuration = {
outputPath,
}),
],
devServer: {
allowedHosts: "all",
headers: {
"Access-Control-Allow-Origin": "*",
},
server: {
type: "https",
options: {
pfx: join(os.homedir(), ".aspnet", "https", "localhost.pfx"),
passphrase: process.env.CERTIFICATE_PASSWORD,
},
},
},
};

export default configuration;
8 changes: 5 additions & 3 deletions application/account-management/WebApp/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { CreateTenantForm } from "@/ui/tenant/CreateTenantForm.tsx";

function App() {
return <CreateTenantForm />;
return (
<div className="App">
<h1>Account Management</h1>
</div>
);
}

export default App;
18 changes: 18 additions & 0 deletions application/account-management/WebApp/src/error-page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { useRouteError } from "react-router-dom";

type ErrorObject = { statusText?: string; message?: string };
export default function ErrorPage() {
const error = useRouteError() as ErrorObject;

console.error(error);

return (
<div className="flex flex-col justify-center items-center w-full">
<h1>Oops!</h1>
<p>Sorry, an unexpected error has occurred.</p>
<p>
<i>{error.statusText || error.message}</i>
</p>
</div>
);
}
10 changes: 10 additions & 0 deletions application/account-management/WebApp/src/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -77,3 +77,13 @@
@apply bg-background text-foreground;
}
}

@layer base {
html,
body,
#root {
height: 100%;
margin: 0;
padding: 0;
}
}
5 changes: 3 additions & 2 deletions application/account-management/WebApp/src/main.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
import { RouterProvider } from "react-router-dom";
import "./main.css";
import { router } from "./router";

ReactDOM.createRoot(document.getElementById("root")!).render(
<React.StrictMode>
<App />
<RouterProvider router={router} />
</React.StrictMode>
);
5 changes: 4 additions & 1 deletion application/account-management/WebApp/src/react-env.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,12 @@ declare module "*.jpg" {
}
declare module "*.svg" {
const ReactComponent: React.FC<React.SVGProps<SVGSVGElement>>;

export default ReactComponent;
}
declare module "*.svg?url" {
const content: string;

export { ReactComponent };
export default content;
}
declare module "*.ico" {
Expand Down
27 changes: 27 additions & 0 deletions application/account-management/WebApp/src/router.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { createBrowserRouter } from "react-router-dom";
import Root from "@/routes/root.tsx";
import ErrorPage from "@/error-page.tsx";
import { CreateTenantForm } from "./ui/tenant/CreateTenantForm";
import { CreatedTenantSuccess } from "./ui/tenant/CreatedTenantSuccess";

export const router = createBrowserRouter([
{
path: "/",
element: <Root />,
errorElement: <ErrorPage />,
children: [
{
path: "/tenant/:id",
element: <h1>Tenant</h1>,
},
{
path: "/tenant/create",
element: <CreateTenantForm />,
},
{
path: "/tenant/create/success",
element: <CreatedTenantSuccess />,
},
],
},
]);
39 changes: 39 additions & 0 deletions application/account-management/WebApp/src/routes/root.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { Outlet, useNavigate } from "react-router-dom";
import AcmeLogo from "@/ui/acme-logo.svg";
import { Button } from "react-aria-components";

export default function Root() {
const navigate = useNavigate();

function handleCreateTenant() {
navigate("/tenant/create");
}

return (
<div className="flex flex-row h-full w-full">
<div className="flex gap-2 flex-col h-full w-80 border-r border-border bg-gray-100 px-6">
<h1 className="flex gap-1 items-center order-1 border-t border-border px-4 py-8">
<AcmeLogo className="w-6 h-6" /> ACME Company
</h1>
<div className="justify-start flex flex-row border-b border-border py-4">
<Button className="bg-blue-600 text-white py-2 px-4 rounded-full" onPress={handleCreateTenant}>
Create Tenant
</Button>
</div>
<nav className="grow">
<ul>
<li className="p-4 hover:bg-gray-200 rounded-xl cursor-pointer">
<a href={`/`}>Account Management</a>
</li>
<li className="p-4 hover:bg-gray-200 rounded-xl cursor-pointer">
<a href={`/user-management`}>User Management</a>
</li>
</ul>
</nav>
</div>
<div className="flex flex-col w-full h-full bg-background">
<Outlet />
</div>
</div>
);
}
22 changes: 22 additions & 0 deletions application/account-management/WebApp/src/ui/acme-logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ export function CreateTenantForm() {
<Form
action={formAction}
validationErrors={state.errors}
className="w-screen h-screen bg-slate-900 flex flex-col p-2 justify-center items-center"
className="w-full h-full flex flex-col p-2 justify-center items-center border-border border"
>
<div className="flex flex-col w-fit bg-slate-300 rounded-sm p-4 gap-2">
<div className="flex flex-col w-fit bg-gray-200 rounded p-4 gap-2 shadow-sm">
<h1 className="text-xl font-bold">Create a tenant</h1>
<TextField name={"subdomain"} autoFocus className={"flex flex-col"} isRequired>
<Label>Subdomain</Label>
Expand All @@ -31,10 +31,9 @@ export function CreateTenantForm() {
<Input className="p-2 rounded-md border border-black" placeholder="email" />
<FieldError />
</TextField>

<Button
type="submit"
className="bg-slate-500 p-2 rounded-md text-white text-sm border border-black hover:bg-slate-400 w-fit"
className="bg-blue-600 p-2 rounded-md text-white text-sm border border-border shadow-lg hover:bg-slate-400 w-fit"
>
Create tenant!
</Button>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { useEffect, useState } from "react";
import { Button } from "react-aria-components";
import Confetti, { type ConfettiConfig } from "react-dom-confetti";

const config: ConfettiConfig = {
angle: 90,
spread: 360,
startVelocity: 28,
elementCount: 170,
dragFriction: 0.12,
duration: 3000,
stagger: 3,
width: "10px",
height: "10px",
//perspective: "500px",
colors: ["#a864fd", "#29cdff", "#78ff44", "#ff718d", "#fdff6a"],
};

export function CreatedTenantSuccess() {
const [confetti, setConfetti] = useState(false);

useEffect(() => {
setConfetti(true);
}, []);

return (
<div className="items-center flex flex-col justify-center h-full">
<div className="p-8 bg-gray-800 text-white rounded-xl shadow-md text-center gap-4 flex flex-col">
<h1 className="text-2xl">Success!</h1>
<p>Your tenant has been created.</p>
<div className="self-center absolute top-10">
<Confetti active={confetti} config={config} />
</div>
</div>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { z } from "zod";
import { accountManagementApi } from "@/lib/api/client.ts";
import { getApiError, getFieldErrors } from "@/lib/apiErrorListSchema.ts";
import { router } from "@/router";

export type State = {
errors?: {
Expand Down Expand Up @@ -46,6 +47,7 @@ export async function createTenant(_: State, formData: FormData): Promise<State>
if (result.response.ok) {
// invalidate cache
// redirect
router.navigate("/tenant/create/success");
return {};
}

Expand Down
2 changes: 1 addition & 1 deletion application/shared-kernel/ApiCore/ApiCoreConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ public static WebApplication AddApiCoreConfiguration<TDbContext>(this WebApplica

app.UseMiddleware<ModelBindingExceptionHandlerMiddleware>();

// Add test-specific endpoints when running tests, such as /throwException.
// Add test-specific endpoints when running tests, such as /api/throwException.
app.MapTestEndpoints();

app.Services.ApplyMigrations<TDbContext>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,6 @@ public static void MapTestEndpoints(this IEndpointRouteBuilder routes)
if (!bool.TryParse(Environment.GetEnvironmentVariable("TestEndpointsEnabled"), out _)) return;

// Add a dummy endpoint that throws an InvalidOperationException for testing purposes.
routes.MapGet("/throwException", _ => throw new InvalidOperationException("Dummy endpoint for testing."));
routes.MapGet("/api/throwException", _ => throw new InvalidOperationException("Dummy endpoint for testing."));
}
}
Loading

0 comments on commit 98ebf00

Please sign in to comment.