From 2f3ebd19eecbd634fe109b8c7c53cee8001335d9 Mon Sep 17 00:00:00 2001 From: jmayer913 <72579603+jmayer913@users.noreply.github.com> Date: Mon, 23 Sep 2024 10:40:24 -0400 Subject: [PATCH 01/43] Removed Template Weather --- .../Controllers/WeatherForecastController.cs | 33 --------- .../JMayer.Example.ASPReact.Server.csproj | 4 ++ .../WeatherForecast.cs | 13 ---- jmayer.example.aspreact.client/src/App.jsx | 71 ++++++++++--------- 4 files changed, 40 insertions(+), 81 deletions(-) delete mode 100644 JMayer.Example.ASPReact.Server/Controllers/WeatherForecastController.cs delete mode 100644 JMayer.Example.ASPReact.Server/WeatherForecast.cs diff --git a/JMayer.Example.ASPReact.Server/Controllers/WeatherForecastController.cs b/JMayer.Example.ASPReact.Server/Controllers/WeatherForecastController.cs deleted file mode 100644 index 61940ba..0000000 --- a/JMayer.Example.ASPReact.Server/Controllers/WeatherForecastController.cs +++ /dev/null @@ -1,33 +0,0 @@ -using Microsoft.AspNetCore.Mvc; - -namespace JMayer.Example.ASPReact.Server.Controllers -{ - [ApiController] - [Route("[controller]")] - public class WeatherForecastController : ControllerBase - { - private static readonly string[] Summaries = new[] - { - "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" - }; - - private readonly ILogger _logger; - - public WeatherForecastController(ILogger logger) - { - _logger = logger; - } - - [HttpGet(Name = "GetWeatherForecast")] - public IEnumerable Get() - { - return Enumerable.Range(1, 5).Select(index => new WeatherForecast - { - Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)), - TemperatureC = Random.Shared.Next(-20, 55), - Summary = Summaries[Random.Shared.Next(Summaries.Length)] - }) - .ToArray(); - } - } -} diff --git a/JMayer.Example.ASPReact.Server/JMayer.Example.ASPReact.Server.csproj b/JMayer.Example.ASPReact.Server/JMayer.Example.ASPReact.Server.csproj index c6e40ec..105f408 100644 --- a/JMayer.Example.ASPReact.Server/JMayer.Example.ASPReact.Server.csproj +++ b/JMayer.Example.ASPReact.Server/JMayer.Example.ASPReact.Server.csproj @@ -22,4 +22,8 @@ + + + + diff --git a/JMayer.Example.ASPReact.Server/WeatherForecast.cs b/JMayer.Example.ASPReact.Server/WeatherForecast.cs deleted file mode 100644 index 9beaf1b..0000000 --- a/JMayer.Example.ASPReact.Server/WeatherForecast.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace JMayer.Example.ASPReact.Server -{ - public class WeatherForecast - { - public DateOnly Date { get; set; } - - public int TemperatureC { get; set; } - - public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); - - public string? Summary { get; set; } - } -} diff --git a/jmayer.example.aspreact.client/src/App.jsx b/jmayer.example.aspreact.client/src/App.jsx index 1722511..897b798 100644 --- a/jmayer.example.aspreact.client/src/App.jsx +++ b/jmayer.example.aspreact.client/src/App.jsx @@ -2,51 +2,52 @@ import { useEffect, useState } from 'react'; import './App.css'; function App() { - const [forecasts, setForecasts] = useState(); + //const [forecasts, setForecasts] = useState(); - useEffect(() => { - populateWeatherData(); - }, []); + //useEffect(() => { + // populateWeatherData(); + //}, []); - const contents = forecasts === undefined - ?

Loading... Please refresh once the ASP.NET backend has started. See https://aka.ms/jspsintegrationreact for more details.

- : - - - - - - - - - - {forecasts.map(forecast => - - - - - - - )} - -
DateTemp. (C)Temp. (F)Summary
{forecast.date}{forecast.temperatureC}{forecast.temperatureF}{forecast.summary}
; + //const contents = forecasts === undefined + // ?

Loading... Please refresh once the ASP.NET backend has started. See https://aka.ms/jspsintegrationreact for more details.

+ // : + // + // + // + // + // + // + // + // + // + // {forecasts.map(forecast => + // + // + // + // + // + // + // )} + // + //
DateTemp. (C)Temp. (F)Summary
{forecast.date}{forecast.temperatureC}{forecast.temperatureF}{forecast.summary}
; + + const contents =

Under Construction

; return (
-

Weather forecast

-

This component demonstrates fetching data from the server.

+

Example Project

{contents}
); - async function populateWeatherData() { - const response = await fetch('weatherforecast'); + //async function populateWeatherData() { + // const response = await fetch('weatherforecast'); - if (response.ok) { - const data = await response.json(); - setForecasts(data); - } - } + // if (response.ok) { + // const data = await response.json(); + // setForecasts(data); + // } + //} } export default App; \ No newline at end of file From baeadc946ac8fc2b4e552a90828ab09a9543b47e Mon Sep 17 00:00:00 2001 From: jmayer913 <72579603+jmayer913@users.noreply.github.com> Date: Mon, 23 Sep 2024 11:59:37 -0400 Subject: [PATCH 02/43] Added PrimeReact --- jmayer.example.aspreact.client/index.html | 6 +- .../package-lock.json | 90 +++++++++++++++++-- jmayer.example.aspreact.client/package.json | 2 + jmayer.example.aspreact.client/src/App.jsx | 14 ++- jmayer.example.aspreact.client/src/index.css | 20 ++--- jmayer.example.aspreact.client/src/main.jsx | 5 +- 6 files changed, 116 insertions(+), 21 deletions(-) diff --git a/jmayer.example.aspreact.client/index.html b/jmayer.example.aspreact.client/index.html index 0c589ec..2c95d84 100644 --- a/jmayer.example.aspreact.client/index.html +++ b/jmayer.example.aspreact.client/index.html @@ -1,11 +1,11 @@ - + - Vite + React - + +
diff --git a/jmayer.example.aspreact.client/package-lock.json b/jmayer.example.aspreact.client/package-lock.json index c7cfed6..922d1d8 100644 --- a/jmayer.example.aspreact.client/package-lock.json +++ b/jmayer.example.aspreact.client/package-lock.json @@ -8,6 +8,8 @@ "name": "jmayer.example.aspreact.client", "version": "0.0.0", "dependencies": { + "primeflex": "^3.3.1", + "primereact": "^10.8.3", "react": "^18.3.1", "react-dom": "^18.3.1" }, @@ -291,6 +293,18 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/runtime": { + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.6.tgz", + "integrity": "sha512-VBj9MYyDb9tuLq7yzqjgzt6Q+IBQLrGZfdjOekyEirZPHxXWoTSGUTMrpsfi58Up73d13NfYLv8HT9vmznjzhQ==", + "license": "MIT", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/template": { "version": "7.25.0", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.0.tgz", @@ -1264,14 +1278,12 @@ "version": "15.7.13", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.13.tgz", "integrity": "sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA==", - "dev": true, "license": "MIT" }, "node_modules/@types/react": { "version": "18.3.8", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.8.tgz", "integrity": "sha512-syBUrW3/XpnW4WJ41Pft+I+aPoDVbrBVQGEnbD7NijDGlVC+8gV/XKRY+7vMDlfPpbwYt0l1vd/Sj8bJGMbs9Q==", - "dev": true, "license": "MIT", "dependencies": { "@types/prop-types": "*", @@ -1288,6 +1300,15 @@ "@types/react": "*" } }, + "node_modules/@types/react-transition-group": { + "version": "4.4.11", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.11.tgz", + "integrity": "sha512-RM05tAniPZ5DZPzzNFP+DmrcOdD0efDUxMy3145oljWSl3x9ZV5vhme98gTxFrj2lhXvmGNnUiuDyJgY9IKkNA==", + "license": "MIT", + "dependencies": { + "@types/react": "*" + } + }, "node_modules/@vitejs/plugin-react": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.3.1.tgz", @@ -1698,7 +1719,6 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", - "dev": true, "license": "MIT" }, "node_modules/data-view-buffer": { @@ -1829,6 +1849,16 @@ "node": ">=0.10.0" } }, + "node_modules/dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, "node_modules/electron-to-chromium": { "version": "1.5.27", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.27.tgz", @@ -3351,7 +3381,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" @@ -3597,11 +3626,39 @@ "node": ">= 0.8.0" } }, + "node_modules/primeflex": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/primeflex/-/primeflex-3.3.1.tgz", + "integrity": "sha512-zaOq3YvcOYytbAmKv3zYc+0VNS9Wg5d37dfxZnveKBFPr7vEIwfV5ydrpiouTft8MVW6qNjfkaQphHSnvgQbpQ==", + "license": "MIT" + }, + "node_modules/primereact": { + "version": "10.8.3", + "resolved": "https://registry.npmjs.org/primereact/-/primereact-10.8.3.tgz", + "integrity": "sha512-LYa7DL1TDmWWrPCeh3CMsx89LXgcf4+rYhJ6YiA7z164WsdzJK388Bp1Qdv5cfpyL/Nm0eIWxIApxwWBv8kwuA==", + "license": "MIT", + "dependencies": { + "@types/react-transition-group": "^4.4.1", + "react-transition-group": "^4.4.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/prop-types": { "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "dev": true, "license": "MIT", "dependencies": { "loose-envify": "^1.4.0", @@ -3669,7 +3726,6 @@ "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "dev": true, "license": "MIT" }, "node_modules/react-refresh": { @@ -3682,6 +3738,22 @@ "node": ">=0.10.0" } }, + "node_modules/react-transition-group": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", + "license": "BSD-3-Clause", + "dependencies": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": ">=16.6.0", + "react-dom": ">=16.6.0" + } + }, "node_modules/reflect.getprototypeof": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz", @@ -3704,6 +3776,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", + "license": "MIT" + }, "node_modules/regexp.prototype.flags": { "version": "1.5.2", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", diff --git a/jmayer.example.aspreact.client/package.json b/jmayer.example.aspreact.client/package.json index 8058989..2ea5032 100644 --- a/jmayer.example.aspreact.client/package.json +++ b/jmayer.example.aspreact.client/package.json @@ -10,6 +10,8 @@ "preview": "vite preview" }, "dependencies": { + "primeflex": "^3.3.1", + "primereact": "^10.8.3", "react": "^18.3.1", "react-dom": "^18.3.1" }, diff --git a/jmayer.example.aspreact.client/src/App.jsx b/jmayer.example.aspreact.client/src/App.jsx index 897b798..49bfa11 100644 --- a/jmayer.example.aspreact.client/src/App.jsx +++ b/jmayer.example.aspreact.client/src/App.jsx @@ -1,4 +1,7 @@ -import { useEffect, useState } from 'react'; +//import { useEffect, useState } from 'react'; +import { Button } from 'primereact/button'; +import 'primereact/resources/themes/lara-light-indigo/theme.css'; +import 'primeflex/primeflex.css'; import './App.css'; function App() { @@ -37,6 +40,15 @@ function App() {

Example Project

{contents} +
+
); diff --git a/jmayer.example.aspreact.client/src/index.css b/jmayer.example.aspreact.client/src/index.css index 6119ad9..6ad246c 100644 --- a/jmayer.example.aspreact.client/src/index.css +++ b/jmayer.example.aspreact.client/src/index.css @@ -1,4 +1,4 @@ -:root { +/*:root { font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; line-height: 1.5; font-weight: 400; @@ -11,16 +11,16 @@ text-rendering: optimizeLegibility; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; -} +}*/ -a { +/*a { font-weight: 500; color: #646cff; text-decoration: inherit; } a:hover { color: #535bf2; -} +}*/ body { margin: 0; @@ -30,12 +30,12 @@ body { min-height: 100vh; } -h1 { +/*h1 { font-size: 3.2em; line-height: 1.1; -} +}*/ -button { +/*button { border-radius: 8px; border: 1px solid transparent; padding: 0.6em 1.2em; @@ -52,9 +52,9 @@ button:hover { button:focus, button:focus-visible { outline: 4px auto -webkit-focus-ring-color; -} +}*/ -@media (prefers-color-scheme: light) { +/*@media (prefers-color-scheme: light) { :root { color: #213547; background-color: #ffffff; @@ -65,4 +65,4 @@ button:focus-visible { button { background-color: #f9f9f9; } -} +}*/ diff --git a/jmayer.example.aspreact.client/src/main.jsx b/jmayer.example.aspreact.client/src/main.jsx index 89f91e5..c75437a 100644 --- a/jmayer.example.aspreact.client/src/main.jsx +++ b/jmayer.example.aspreact.client/src/main.jsx @@ -1,10 +1,13 @@ import { StrictMode } from 'react' import { createRoot } from 'react-dom/client' +import { PrimeReactProvider } from 'primereact/api' import App from './App.jsx' import './index.css' createRoot(document.getElementById('root')).render( - + + + , ) From 40a61a72f96fb347eb03157275ef96717bd73fa6 Mon Sep 17 00:00:00 2001 From: jmayer913 <72579603+jmayer913@users.noreply.github.com> Date: Tue, 1 Oct 2024 19:39:36 -0400 Subject: [PATCH 03/43] Added layout & home page --- .../package-lock.json | 7 ++ jmayer.example.aspreact.client/package.json | 1 + jmayer.example.aspreact.client/src/App.css | 4 +- jmayer.example.aspreact.client/src/App.jsx | 68 ++++--------------- .../src/home/Home.jsx | 7 ++ jmayer.example.aspreact.client/src/index.css | 4 +- .../src/layout/Header.jsx | 10 +++ .../src/layout/Menu.jsx | 17 +++++ 8 files changed, 59 insertions(+), 59 deletions(-) create mode 100644 jmayer.example.aspreact.client/src/home/Home.jsx create mode 100644 jmayer.example.aspreact.client/src/layout/Header.jsx create mode 100644 jmayer.example.aspreact.client/src/layout/Menu.jsx diff --git a/jmayer.example.aspreact.client/package-lock.json b/jmayer.example.aspreact.client/package-lock.json index 922d1d8..a6b1950 100644 --- a/jmayer.example.aspreact.client/package-lock.json +++ b/jmayer.example.aspreact.client/package-lock.json @@ -9,6 +9,7 @@ "version": "0.0.0", "dependencies": { "primeflex": "^3.3.1", + "primeicons": "^7.0.0", "primereact": "^10.8.3", "react": "^18.3.1", "react-dom": "^18.3.1" @@ -3632,6 +3633,12 @@ "integrity": "sha512-zaOq3YvcOYytbAmKv3zYc+0VNS9Wg5d37dfxZnveKBFPr7vEIwfV5ydrpiouTft8MVW6qNjfkaQphHSnvgQbpQ==", "license": "MIT" }, + "node_modules/primeicons": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/primeicons/-/primeicons-7.0.0.tgz", + "integrity": "sha512-jK3Et9UzwzTsd6tzl2RmwrVY/b8raJ3QZLzoDACj+oTJ0oX7L9Hy+XnVwgo4QVKlKpnP/Ur13SXV/pVh4LzaDw==", + "license": "MIT" + }, "node_modules/primereact": { "version": "10.8.3", "resolved": "https://registry.npmjs.org/primereact/-/primereact-10.8.3.tgz", diff --git a/jmayer.example.aspreact.client/package.json b/jmayer.example.aspreact.client/package.json index 2ea5032..870ea1d 100644 --- a/jmayer.example.aspreact.client/package.json +++ b/jmayer.example.aspreact.client/package.json @@ -11,6 +11,7 @@ }, "dependencies": { "primeflex": "^3.3.1", + "primeicons": "^7.0.0", "primereact": "^10.8.3", "react": "^18.3.1", "react-dom": "^18.3.1" diff --git a/jmayer.example.aspreact.client/src/App.css b/jmayer.example.aspreact.client/src/App.css index 32d0d22..1ed856a 100644 --- a/jmayer.example.aspreact.client/src/App.css +++ b/jmayer.example.aspreact.client/src/App.css @@ -1,4 +1,4 @@ -#root { +/*#root { max-width: 1280px; margin: 0 auto; padding: 2rem; @@ -8,4 +8,4 @@ th, td { padding-left: 1rem; padding-right: 1rem; -} \ No newline at end of file +}*/ \ No newline at end of file diff --git a/jmayer.example.aspreact.client/src/App.jsx b/jmayer.example.aspreact.client/src/App.jsx index 49bfa11..7918396 100644 --- a/jmayer.example.aspreact.client/src/App.jsx +++ b/jmayer.example.aspreact.client/src/App.jsx @@ -1,65 +1,23 @@ -//import { useEffect, useState } from 'react'; -import { Button } from 'primereact/button'; -import 'primereact/resources/themes/lara-light-indigo/theme.css'; +import { useState } from 'react'; +import Header from './layout/Header.jsx'; +import Menu from './layout/Menu.jsx'; +import Home from './home/Home.jsx'; +import 'primereact/resources/themes/lara-dark-indigo/theme.css'; import 'primeflex/primeflex.css'; +import 'primeicons/primeicons.css'; import './App.css'; function App() { - //const [forecasts, setForecasts] = useState(); - - //useEffect(() => { - // populateWeatherData(); - //}, []); - - //const contents = forecasts === undefined - // ?

Loading... Please refresh once the ASP.NET backend has started. See https://aka.ms/jspsintegrationreact for more details.

- // : - // - // - // - // - // - // - // - // - // - // {forecasts.map(forecast => - // - // - // - // - // - // - // )} - // - //
DateTemp. (C)Temp. (F)Summary
{forecast.date}{forecast.temperatureC}{forecast.temperatureF}{forecast.summary}
; - - const contents =

Under Construction

; + const [sideBarVisible, setSideBarVisible] = useState(false); + const [selectedScreen, setSelectedScreen] = useState('home'); return ( -
-

Example Project

- {contents} -
-
-
+ <> +
+ + {selectedScreen === 'home' && } + ); - - //async function populateWeatherData() { - // const response = await fetch('weatherforecast'); - - // if (response.ok) { - // const data = await response.json(); - // setForecasts(data); - // } - //} } export default App; \ No newline at end of file diff --git a/jmayer.example.aspreact.client/src/home/Home.jsx b/jmayer.example.aspreact.client/src/home/Home.jsx new file mode 100644 index 0000000..73abf9c --- /dev/null +++ b/jmayer.example.aspreact.client/src/home/Home.jsx @@ -0,0 +1,7 @@ +export default function Home() { + return ( + <> +

Under Construction

+ + ); +} \ No newline at end of file diff --git a/jmayer.example.aspreact.client/src/index.css b/jmayer.example.aspreact.client/src/index.css index 6ad246c..9123d3b 100644 --- a/jmayer.example.aspreact.client/src/index.css +++ b/jmayer.example.aspreact.client/src/index.css @@ -22,13 +22,13 @@ a:hover { color: #535bf2; }*/ -body { +/*body { margin: 0; display: flex; place-items: center; min-width: 320px; min-height: 100vh; -} +}*/ /*h1 { font-size: 3.2em; diff --git a/jmayer.example.aspreact.client/src/layout/Header.jsx b/jmayer.example.aspreact.client/src/layout/Header.jsx new file mode 100644 index 0000000..a10b996 --- /dev/null +++ b/jmayer.example.aspreact.client/src/layout/Header.jsx @@ -0,0 +1,10 @@ +import { Button } from 'primereact/button'; + +export default function Header({setSideBarVisible}) { + return ( +
+
+ ); +} \ No newline at end of file diff --git a/jmayer.example.aspreact.client/src/layout/Menu.jsx b/jmayer.example.aspreact.client/src/layout/Menu.jsx new file mode 100644 index 0000000..266ee25 --- /dev/null +++ b/jmayer.example.aspreact.client/src/layout/Menu.jsx @@ -0,0 +1,17 @@ +import { PanelMenu } from 'primereact/panelmenu'; +import { Sidebar } from 'primereact/sidebar'; + +export default function Menu({ sideBarVisible, setSideBarVisible, setSelectedScreen}) { + const menuItems = [ + { + label: 'Home', + command: () => setSelectedScreen('home'), + } + ]; + + return ( + setSideBarVisible(false)}> + + + ); +} \ No newline at end of file From f2d94a9a3047e5ada6467831192a95e534d6eb6e Mon Sep 17 00:00:00 2001 From: jmayer913 <72579603+jmayer913@users.noreply.github.com> Date: Wed, 2 Oct 2024 10:36:34 -0400 Subject: [PATCH 04/43] Moved components; added flight schedule component --- jmayer.example.aspreact.client/index.html | 2 +- jmayer.example.aspreact.client/src/App.jsx | 9 +++-- .../flightSchedule/FlightSchedule.jsx | 25 +++++++++++++ .../src/{ => components}/home/Home.jsx | 1 + .../src/{ => components}/layout/Header.jsx | 2 + .../src/components/layout/Menu.jsx | 37 +++++++++++++++++++ .../src/layout/Menu.jsx | 17 --------- 7 files changed, 72 insertions(+), 21 deletions(-) create mode 100644 jmayer.example.aspreact.client/src/components/flightSchedule/FlightSchedule.jsx rename jmayer.example.aspreact.client/src/{ => components}/home/Home.jsx (61%) rename jmayer.example.aspreact.client/src/{ => components}/layout/Header.jsx (74%) create mode 100644 jmayer.example.aspreact.client/src/components/layout/Menu.jsx delete mode 100644 jmayer.example.aspreact.client/src/layout/Menu.jsx diff --git a/jmayer.example.aspreact.client/index.html b/jmayer.example.aspreact.client/index.html index 2c95d84..67bba53 100644 --- a/jmayer.example.aspreact.client/index.html +++ b/jmayer.example.aspreact.client/index.html @@ -3,7 +3,7 @@ - Vite + React + ASP.NET Core / React Example diff --git a/jmayer.example.aspreact.client/src/App.jsx b/jmayer.example.aspreact.client/src/App.jsx index 7918396..d6d49c9 100644 --- a/jmayer.example.aspreact.client/src/App.jsx +++ b/jmayer.example.aspreact.client/src/App.jsx @@ -1,12 +1,14 @@ import { useState } from 'react'; -import Header from './layout/Header.jsx'; -import Menu from './layout/Menu.jsx'; -import Home from './home/Home.jsx'; +import FlightSchedule from './components/flightSchedule/FlightSchedule.jsx'; +import Home from './components/home/Home.jsx'; +import Header from './components/layout/Header.jsx'; +import Menu from './components/layout/Menu.jsx'; import 'primereact/resources/themes/lara-dark-indigo/theme.css'; import 'primeflex/primeflex.css'; import 'primeicons/primeicons.css'; import './App.css'; +//The main layout of the website & the currently selected screen. function App() { const [sideBarVisible, setSideBarVisible] = useState(false); const [selectedScreen, setSelectedScreen] = useState('home'); @@ -16,6 +18,7 @@ function App() {
{selectedScreen === 'home' && } + {selectedScreen === 'flight schedule' && } ); } diff --git a/jmayer.example.aspreact.client/src/components/flightSchedule/FlightSchedule.jsx b/jmayer.example.aspreact.client/src/components/flightSchedule/FlightSchedule.jsx new file mode 100644 index 0000000..0e2e4a3 --- /dev/null +++ b/jmayer.example.aspreact.client/src/components/flightSchedule/FlightSchedule.jsx @@ -0,0 +1,25 @@ +import { useState, useEffect } from 'react' +import { Card } from 'primereact/card'; +import { Column } from 'primereact/column'; +import { DataTable } from 'primereact/datatable'; + +//The flight schedule screen. Users can manage active flights. +export default function FlightSchedule() { + const [flights, setFlights] = useState([]); + + useEffect(() => { + //TO DO: Query Data on Server. + }, []); + + return ( + + + + + + + + + + ); +} \ No newline at end of file diff --git a/jmayer.example.aspreact.client/src/home/Home.jsx b/jmayer.example.aspreact.client/src/components/home/Home.jsx similarity index 61% rename from jmayer.example.aspreact.client/src/home/Home.jsx rename to jmayer.example.aspreact.client/src/components/home/Home.jsx index 73abf9c..3119559 100644 --- a/jmayer.example.aspreact.client/src/home/Home.jsx +++ b/jmayer.example.aspreact.client/src/components/home/Home.jsx @@ -1,3 +1,4 @@ +//The home screen. It displays a description about the example website. export default function Home() { return ( <> diff --git a/jmayer.example.aspreact.client/src/layout/Header.jsx b/jmayer.example.aspreact.client/src/components/layout/Header.jsx similarity index 74% rename from jmayer.example.aspreact.client/src/layout/Header.jsx rename to jmayer.example.aspreact.client/src/components/layout/Header.jsx index a10b996..2e51bd8 100644 --- a/jmayer.example.aspreact.client/src/layout/Header.jsx +++ b/jmayer.example.aspreact.client/src/components/layout/Header.jsx @@ -1,5 +1,7 @@ import { Button } from 'primereact/button'; +//The top header of the website. +//@param {function} props.setSideBarVisible Used by the component to show the sidebar menu. export default function Header({setSideBarVisible}) { return (
diff --git a/jmayer.example.aspreact.client/src/components/layout/Menu.jsx b/jmayer.example.aspreact.client/src/components/layout/Menu.jsx new file mode 100644 index 0000000..123495d --- /dev/null +++ b/jmayer.example.aspreact.client/src/components/layout/Menu.jsx @@ -0,0 +1,37 @@ +import { PanelMenu } from 'primereact/panelmenu'; +import { Sidebar } from 'primereact/sidebar'; + +//The sidebar menu of the website. +//@param {object} props The properties accepted by the component. +//@param {bool} props.sideBarVisible Used to control if the sidebar menu is visibile or not. +//@param {function} props.setSideBarVisible Used by the component to hide the sidebar menu. +//@param {function} props.setSelectedScreen Used by the component to set what screen is displayed in the App component. +export default function Menu({ sideBarVisible, setSideBarVisible, setSelectedScreen }) { + //Define the labels for the menu. + const homeLabel = 'Home'; + const flightScheduleLabel = 'Flight Schedule'; + + //Define the menus to display. + const menuItems = [ + { + label: homeLabel, + command: () => { + setSelectedScreen(homeLabel.toLowerCase()); + setSideBarVisible(false); + }, + }, + { + label: flightScheduleLabel, + command: () => { + setSelectedScreen(flightScheduleLabel.toLowerCase()); + setSideBarVisible(false); + }, + } + ]; + + return ( + setSideBarVisible(false)}> + + + ); +} \ No newline at end of file diff --git a/jmayer.example.aspreact.client/src/layout/Menu.jsx b/jmayer.example.aspreact.client/src/layout/Menu.jsx deleted file mode 100644 index 266ee25..0000000 --- a/jmayer.example.aspreact.client/src/layout/Menu.jsx +++ /dev/null @@ -1,17 +0,0 @@ -import { PanelMenu } from 'primereact/panelmenu'; -import { Sidebar } from 'primereact/sidebar'; - -export default function Menu({ sideBarVisible, setSideBarVisible, setSelectedScreen}) { - const menuItems = [ - { - label: 'Home', - command: () => setSelectedScreen('home'), - } - ]; - - return ( - setSideBarVisible(false)}> - - - ); -} \ No newline at end of file From 4d735efd4870ef941afe115c8db9a53ae67e1c41 Mon Sep 17 00:00:00 2001 From: jmayer913 <72579603+jmayer913@users.noreply.github.com> Date: Thu, 3 Oct 2024 09:49:18 -0400 Subject: [PATCH 05/43] Switched to router for navigation; renaming --- .../package-lock.json | 44 ++++++++++++++++++- jmayer.example.aspreact.client/package.json | 3 +- jmayer.example.aspreact.client/src/App.jsx | 20 ++++++--- ...ghtSchedule.jsx => FlightSchedulePage.jsx} | 4 +- .../src/components/home/Home.jsx | 8 ---- .../src/components/home/HomePage.jsx | 8 ++++ .../src/components/layout/Menu.jsx | 21 +++------ .../src/components/notFound/NotFoundPage.jsx | 6 +++ 8 files changed, 79 insertions(+), 35 deletions(-) rename jmayer.example.aspreact.client/src/components/flightSchedule/{FlightSchedule.jsx => FlightSchedulePage.jsx} (88%) delete mode 100644 jmayer.example.aspreact.client/src/components/home/Home.jsx create mode 100644 jmayer.example.aspreact.client/src/components/home/HomePage.jsx create mode 100644 jmayer.example.aspreact.client/src/components/notFound/NotFoundPage.jsx diff --git a/jmayer.example.aspreact.client/package-lock.json b/jmayer.example.aspreact.client/package-lock.json index a6b1950..ad57572 100644 --- a/jmayer.example.aspreact.client/package-lock.json +++ b/jmayer.example.aspreact.client/package-lock.json @@ -12,7 +12,8 @@ "primeicons": "^7.0.0", "primereact": "^10.8.3", "react": "^18.3.1", - "react-dom": "^18.3.1" + "react-dom": "^18.3.1", + "react-router-dom": "^6.26.2" }, "devDependencies": { "@eslint/js": "^9.9.0", @@ -999,6 +1000,15 @@ "node": ">= 8" } }, + "node_modules/@remix-run/router": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.19.2.tgz", + "integrity": "sha512-baiMx18+IMuD1yyvOGaHM9QrVUPGGG0jC+z+IPHnRJWUAUvaKuWKyE8gjDj2rzv3sz9zOGoRSPgeBVHRhZnBlA==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/@rollup/rollup-android-arm-eabi": { "version": "4.22.4", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.22.4.tgz", @@ -3745,6 +3755,38 @@ "node": ">=0.10.0" } }, + "node_modules/react-router": { + "version": "6.26.2", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.26.2.tgz", + "integrity": "sha512-tvN1iuT03kHgOFnLPfLJ8V95eijteveqdOSk+srqfePtQvqCExB8eHOYnlilbOcyJyKnYkr1vJvf7YqotAJu1A==", + "license": "MIT", + "dependencies": { + "@remix-run/router": "1.19.2" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/react-router-dom": { + "version": "6.26.2", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.26.2.tgz", + "integrity": "sha512-z7YkaEW0Dy35T3/QKPYB1LjMK2R1fxnHO8kWpUMTBdfVzZrWOiY9a7CtN8HqdWtDUWd5FY6Dl8HFsqVwH4uOtQ==", + "license": "MIT", + "dependencies": { + "@remix-run/router": "1.19.2", + "react-router": "6.26.2" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, "node_modules/react-transition-group": { "version": "4.4.5", "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", diff --git a/jmayer.example.aspreact.client/package.json b/jmayer.example.aspreact.client/package.json index 870ea1d..ff7e350 100644 --- a/jmayer.example.aspreact.client/package.json +++ b/jmayer.example.aspreact.client/package.json @@ -14,7 +14,8 @@ "primeicons": "^7.0.0", "primereact": "^10.8.3", "react": "^18.3.1", - "react-dom": "^18.3.1" + "react-dom": "^18.3.1", + "react-router-dom": "^6.26.2" }, "devDependencies": { "@eslint/js": "^9.9.0", diff --git a/jmayer.example.aspreact.client/src/App.jsx b/jmayer.example.aspreact.client/src/App.jsx index d6d49c9..c24908b 100644 --- a/jmayer.example.aspreact.client/src/App.jsx +++ b/jmayer.example.aspreact.client/src/App.jsx @@ -1,24 +1,30 @@ import { useState } from 'react'; -import FlightSchedule from './components/flightSchedule/FlightSchedule.jsx'; -import Home from './components/home/Home.jsx'; +import { BrowserRouter, Routes, Route } from 'react-router-dom'; +import FlightSchedulePage from './components/flightSchedule/FlightSchedulePage.jsx'; +import HomePage from './components/home/HomePage.jsx'; import Header from './components/layout/Header.jsx'; import Menu from './components/layout/Menu.jsx'; +import NotFoundPage from './components/NotFound/NotFoundPage.jsx'; import 'primereact/resources/themes/lara-dark-indigo/theme.css'; import 'primeflex/primeflex.css'; import 'primeicons/primeicons.css'; import './App.css'; -//The main layout of the website & the currently selected screen. +//The main layout of the website & the current page. function App() { const [sideBarVisible, setSideBarVisible] = useState(false); - const [selectedScreen, setSelectedScreen] = useState('home'); return ( <>
- - {selectedScreen === 'home' && } - {selectedScreen === 'flight schedule' && } + + + + } /> + } /> + } /> + + ); } diff --git a/jmayer.example.aspreact.client/src/components/flightSchedule/FlightSchedule.jsx b/jmayer.example.aspreact.client/src/components/flightSchedule/FlightSchedulePage.jsx similarity index 88% rename from jmayer.example.aspreact.client/src/components/flightSchedule/FlightSchedule.jsx rename to jmayer.example.aspreact.client/src/components/flightSchedule/FlightSchedulePage.jsx index 0e2e4a3..e40933e 100644 --- a/jmayer.example.aspreact.client/src/components/flightSchedule/FlightSchedule.jsx +++ b/jmayer.example.aspreact.client/src/components/flightSchedule/FlightSchedulePage.jsx @@ -3,8 +3,8 @@ import { Card } from 'primereact/card'; import { Column } from 'primereact/column'; import { DataTable } from 'primereact/datatable'; -//The flight schedule screen. Users can manage active flights. -export default function FlightSchedule() { +//The flight schedule page. Users can manage active flights. +export default function FlightSchedulePage() { const [flights, setFlights] = useState([]); useEffect(() => { diff --git a/jmayer.example.aspreact.client/src/components/home/Home.jsx b/jmayer.example.aspreact.client/src/components/home/Home.jsx deleted file mode 100644 index 3119559..0000000 --- a/jmayer.example.aspreact.client/src/components/home/Home.jsx +++ /dev/null @@ -1,8 +0,0 @@ -//The home screen. It displays a description about the example website. -export default function Home() { - return ( - <> -

