Skip to content

Commit

Permalink
Final FE setup
Browse files Browse the repository at this point in the history
  • Loading branch information
Tomas-Juri committed Jan 20, 2024
1 parent 4ab94e3 commit 396c4ff
Show file tree
Hide file tree
Showing 15 changed files with 287 additions and 18 deletions.
11 changes: 1 addition & 10 deletions 2024/Backend/Api/WeatherForecastController.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
using Application.Backend.Database;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

namespace Application.Backend.Api;

[ApiController]
[Route("[controller]")]
[Route("/weather-forecast")]
public class WeatherForecastController(DataContext dataContext) : ControllerBase
{
[HttpGet]
Expand All @@ -14,12 +13,4 @@ public IActionResult Get()
var weatherForecasts = dataContext.WeatherForecasts.ToList();
return Ok(weatherForecasts);
}

[HttpGet("/authorized")]
[Authorize]
public IActionResult GetAuthorized()
{
var weatherForecasts = dataContext.WeatherForecasts.ToList();
return Ok(weatherForecasts);
}
}
35 changes: 32 additions & 3 deletions 2024/Frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions 2024/Frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"@types/node": "^20.11.5",
"@types/react": "^18.2.48",
"@types/react-dom": "^18.2.18",
"axios": "^1.6.5",
"bootstrap": "^5.3.2",
"react": "^18.2.0",
"react-bootstrap": "^2.10.0",
Expand Down
12 changes: 10 additions & 2 deletions 2024/Frontend/src/Application.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
import React from 'react';
import "bootstrap/dist/css/bootstrap.min.css";
import { Routes, Route } from "react-router-dom";
import { HomePage, CounterPage, FetchDataPage } from "./components/pages";

export const Application = () => <main> Hello world</main>
export const Application = () => (
<Routes>
<Route index element={<HomePage />} />
<Route path="/counter" element={<CounterPage />} />
<Route path="/fetch-data" element={<FetchDataPage />} />
</Routes>
);
5 changes: 5 additions & 0 deletions 2024/Frontend/src/api/endpoints.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export const Endpoints = {
WeatherForecast: {
Index: '/weather-forecast'
}
}
67 changes: 66 additions & 1 deletion 2024/Frontend/src/api/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,70 @@
import axios, { AxiosError, AxiosInstance } from "axios";

const target = process.env.ASPNETCORE_HTTPS_PORT
? `https://localhost:${process.env.ASPNETCORE_HTTPS_PORT}`
: process.env.ASPNETCORE_URLS
? process.env.ASPNETCORE_URLS.split(";")[0]
: "http://localhost:48711";
: "https://localhost:7101/";

export function api(): AxiosInstance {
const headers: { [key: string]: string } = {
"Content-Type": "application/json",
};

const token = localStorage.getItem("token");
if (token) {
headers.Authorization = `Bearer ${token}`;
}

const instance = axios.create({
baseURL: target,
headers,
});

instance.interceptors.response.use(
(response) => {
handleDates(response.data);

if (isIsoDateString(response.data))
response.data = new Date(response.data);

return response;
},
(error: AxiosError) => {
const { response } = error || { response: null, config: {} };
const { status } = response || { status: null };

console.error("error:", { error, response });

if (status === 401) {
// TODO handle unauthorized
}

return Promise.reject(error);
}
);
instance.interceptors.request.use((request) => {
// console.info(request);

return request;
});

return instance;
}

const isoDateFormat = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d*)?$/;

function isIsoDateString(value: any): boolean {
return value && typeof value === "string" && isoDateFormat.test(value);
}

export function handleDates(body: any) {
if (body === null || body === undefined || typeof body !== "object")
return body;

for (const key of Object.keys(body)) {
const value = body[key];
if (isIsoDateString(value)) body[key] = new Date(value);
else if (typeof value === "object") handleDates(value);
}
}
29 changes: 29 additions & 0 deletions 2024/Frontend/src/components/organisms/Layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { ReactNode } from "react";
import Container from "react-bootstrap/Container";
import Nav from 'react-bootstrap/Nav';
import Navbar from 'react-bootstrap/Navbar';
import { Link } from "react-router-dom";

type Props = {
children: ReactNode;
};

export const Layout = ({ children }: Props) => (
<>
<Navbar expand="lg" className="mb-4 border-bottom box-shadow">
<Container>
<Navbar.Brand href="#home">Application</Navbar.Brand>
<Navbar.Toggle aria-controls="basic-navbar-nav" />
<Navbar.Collapse id="basic-navbar-nav">
<Nav className="me-auto">
<Nav.Link as={Link} to="/">Home</Nav.Link>
<Nav.Link as={Link} to="/counter">Counter</Nav.Link>
<Nav.Link as={Link} to="/fetch-data">Fetch Data</Nav.Link>
</Nav>
</Navbar.Collapse>
</Container>
</Navbar>
<Container as="main">{children}</Container>
<footer></footer>
</>
);
1 change: 1 addition & 0 deletions 2024/Frontend/src/components/organisms/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { Layout } from "./Layout";
18 changes: 18 additions & 0 deletions 2024/Frontend/src/components/pages/CounterPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { useState } from "react";
import { Layout } from "../organisms";
import Button from "react-bootstrap/Button";
import Alert from "react-bootstrap/Alert";