Under Construction

- - ); -} \ No newline at end of file diff --git a/jmayer.example.aspreact.client/src/components/home/HomePage.jsx b/jmayer.example.aspreact.client/src/components/home/HomePage.jsx new file mode 100644 index 0000000..a1dfab2 --- /dev/null +++ b/jmayer.example.aspreact.client/src/components/home/HomePage.jsx @@ -0,0 +1,8 @@ +//The home page. It displays a description about the example website. +export default function HomePage() { + return ( + <> +

Under Construction

+ + ); +} \ No newline at end of file diff --git a/jmayer.example.aspreact.client/src/components/layout/Menu.jsx b/jmayer.example.aspreact.client/src/components/layout/Menu.jsx index 123495d..a9b5141 100644 --- a/jmayer.example.aspreact.client/src/components/layout/Menu.jsx +++ b/jmayer.example.aspreact.client/src/components/layout/Menu.jsx @@ -5,27 +5,16 @@ import { Sidebar } from 'primereact/sidebar'; //@param {object} props The properties accepted by the component. //@param {bool} props.sideBarVisible Used to control if the sidebar menu is visibile or not. //@param {function} props.setSideBarVisible Used by the component to hide the sidebar menu. -//@param {function} props.setSelectedScreen Used by the component to set what screen is displayed in the App component. -export default function Menu({ sideBarVisible, setSideBarVisible, setSelectedScreen }) { - //Define the labels for the menu. - const homeLabel = 'Home'; - const flightScheduleLabel = 'Flight Schedule'; - +export default function Menu({ sideBarVisible, setSideBarVisible }) { //Define the menus to display. const menuItems = [ { - label: homeLabel, - command: () => { - setSelectedScreen(homeLabel.toLowerCase()); - setSideBarVisible(false); - }, + label: 'Home', + url: '/', }, { - label: flightScheduleLabel, - command: () => { - setSelectedScreen(flightScheduleLabel.toLowerCase()); - setSideBarVisible(false); - }, + label: 'Flight Schedule', + url: '/FlightSchedule', } ]; diff --git a/jmayer.example.aspreact.client/src/components/notFound/NotFoundPage.jsx b/jmayer.example.aspreact.client/src/components/notFound/NotFoundPage.jsx new file mode 100644 index 0000000..46e693e --- /dev/null +++ b/jmayer.example.aspreact.client/src/components/notFound/NotFoundPage.jsx @@ -0,0 +1,6 @@ +//The not found page. It displays a description stating the page was not found in the website. +export default function NotFoundPage() { + return ( +