export const CounterPage = () => {
const [count, setCount] = useState(0);

return (
<Layout>
<h1>Counter example!</h1>
<Alert>Count is {count}</Alert>
<Button variant="primary" onClick={() => setCount(count + 1)}>
Click me
</Button>
</Layout>
);
};
46 changes: 46 additions & 0 deletions 2024/Frontend/src/components/pages/FetchDataPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { useEffect, useState } from "react";
import { Layout } from "../organisms";
import { api } from "../../api";
import { Endpoints } from "../../api/endpoints";
import Table from 'react-bootstrap/Table';

type WeatherForecast = {
id: string;
date: Date;
temperatureC: number;
summary: string;
};

export const FetchDataPage = () => {
const [data, setData] = useState<WeatherForecast[]>([]);

useEffect(() => {
api()
.get<WeatherForecast[]>(Endpoints.WeatherForecast.Index)
.then((response) => setData(response.data));
}, []);

return (
<Layout>
<h1>Fetch data example!</h1>
<Table striped bordered hover className="mt-4">
<thead>
<tr>
<th>Id</th>
<th>Date</th>
<th>Temperature</th>
<th>Summary</th>
</tr>
</thead>
<tbody>
{data.map(forecast => <tr>
<td>{forecast.id}</td>
<td>{forecast.date.toLocaleString('cs')}</td>
<td>{forecast.temperatureC}°C</td>
<td>{forecast.summary}</td>
</tr>)}
</tbody>
</Table>
</Layout>
);
};
47 changes: 47 additions & 0 deletions 2024/Frontend/src/components/pages/HomePage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { Layout } from "../organisms";

export const HomePage = () => (
<Layout>
<h1>Hello, world!</h1>
<p>Welcome to your new single-page application, built with:</p>
<ul>
<li>
<a href="https://get.asp.net/">ASP.NET Core</a> and{" "}
<a href="https://msdn.microsoft.com/en-us/library/67ef8sbd.aspx">C#</a>{" "}
for cross-platform server-side code
</li>
<li>
<a href="https://facebook.github.io/react/">React</a> for client-side
code
</li>
<li>
<a href="http://getbootstrap.com/">Bootstrap</a> for layout and styling
</li>
</ul>
<p>To help you get started, we have also set up:</p>
<ul>
<li>
<strong>Client-side navigation</strong>. For example, click{" "}
<em>Counter</em> then <em>Back</em> to return here.
</li>
<li>
<strong>Development server integration</strong>. In development mode,
the development server from <code>create-react-app</code> runs in the
background automatically, so your client-side resources are dynamically
built on demand and the page refreshes when you modify any file.
</li>
<li>
<strong>Efficient production builds</strong>. In production mode,
development-time features are disabled, and your{" "}
<code>dotnet publish</code> configuration produces minified, efficiently
bundled JavaScript files.
</li>
</ul>
<p>
The <code>Frontend</code> subdirectory is a standard React application
based on the <code>create-react-app</code> template. If you open a command
prompt in that directory, you can run <code>npm</code> commands such as{" "}
<code>npm test</code> or <code>npm install</code>.
</p>
</Layout>
);
3 changes: 3 additions & 0 deletions 2024/Frontend/src/components/pages/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export { HomePage } from "./HomePage";
export { FetchDataPage } from "./FetchDataPage";
export { CounterPage } from "./CounterPage";
3 changes: 1 addition & 2 deletions 2024/Frontend/src/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import React from "react";
import { createRoot } from "react-dom/client";
import { BrowserRouter } from "react-router-dom";
import { Application } from "./Application.tsx";
import { Application } from "./Application";

const baseUrl =
document.getElementsByTagName("base")[0].getAttribute("href") ?? "";
Expand Down
19 changes: 19 additions & 0 deletions 2024/Frontend/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"compilerOptions": {
"target": "es5",
"lib": ["dom", "dom.iterable", "esnext", "webworker"],
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noFallthroughCasesInSwitch": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"noEmit": true,
"jsx": "react-jsx"
},
"include": ["src"]
}
8 changes: 8 additions & 0 deletions 2024/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,13 @@
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

// Add Cors
builder.Services.AddCors(options =>
options.AddDefaultPolicy(policy => policy
.AllowAnyHeader()
.AllowAnyMethod()
.AllowAnyOrigin()));

// Add Database
builder.Services
.AddDbContext<DataContext>(options => options
Expand Down Expand Up @@ -47,6 +54,7 @@
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors();

// TODO Use Auth

Expand Down

0 comments on commit 396c4ff

Please sign in to comment.