Sorry, the page was not found.

+ ); +} \ No newline at end of file From 73d6f8894b33f624b0fc5307fd52173cd68ce382 Mon Sep 17 00:00:00 2001 From: jmayer913 <72579603+jmayer913@users.noreply.github.com> Date: Fri, 4 Oct 2024 13:56:35 -0400 Subject: [PATCH 06/43] Added airline page & airline objects --- .../Airlines/Airline.cs | 53 +++++++++++++++++++ .../Airlines/AirlineController.cs | 16 ++++++ .../Airlines/AirlineDataLayer.cs | 10 ++++ .../Airlines/IAirlineDataLayer.cs | 10 ++++ .../FlightScheduleExampleBuilder.cs | 50 +++++++++++++++++ .../JMayer.Example.ASPReact.Server.csproj | 1 + JMayer.Example.ASPReact.Server/Program.cs | 50 +++++++++++++++-- jmayer.example.aspreact.client/src/App.jsx | 2 + .../src/components/airline/AirlinePage.jsx | 38 +++++++++++++ .../flightSchedule/FlightSchedulePage.jsx | 2 +- .../src/components/layout/Menu.jsx | 4 ++ 11 files changed, 232 insertions(+), 4 deletions(-) create mode 100644 JMayer.Example.ASPReact.Server/Airlines/Airline.cs create mode 100644 JMayer.Example.ASPReact.Server/Airlines/AirlineController.cs create mode 100644 JMayer.Example.ASPReact.Server/Airlines/AirlineDataLayer.cs create mode 100644 JMayer.Example.ASPReact.Server/Airlines/IAirlineDataLayer.cs create mode 100644 JMayer.Example.ASPReact.Server/FlightScheduleExampleBuilder.cs create mode 100644 jmayer.example.aspreact.client/src/components/airline/AirlinePage.jsx diff --git a/JMayer.Example.ASPReact.Server/Airlines/Airline.cs b/JMayer.Example.ASPReact.Server/Airlines/Airline.cs new file mode 100644 index 0000000..e0b270f --- /dev/null +++ b/JMayer.Example.ASPReact.Server/Airlines/Airline.cs @@ -0,0 +1,53 @@ +using JMayer.Data.Data; +using System.ComponentModel.DataAnnotations; +namespace JMayer.Example.ASPReact.Server.Airlines; + +/// +/// The class represents an airline and its codes. +/// +public class Airline : UserEditableDataObject +{ + /// + /// The property gets/sets the IATA code assigned by the IATA organization. + /// + [Required] + [RegularExpression("^[A-Z0-9]{2}$", ErrorMessage = "The IATA must be 2 alphanumeric characters; letters must be capitalized.")] + public string IATA { get;set; } = string.Empty; + + /// + /// The property gets/sets the ICAO code assigned by the International Aviation Organization. + /// + [RegularExpression("^[A-Z]{3}$", ErrorMessage = "The ICAO must be 3 capital letters.")] + public string ICAO { get; set; } = string.Empty; + + /// + /// The property gets/sets the number code assigned by the IATA organization. + /// + [Required] + [RegularExpression("^\\d{3}$", ErrorMessage = "The number code must be 3 digits.")] + public string NumberCode { get; set; } = "000"; + + /// + /// The default constructor. + /// + public Airline() { } + + /// + /// The copy constructor. + /// + /// The copy. + public Airline(Airline copy) => MapProperties(copy); + + /// + public override void MapProperties(DataObject dataObject) + { + base.MapProperties(dataObject); + + if (dataObject is Airline airline) + { + IATA = airline.IATA; + ICAO = airline.ICAO; + NumberCode = airline.NumberCode; + } + } +} diff --git a/JMayer.Example.ASPReact.Server/Airlines/AirlineController.cs b/JMayer.Example.ASPReact.Server/Airlines/AirlineController.cs new file mode 100644 index 0000000..c1893eb --- /dev/null +++ b/JMayer.Example.ASPReact.Server/Airlines/AirlineController.cs @@ -0,0 +1,16 @@ +using JMayer.Data.Database.DataLayer; +using JMayer.Web.Mvc.Controller; +using Microsoft.AspNetCore.Mvc; + +namespace JMayer.Example.ASPReact.Server.Airlines; + +/// +/// The class manages HTTP requests for CRUD operations associated with an airline in a database. +/// +[Route("api/[controller]")] +[ApiController] +public class AirlineController : UserEditableController +{ + /// + public AirlineController(IAirlineDataLayer dataLayer, ILogger logger) : base(dataLayer, logger) { } +} diff --git a/JMayer.Example.ASPReact.Server/Airlines/AirlineDataLayer.cs b/JMayer.Example.ASPReact.Server/Airlines/AirlineDataLayer.cs new file mode 100644 index 0000000..754746f --- /dev/null +++ b/JMayer.Example.ASPReact.Server/Airlines/AirlineDataLayer.cs @@ -0,0 +1,10 @@ +using JMayer.Data.Database.DataLayer.MemoryStorage; + +namespace JMayer.Example.ASPReact.Server.Airlines; + +/// +/// The class manages CRUD interactions with the database for an airline. +/// +public class AirlineDataLayer : UserEditableDataLayer, IAirlineDataLayer +{ +} diff --git a/JMayer.Example.ASPReact.Server/Airlines/IAirlineDataLayer.cs b/JMayer.Example.ASPReact.Server/Airlines/IAirlineDataLayer.cs new file mode 100644 index 0000000..0f856e8 --- /dev/null +++ b/JMayer.Example.ASPReact.Server/Airlines/IAirlineDataLayer.cs @@ -0,0 +1,10 @@ +using JMayer.Data.Database.DataLayer; + +namespace JMayer.Example.ASPReact.Server.Airlines; + +/// +/// The interface for interacting with an airline collection in a database using CRUD operations. +/// +public interface IAirlineDataLayer : IUserEditableDataLayer +{ +} diff --git a/JMayer.Example.ASPReact.Server/FlightScheduleExampleBuilder.cs b/JMayer.Example.ASPReact.Server/FlightScheduleExampleBuilder.cs new file mode 100644 index 0000000..6c3b8c6 --- /dev/null +++ b/JMayer.Example.ASPReact.Server/FlightScheduleExampleBuilder.cs @@ -0,0 +1,50 @@ +using JMayer.Example.ASPReact.Server.Airlines; + +namespace JMayer.Example.ASPReact.Server; + +/// +/// The class is used to generate example data for a flight schedule. +/// +public class FlightScheduleExampleBuilder +{ + /// + /// The property gets/sets the data layer used to interact with airlines. + /// + public IAirlineDataLayer AirlineDataLayer { get; set; } = new AirlineDataLayer(); + + /// + /// The method builds the flight schedule example data. + /// + public void Build() + { + BuildAirlines(); + } + + /// + /// The method builds the airlines for the flight schedule. + /// + private void BuildAirlines() + { + _ = AirlineDataLayer.CreateAsync(new Airline() + { + IATA = "AA", + ICAO = "AAL", + Name = "American Airlines", + NumberCode = "001", + }); + _ = AirlineDataLayer.CreateAsync(new Airline() + { + IATA = "DL", + ICAO = "DAL", + Name = "Delta Air Lines", + NumberCode = "006", + }); + _ = AirlineDataLayer.CreateAsync(new Airline() + { + IATA = "WN", + ICAO = "SWA", + Name = "Southwest Airlines", + NumberCode = "526", + }); + } +} diff --git a/JMayer.Example.ASPReact.Server/JMayer.Example.ASPReact.Server.csproj b/JMayer.Example.ASPReact.Server/JMayer.Example.ASPReact.Server.csproj index 105f408..afd16cf 100644 --- a/JMayer.Example.ASPReact.Server/JMayer.Example.ASPReact.Server.csproj +++ b/JMayer.Example.ASPReact.Server/JMayer.Example.ASPReact.Server.csproj @@ -10,6 +10,7 @@ + 8.*-* diff --git a/JMayer.Example.ASPReact.Server/Program.cs b/JMayer.Example.ASPReact.Server/Program.cs index 1da74a0..8c59fbb 100644 --- a/JMayer.Example.ASPReact.Server/Program.cs +++ b/JMayer.Example.ASPReact.Server/Program.cs @@ -1,14 +1,57 @@ +using JMayer.Example.ASPReact.Server; +using JMayer.Example.ASPReact.Server.Airlines; +using Microsoft.AspNetCore.ResponseCompression; +using System.IO.Compression; + var builder = WebApplication.CreateBuilder(args); -// Add services to the container. +#region Setup Database, Data Layers & Logging + +builder.Logging.ClearProviders(); +builder.Logging.AddConsole(); + +FlightScheduleExampleBuilder flightScheduleExampleBuilder = new(); +flightScheduleExampleBuilder.Build(); + +//Add the data layers. Because the example data needs to be built before registration and the data +//layers are memory based, dependency injection is not being used which is awkward but on a normal website, +//the middleware would handle the dependency injection. +builder.Services.AddSingleton(factory => (AirlineDataLayer)flightScheduleExampleBuilder.AirlineDataLayer); +#endregion + +#region Setup Services + +// Add services to the container. builder.Services.AddControllers(); + // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); +builder.Services.Configure(options => +{ + options.Level = CompressionLevel.Fastest; +}); +builder.Services.AddResponseCompression(options => +{ + options.Providers.Add(); +}); + +builder.Services.AddCors(options => +{ + options.AddPolicy("ReactPolicy", policy => + { + policy.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader(); + }); +}); + +#endregion + var app = builder.Build(); +#region Setup App + app.UseDefaultFiles(); app.UseStaticFiles(); @@ -20,11 +63,12 @@ } app.UseHttpsRedirection(); - app.UseAuthorization(); +app.UseCors("ReactPolicy"); app.MapControllers(); - app.MapFallbackToFile("/index.html"); +#endregion + app.Run(); diff --git a/jmayer.example.aspreact.client/src/App.jsx b/jmayer.example.aspreact.client/src/App.jsx index c24908b..f667cfa 100644 --- a/jmayer.example.aspreact.client/src/App.jsx +++ b/jmayer.example.aspreact.client/src/App.jsx @@ -9,6 +9,7 @@ import 'primereact/resources/themes/lara-dark-indigo/theme.css'; import 'primeflex/primeflex.css'; import 'primeicons/primeicons.css'; import './App.css'; +import AirlinePage from './components/airline/AirlinePage.jsx'; //The main layout of the website & the current page. function App() { @@ -21,6 +22,7 @@ function App() { } /> + } /> } /> } /> diff --git a/jmayer.example.aspreact.client/src/components/airline/AirlinePage.jsx b/jmayer.example.aspreact.client/src/components/airline/AirlinePage.jsx new file mode 100644 index 0000000..fda696f --- /dev/null +++ b/jmayer.example.aspreact.client/src/components/airline/AirlinePage.jsx @@ -0,0 +1,38 @@ +import { useState, useEffect } from 'react' +import { Card } from 'primereact/card'; +import { Column } from 'primereact/column'; +import { DataTable } from 'primereact/datatable'; + +//The airline page. Users can manage the airlines. +export default function AirlinePage() { + const [airlines, setAirlines] = useState([]); + + useEffect(() => { + let ignore = false; + + //Need to add error handling. + //Need to figure out how to not hardcode the base address. + fetch("https://localhost:7020/api/Airline/All") + .then(response => response.json()) + .then(json => { + if (!ignore) { + setAirlines(json) + } + }); + + return () => { + ignore = true; + } + }, []); + + return ( + + + + + + + + + ); +} \ No newline at end of file diff --git a/jmayer.example.aspreact.client/src/components/flightSchedule/FlightSchedulePage.jsx b/jmayer.example.aspreact.client/src/components/flightSchedule/FlightSchedulePage.jsx index e40933e..f6295b2 100644 --- a/jmayer.example.aspreact.client/src/components/flightSchedule/FlightSchedulePage.jsx +++ b/jmayer.example.aspreact.client/src/components/flightSchedule/FlightSchedulePage.jsx @@ -14,7 +14,7 @@ export default function FlightSchedulePage() { return ( - + diff --git a/jmayer.example.aspreact.client/src/components/layout/Menu.jsx b/jmayer.example.aspreact.client/src/components/layout/Menu.jsx index a9b5141..b55ecb2 100644 --- a/jmayer.example.aspreact.client/src/components/layout/Menu.jsx +++ b/jmayer.example.aspreact.client/src/components/layout/Menu.jsx @@ -12,6 +12,10 @@ export default function Menu({ sideBarVisible, setSideBarVisible }) { label: 'Home', url: '/', }, + { + label: 'Airlines', + url: '/Airline', + }, { label: 'Flight Schedule', url: '/FlightSchedule', From b5ebfcc70c6fe0430a7f5438645b0e64b8799826 Mon Sep 17 00:00:00 2001 From: jmayer913 <72579603+jmayer913@users.noreply.github.com> Date: Fri, 4 Oct 2024 14:18:03 -0400 Subject: [PATCH 07/43] Fixed the proxy to work with api calls --- JMayer.Example.ASPReact.Server/Program.cs | 4 ++-- .../src/components/airline/AirlinePage.jsx | 7 ++++--- jmayer.example.aspreact.client/vite.config.js | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/JMayer.Example.ASPReact.Server/Program.cs b/JMayer.Example.ASPReact.Server/Program.cs index 8c59fbb..8027998 100644 --- a/JMayer.Example.ASPReact.Server/Program.cs +++ b/JMayer.Example.ASPReact.Server/Program.cs @@ -14,8 +14,8 @@ flightScheduleExampleBuilder.Build(); //Add the data layers. Because the example data needs to be built before registration and the data -//layers are memory based, dependency injection is not being used which is awkward but on a normal website, -//the middleware would handle the dependency injection. +//layers are memory based, the middleware is not creating the data layers which is awkard but on a +//normal website, the middleware would handle this. builder.Services.AddSingleton(factory => (AirlineDataLayer)flightScheduleExampleBuilder.AirlineDataLayer); #endregion diff --git a/jmayer.example.aspreact.client/src/components/airline/AirlinePage.jsx b/jmayer.example.aspreact.client/src/components/airline/AirlinePage.jsx index fda696f..24bd128 100644 --- a/jmayer.example.aspreact.client/src/components/airline/AirlinePage.jsx +++ b/jmayer.example.aspreact.client/src/components/airline/AirlinePage.jsx @@ -10,14 +10,15 @@ export default function AirlinePage() { useEffect(() => { let ignore = false; - //Need to add error handling. - //Need to figure out how to not hardcode the base address. - fetch("https://localhost:7020/api/Airline/All") + fetch("/api/Airline/All") .then(response => response.json()) .then(json => { if (!ignore) { setAirlines(json) } + }) + .catch(error => { + //TO DO: Add error handling. }); return () => { diff --git a/jmayer.example.aspreact.client/vite.config.js b/jmayer.example.aspreact.client/vite.config.js index 6e0b4ce..6dd7094 100644 --- a/jmayer.example.aspreact.client/vite.config.js +++ b/jmayer.example.aspreact.client/vite.config.js @@ -43,7 +43,7 @@ export default defineConfig({ }, server: { proxy: { - '^/weatherforecast': { + '/api': { target, secure: false } From 737d6e06f7d8cbe47151aff3143e617f2365cb7e Mon Sep 17 00:00:00 2001 From: jmayer913 <72579603+jmayer913@users.noreply.github.com> Date: Fri, 4 Oct 2024 14:21:12 -0400 Subject: [PATCH 08/43] Added a workflow --- .github/workflows/mainworkflow.yml | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 .github/workflows/mainworkflow.yml diff --git a/.github/workflows/mainworkflow.yml b/.github/workflows/mainworkflow.yml new file mode 100644 index 0000000..c8c3466 --- /dev/null +++ b/.github/workflows/mainworkflow.yml @@ -0,0 +1,29 @@ +# This workflow will build a .NET project +# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-net + +name: MainWorkflow + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + +jobs: + build: + + runs-on: windows-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: 8.0.x + - name: Restore dependencies + run: dotnet restore + - name: Build + run: dotnet build --configuration Release --no-restore + - name: Test + run: dotnet test --verbosity normal From 707c7855160a44a9aff5a401e5a9a90c6fc884ae Mon Sep 17 00:00:00 2001 From: jmayer913 <72579603+jmayer913@users.noreply.github.com> Date: Wed, 9 Oct 2024 13:32:18 -0400 Subject: [PATCH 09/43] Added functionality to the airline data table --- .../src/components/airline/AirlinePage.jsx | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/jmayer.example.aspreact.client/src/components/airline/AirlinePage.jsx b/jmayer.example.aspreact.client/src/components/airline/AirlinePage.jsx index 24bd128..e17bd2f 100644 --- a/jmayer.example.aspreact.client/src/components/airline/AirlinePage.jsx +++ b/jmayer.example.aspreact.client/src/components/airline/AirlinePage.jsx @@ -28,11 +28,13 @@ export default function AirlinePage() { return ( - - - - - + + + + + ); From 00c89f96f8fdaa7177b9703d3b5c6c37054d6747 Mon Sep 17 00:00:00 2001 From: jmayer913 <72579603+jmayer913@users.noreply.github.com> Date: Wed, 9 Oct 2024 15:54:46 -0400 Subject: [PATCH 10/43] Added airline deletion --- jmayer.example.aspreact.client/src/App.jsx | 2 +- .../airline/AirlineDeleteConfirmDialog.jsx | 41 ++++++++++++ .../src/components/airline/AirlinePage.jsx | 64 +++++++++++++++---- 3 files changed, 95 insertions(+), 12 deletions(-) create mode 100644 jmayer.example.aspreact.client/src/components/airline/AirlineDeleteConfirmDialog.jsx diff --git a/jmayer.example.aspreact.client/src/App.jsx b/jmayer.example.aspreact.client/src/App.jsx index f667cfa..81b50cc 100644 --- a/jmayer.example.aspreact.client/src/App.jsx +++ b/jmayer.example.aspreact.client/src/App.jsx @@ -1,5 +1,6 @@ import { useState } from 'react'; import { BrowserRouter, Routes, Route } from 'react-router-dom'; +import AirlinePage from './components/airline/AirlinePage.jsx'; import FlightSchedulePage from './components/flightSchedule/FlightSchedulePage.jsx'; import HomePage from './components/home/HomePage.jsx'; import Header from './components/layout/Header.jsx'; @@ -9,7 +10,6 @@ import 'primereact/resources/themes/lara-dark-indigo/theme.css'; import 'primeflex/primeflex.css'; import 'primeicons/primeicons.css'; import './App.css'; -import AirlinePage from './components/airline/AirlinePage.jsx'; //The main layout of the website & the current page. function App() { diff --git a/jmayer.example.aspreact.client/src/components/airline/AirlineDeleteConfirmDialog.jsx b/jmayer.example.aspreact.client/src/components/airline/AirlineDeleteConfirmDialog.jsx new file mode 100644 index 0000000..9c26cd0 --- /dev/null +++ b/jmayer.example.aspreact.client/src/components/airline/AirlineDeleteConfirmDialog.jsx @@ -0,0 +1,41 @@ +import React from 'react' +import { Button } from 'primereact/button'; +import { Dialog } from 'primereact/dialog'; + +//Used to delete an airline; user must confirm first. +//@param {object} props The properties accepted by the component. +//@param {object} props.airline The airline to be deleted on user confirmation. +//@param {bool} props.visible Used to control if the dialog is visible or not. +//@param {function} props.hide Used to hide the dialog. +export default function AirlineDeleteConfirmDialog({ airline, visible, hide }) { + //Sends a request to the server to delete the airline. + //This is done only after the user has confirmed the deletion. + const deleteAirline = () => { + fetch('/api/Airline/' + airline.integer64ID, { method: 'DELETE' }) + .then(() => { + hide(); + //TO DO: Refresh the data table. + }) + .catch(error => { + //TO DO: Add error handling. + }); + }; + + //The footer to be displayed on the dialog. + const footer = ( + +
+ ); + }; + + const actionBodyTemple = (rowData) => { + return ( + +