diff --git a/EnvelopeGenerator.sln b/EnvelopeGenerator.sln
index 8fa06e8d..0db77ff0 100644
--- a/EnvelopeGenerator.sln
+++ b/EnvelopeGenerator.sln
@@ -41,6 +41,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EnvelopeGenerator.API", "En
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "receiverUI", "receiverUI", "{73D8F466-90AA-4F95-9BD1-7CDBB8565162}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EnvelopeGenerator.ReceiverUI.Web", "receiverUI\EnvelopeGenerator.ReceiverUI.Web\EnvelopeGenerator.ReceiverUI.Web\EnvelopeGenerator.ReceiverUI.Web.csproj", "{AAD4720E-D175-44B5-B431-DB0BA636CD20}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EnvelopeGenerator.ReceiverUI.Web.Client", "receiverUI\EnvelopeGenerator.ReceiverUI.Web\EnvelopeGenerator.ReceiverUI.Web.Client\EnvelopeGenerator.ReceiverUI.Web.Client.csproj", "{5D97B2C2-E19B-4958-81E1-38864EC88FEB}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -99,6 +103,14 @@ Global
{EC768913-6270-14F4-1DD3-69C87A659462}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EC768913-6270-14F4-1DD3-69C87A659462}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EC768913-6270-14F4-1DD3-69C87A659462}.Release|Any CPU.Build.0 = Release|Any CPU
+ {AAD4720E-D175-44B5-B431-DB0BA636CD20}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {AAD4720E-D175-44B5-B431-DB0BA636CD20}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {AAD4720E-D175-44B5-B431-DB0BA636CD20}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {AAD4720E-D175-44B5-B431-DB0BA636CD20}.Release|Any CPU.Build.0 = Release|Any CPU
+ {5D97B2C2-E19B-4958-81E1-38864EC88FEB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {5D97B2C2-E19B-4958-81E1-38864EC88FEB}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {5D97B2C2-E19B-4958-81E1-38864EC88FEB}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {5D97B2C2-E19B-4958-81E1-38864EC88FEB}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -121,6 +133,8 @@ Global
{E3676510-7030-4E85-86E1-51E483E2A3B6} = {9943209E-1744-4944-B1BA-4F87FC1A0EEB}
{EC768913-6270-14F4-1DD3-69C87A659462} = {E3C758DC-914D-4B7E-8457-0813F1FDB0CB}
{73D8F466-90AA-4F95-9BD1-7CDBB8565162} = {E3C758DC-914D-4B7E-8457-0813F1FDB0CB}
+ {AAD4720E-D175-44B5-B431-DB0BA636CD20} = {73D8F466-90AA-4F95-9BD1-7CDBB8565162}
+ {5D97B2C2-E19B-4958-81E1-38864EC88FEB} = {73D8F466-90AA-4F95-9BD1-7CDBB8565162}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {73E60370-756D-45AD-A19A-C40A02DACCC7}
diff --git a/receiverUI/.github/copilot-instructions.md b/receiverUI/.github/copilot-instructions.md
new file mode 100644
index 00000000..cf732a5b
--- /dev/null
+++ b/receiverUI/.github/copilot-instructions.md
@@ -0,0 +1,22 @@
+---
+description: 'Answer questions about DevExpress UI Components and their APIs using the dxdocs server'
+---
+
+You are a .NET programmer and DevExpress products expert.
+
+You are tasked with answering questions about DevExpress components and their APIs using dxdocs MCP server tools.
+
+For **ANY** question about DevExpress components, use the dxdocs server to construct your answer.
+
+## Workflow:
+1. **Call devexpress_docs_search** to obtain help topics related to the user question
+2. **Call devexpress_docs_get_content** to fetch and read most relevant help topics
+3. **Reflect on obtained content** and how it relates to the question
+4. **Provide a comprehensive answer** based solely on retrieved information
+
+## Constraints:
+- **Use devexpress_docs_search only once per question** to avoid redundant queries
+- When answering questions, **use only information obtained from MCP server tools**
+- **Include code examples** when available in the documentation
+- **Reference specific DevExpress controls and properties** mentioned in the documentation
+- **Invoke version-specific MCP tools** (for example, dxdocs25_1) if a user specifies a version (for example, v25.1)
diff --git a/receiverUI/.mcp.json b/receiverUI/.mcp.json
new file mode 100644
index 00000000..b44d769b
--- /dev/null
+++ b/receiverUI/.mcp.json
@@ -0,0 +1,12 @@
+{
+ "servers": {
+ "dxdocs": {
+ "url": "https://api.devexpress.com/mcp/docs",
+ "type": "http"
+ },
+ "dxdocs25_1": {
+ "url": "https://api.devexpress.com/mcp/docs?v=25.1",
+ "type": "http"
+ }
+ }
+}
\ No newline at end of file
diff --git a/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web.Client/Documents/Invoice.pdf b/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web.Client/Documents/Invoice.pdf
new file mode 100644
index 00000000..dbd52014
Binary files /dev/null and b/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web.Client/Documents/Invoice.pdf differ
diff --git a/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web.Client/EnvelopeGenerator.ReceiverUI.Web.Client.csproj b/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web.Client/EnvelopeGenerator.ReceiverUI.Web.Client.csproj
new file mode 100644
index 00000000..27d58a31
--- /dev/null
+++ b/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web.Client/EnvelopeGenerator.ReceiverUI.Web.Client.csproj
@@ -0,0 +1,30 @@
+
+
+ net8.0
+ enable
+ enable
+ true
+ Default
+ $(MSBuildWarningsAsMessage);WASM0001
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web.Client/Layout/Drawer.razor b/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web.Client/Layout/Drawer.razor
new file mode 100644
index 00000000..73a8d3e5
--- /dev/null
+++ b/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web.Client/Layout/Drawer.razor
@@ -0,0 +1,38 @@
+@inherits DrawerStateComponentBase
+
+
+
+
+
diff --git a/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web.Client/Services/ServiceExtensions.cs b/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web.Client/Services/ServiceExtensions.cs
new file mode 100644
index 00000000..830c0651
--- /dev/null
+++ b/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web.Client/Services/ServiceExtensions.cs
@@ -0,0 +1,25 @@
+using Azure;
+using Azure.AI.OpenAI;
+using Microsoft.Extensions.AI;
+
+namespace EnvelopeGenerator.ReceiverUI.Web.Client.Utils
+{
+ public static class ServiceExtensions
+ {
+ // Demo AI services are rate limited and intended for demonstration purposes only.
+ // DevExpress does not offer a REST API and does not ship any built-in LLMs/SLMs.
+ // Use of demo credentials in production is strictly prohibited.
+ // Specify the Azure OpenAI endpoint, key, and deployment name in the 'appsettings.json' file.
+ public static void AddChatClient(this IServiceCollection services, string aiEndpoint, string aiKey, string deployment)
+ {
+ services.AddDevExpressAI();
+ services.AddScoped(_ =>
+ {
+ var azureClient = new AzureOpenAIClient(new Uri(aiEndpoint), new AzureKeyCredential(aiKey));
+ return azureClient
+ .GetChatClient(deployment)
+ .AsIChatClient();
+ });
+ }
+ }
+}
diff --git a/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web.Client/Shared/DrawerStateComponentBase.cs b/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web.Client/Shared/DrawerStateComponentBase.cs
new file mode 100644
index 00000000..20b96024
--- /dev/null
+++ b/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web.Client/Shared/DrawerStateComponentBase.cs
@@ -0,0 +1,77 @@
+using Microsoft.AspNetCore.Components;
+
+namespace EnvelopeGenerator.ReceiverUI.Web.Client.Shared
+{
+ public abstract class DrawerStateComponentBase : ComponentBase
+ {
+ [SupplyParameterFromQuery(Name = DrawerStateUrlBuilder.DrawerStateQueryParameterName)]
+ public bool ToggledDrawer { get; set; }
+
+ [Inject] NavigationManager NavigationManager { get; set; } = null!;
+
+ protected string AddDrawerStateToUrl(string baseUrl)
+ {
+ return DrawerStateUrlBuilder.AddStateToUrl(baseUrl, ToggledDrawer, NavigationManager);
+ }
+
+ protected string AddDrawerStateToUrlToggled(string baseUrl)
+ {
+ return DrawerStateUrlBuilder.AddStateToUrl(baseUrl, !ToggledDrawer, NavigationManager);
+ }
+
+ protected string RemoveDrawerStateFromUrl(string baseUrl)
+ {
+ return DrawerStateUrlBuilder.RemoveStateFromUrl(baseUrl, NavigationManager);
+ }
+ }
+
+ public abstract class DrawerStateLayoutComponentBase : LayoutComponentBase
+ {
+ [SupplyParameterFromQuery(Name = DrawerStateUrlBuilder.DrawerStateQueryParameterName)]
+ public bool ToggledDrawer { get; set; }
+
+ [Inject] NavigationManager NavigationManager { get; set; } = null!;
+
+ protected string AddDrawerStateToUrl(string baseUrl)
+ {
+ return DrawerStateUrlBuilder.AddStateToUrl(baseUrl, ToggledDrawer, NavigationManager);
+ }
+
+ protected string AddDrawerStateToUrlToggled(string baseUrl)
+ {
+ return DrawerStateUrlBuilder.AddStateToUrl(baseUrl, !ToggledDrawer, NavigationManager);
+ }
+
+ protected string RemoveDrawerStateFromUrl(string baseUrl)
+ {
+ return DrawerStateUrlBuilder.RemoveStateFromUrl(baseUrl, NavigationManager);
+ }
+ }
+
+ internal static class DrawerStateUrlBuilder
+ {
+ public const string DrawerStateQueryParameterName = "toggledSidebar";
+
+ public static string AddStateToUrl(string baseUrl, bool toggledDrawer, NavigationManager navigationManager)
+ {
+ return navigationManager.GetUriWithQueryParameters(
+ baseUrl,
+ new Dictionary
+ {
+ [DrawerStateQueryParameterName] = toggledDrawer ? true : null
+ }
+ );
+ }
+
+ public static string RemoveStateFromUrl(string baseUrl, NavigationManager navigationManager)
+ {
+ return navigationManager.GetUriWithQueryParameters(
+ baseUrl,
+ new Dictionary
+ {
+ [DrawerStateQueryParameterName] = null
+ }
+ );
+ }
+ }
+}
\ No newline at end of file
diff --git a/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web.Client/_Imports.razor b/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web.Client/_Imports.razor
new file mode 100644
index 00000000..3b08aa5b
--- /dev/null
+++ b/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web.Client/_Imports.razor
@@ -0,0 +1,16 @@
+@using System.Net.Http
+@using System.Net.Http.Json
+@using Microsoft.AspNetCore.Components.Forms
+@using Microsoft.AspNetCore.Components.Routing
+@using Microsoft.AspNetCore.Components.Web
+@using Microsoft.AspNetCore.Components.Web.Virtualization
+@using Microsoft.JSInterop
+@using static Microsoft.AspNetCore.Components.Web.RenderMode
+@using EnvelopeGenerator.ReceiverUI.Web.Client
+@using EnvelopeGenerator.ReceiverUI.Web.Client.Shared
+
+@using DevExpress.Blazor
+@using DevExpress.Blazor.PdfViewer
+@using DevExpress.Blazor.Reporting.Models
+@using DevExpress.AIIntegration.Blazor.Chat
+@using DevExpress.AIIntegration.Blazor.HtmlEditor
diff --git a/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web.Client/wwwroot/appsettings.Development.json b/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web.Client/wwwroot/appsettings.Development.json
new file mode 100644
index 00000000..0c208ae9
--- /dev/null
+++ b/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web.Client/wwwroot/appsettings.Development.json
@@ -0,0 +1,8 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.AspNetCore": "Warning"
+ }
+ }
+}
diff --git a/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web.Client/wwwroot/appsettings.json b/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web.Client/wwwroot/appsettings.json
new file mode 100644
index 00000000..0c208ae9
--- /dev/null
+++ b/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web.Client/wwwroot/appsettings.json
@@ -0,0 +1,8 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.AspNetCore": "Warning"
+ }
+ }
+}
diff --git a/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web.sln b/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web.sln
new file mode 100644
index 00000000..94a08e9c
--- /dev/null
+++ b/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web.sln
@@ -0,0 +1,50 @@
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.0.0
+MinimumVisualStudioVersion = 16.0.0.0
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EnvelopeGenerator.ReceiverUI.Web", "EnvelopeGenerator.ReceiverUI.Web\EnvelopeGenerator.ReceiverUI.Web.csproj", "{650B3CE7-2E93-4CC4-9F46-466686815EAA}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EnvelopeGenerator.ReceiverUI.Web.Client", "EnvelopeGenerator.ReceiverUI.Web.Client\EnvelopeGenerator.ReceiverUI.Web.Client.csproj", "{5990939C-7E7B-4CFA-86FF-44CA5756498A}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ Release|Any CPU = Release|Any CPU
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {5990939C-7E7B-4CFA-86FF-44CA5756498A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {5990939C-7E7B-4CFA-86FF-44CA5756498A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {5990939C-7E7B-4CFA-86FF-44CA5756498A}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {5990939C-7E7B-4CFA-86FF-44CA5756498A}.Debug|x64.Build.0 = Debug|Any CPU
+ {5990939C-7E7B-4CFA-86FF-44CA5756498A}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {5990939C-7E7B-4CFA-86FF-44CA5756498A}.Debug|x86.Build.0 = Debug|Any CPU
+ {5990939C-7E7B-4CFA-86FF-44CA5756498A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {5990939C-7E7B-4CFA-86FF-44CA5756498A}.Release|Any CPU.Build.0 = Release|Any CPU
+ {5990939C-7E7B-4CFA-86FF-44CA5756498A}.Release|x64.ActiveCfg = Release|Any CPU
+ {5990939C-7E7B-4CFA-86FF-44CA5756498A}.Release|x64.Build.0 = Release|Any CPU
+ {5990939C-7E7B-4CFA-86FF-44CA5756498A}.Release|x86.ActiveCfg = Release|Any CPU
+ {5990939C-7E7B-4CFA-86FF-44CA5756498A}.Release|x86.Build.0 = Release|Any CPU
+ {650B3CE7-2E93-4CC4-9F46-466686815EAA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {650B3CE7-2E93-4CC4-9F46-466686815EAA}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {650B3CE7-2E93-4CC4-9F46-466686815EAA}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {650B3CE7-2E93-4CC4-9F46-466686815EAA}.Debug|x64.Build.0 = Debug|Any CPU
+ {650B3CE7-2E93-4CC4-9F46-466686815EAA}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {650B3CE7-2E93-4CC4-9F46-466686815EAA}.Debug|x86.Build.0 = Debug|Any CPU
+ {650B3CE7-2E93-4CC4-9F46-466686815EAA}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {650B3CE7-2E93-4CC4-9F46-466686815EAA}.Release|Any CPU.Build.0 = Release|Any CPU
+ {650B3CE7-2E93-4CC4-9F46-466686815EAA}.Release|x64.ActiveCfg = Release|Any CPU
+ {650B3CE7-2E93-4CC4-9F46-466686815EAA}.Release|x64.Build.0 = Release|Any CPU
+ {650B3CE7-2E93-4CC4-9F46-466686815EAA}.Release|x86.ActiveCfg = Release|Any CPU
+ {650B3CE7-2E93-4CC4-9F46-466686815EAA}.Release|x86.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {4C26868E-5E7C-458D-82E3-040509D0C71F}
+ EndGlobalSection
+EndGlobal
diff --git a/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web/Components/App.razor b/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web/Components/App.razor
new file mode 100644
index 00000000..b2892046
--- /dev/null
+++ b/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web/Components/App.razor
@@ -0,0 +1,31 @@
+@using Microsoft.AspNetCore.Mvc.ViewFeatures
+@inject IFileVersionProvider FileVersionProvider
+
+
+
+
+
+
+
+ @DxResourceManager.RegisterTheme(ActiveTheme)
+ @DxResourceManager.RegisterScripts()
+
+
+
+
+
+
+
+
+
+
+
+@code {
+ static readonly ITheme ActiveTheme = Themes.Fluent.Clone(properties => {
+ properties.Mode = ThemeMode.Light;
+ properties.UseBootstrapStyles = true;
+ });
+
+ private string AppendVersion(string path) => FileVersionProvider.AddFileVersionToPath("/", path);
+
+}
diff --git a/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web/Components/Pages/Error.razor b/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web/Components/Pages/Error.razor
new file mode 100644
index 00000000..576cc2d2
--- /dev/null
+++ b/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web/Components/Pages/Error.razor
@@ -0,0 +1,36 @@
+@page "/Error"
+@using System.Diagnostics
+
+Error
+
+
Error.
+
An error occurred while processing your request.
+
+@if (ShowRequestId)
+{
+
+ Request ID:@RequestId
+
+}
+
+
Development Mode
+
+ Swapping to Development environment will display more detailed information about the error that occurred.
+
+
+ The Development environment shouldn't be enabled for deployed applications.
+ It can result in displaying sensitive information from exceptions to end users.
+ For local debugging, enable the Development environment by setting the ASPNETCORE_ENVIRONMENT environment variable to Development
+ and restarting the app.
+
+
+@code{
+ [CascadingParameter]
+ private HttpContext? HttpContext { get; set; }
+
+ private string? RequestId { get; set; }
+ private bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
+
+ protected override void OnInitialized() =>
+ RequestId = Activity.Current?.Id ?? HttpContext?.TraceIdentifier;
+}
diff --git a/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web/Components/_Imports.razor b/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web/Components/_Imports.razor
new file mode 100644
index 00000000..5d6421db
--- /dev/null
+++ b/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web/Components/_Imports.razor
@@ -0,0 +1,18 @@
+@using System.Net.Http
+@using System.Net.Http.Json
+@using Microsoft.AspNetCore.Components.Forms
+@using Microsoft.AspNetCore.Components.Routing
+@using Microsoft.AspNetCore.Components.Web
+@using Microsoft.AspNetCore.Components.Web.Virtualization
+@using Microsoft.JSInterop
+@using static Microsoft.AspNetCore.Components.Web.RenderMode
+@using EnvelopeGenerator.ReceiverUI.Web
+@using EnvelopeGenerator.ReceiverUI.Web.Components
+@using EnvelopeGenerator.ReceiverUI.Web.Client
+@using EnvelopeGenerator.ReceiverUI.Web.Client.Shared
+
+@using DevExpress.Blazor
+@using DevExpress.Blazor.PdfViewer
+@using DevExpress.Blazor.Reporting.Models
+@using DevExpress.AIIntegration.Blazor.Chat
+@using DevExpress.AIIntegration.Blazor.HtmlEditor
diff --git a/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web.csproj b/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web.csproj
new file mode 100644
index 00000000..f37a5a4f
--- /dev/null
+++ b/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web.csproj
@@ -0,0 +1,25 @@
+
+
+ net8.0
+ enable
+ enable
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web/Program.cs b/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web/Program.cs
new file mode 100644
index 00000000..a944b892
--- /dev/null
+++ b/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web/Program.cs
@@ -0,0 +1,78 @@
+using EnvelopeGenerator.ReceiverUI.Web.Client.Utils;
+using EnvelopeGenerator.ReceiverUI.Web.Components;
+using System.Text;
+
+var builder = WebApplication.CreateBuilder(args);
+
+// Add services to the container.
+builder.Services.AddRazorComponents()
+ .AddInteractiveServerComponents()
+ .AddInteractiveWebAssemblyComponents();
+
+builder.Services.AddDevExpressBlazor(options =>
+{
+ options.SizeMode = DevExpress.Blazor.SizeMode.Medium;
+});
+
+var aiUri = builder.Configuration.GetSection("AzureOpenAISettings")["Endpoint"];
+var aiKey = builder.Configuration.GetSection("AzureOpenAISettings")["Key"];
+var aiModel = builder.Configuration.GetSection("AzureOpenAISettings")["DeploymentName"];
+
+if (string.IsNullOrEmpty(aiUri) || string.IsNullOrEmpty(aiKey) || string.IsNullOrEmpty(aiModel))
+ throw new InvalidOperationException("Specify the OpenAI endpoint, key, and deployment name in the 'appsettings.json' file.");
+builder.Services.AddChatClient(aiUri, aiKey, aiModel);
+builder.Services.AddHttpClient();
+
+builder.Services.AddMvc();
+
+builder.Services.AddDevExpressServerSideBlazorPdfViewer();
+
+var app = builder.Build();
+
+// Configure the HTTP request pipeline.
+if (app.Environment.IsDevelopment())
+{
+ app.UseWebAssemblyDebugging();
+}
+else
+{
+ app.UseExceptionHandler("/Error", createScopeForErrors: true);
+ // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
+ app.UseHsts();
+}
+
+app.MapPost("/api/chat/{*path}", async (string path, HttpContext context, CancellationToken ct) =>
+{
+ var httpClientFactory = context.RequestServices.GetRequiredService();
+
+ var client = httpClientFactory.CreateClient();
+ client.BaseAddress = new(aiUri);
+ client.DefaultRequestHeaders.Authorization = new("Bearer", aiKey);
+
+ var newPath = path.Replace("proxychat", aiModel);
+ var endpointUri = new Uri(aiUri);
+ var uriBuilder = new UriBuilder(endpointUri)
+ {
+ Path = $"{endpointUri.AbsolutePath}/{newPath}",
+ Query = context.Request.QueryString.Value
+ };
+
+ var body = await new StreamReader(context.Request.Body).ReadToEndAsync(ct);
+
+ var response = await client.PostAsync(uriBuilder.Uri, new StringContent(body, Encoding.UTF8, "application/json"), ct);
+ context.Response.StatusCode = (int)response.StatusCode;
+ await response.Content.CopyToAsync(context.Response.Body, ct);
+});
+
+app.UseHttpsRedirection();
+
+app.UseStaticFiles();
+app.UseAntiforgery();
+
+app.MapRazorComponents()
+ .AddInteractiveServerRenderMode()
+ .AddInteractiveWebAssemblyRenderMode()
+ .AddAdditionalAssemblies(typeof(EnvelopeGenerator.ReceiverUI.Web.Client._Imports).Assembly)
+ .AllowAnonymous();
+
+app.Run();
diff --git a/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web/Properties/launchSettings.json b/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web/Properties/launchSettings.json
new file mode 100644
index 00000000..4a42f9d4
--- /dev/null
+++ b/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web/Properties/launchSettings.json
@@ -0,0 +1,25 @@
+{
+ "$schema": "http://json.schemastore.org/launchsettings.json",
+ "profiles": {
+ "http": {
+ "commandName": "Project",
+ "dotnetRunMessages": true,
+ "launchBrowser": true,
+ "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}",
+ "applicationUrl": "http://localhost:5000",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ },
+ "https": {
+ "commandName": "Project",
+ "dotnetRunMessages": true,
+ "launchBrowser": true,
+ "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}",
+ "applicationUrl": "https://localhost:5001;http://localhost:5000",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ }
+ }
+}
diff --git a/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web/appsettings.Development.json b/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web/appsettings.Development.json
new file mode 100644
index 00000000..0c208ae9
--- /dev/null
+++ b/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web/appsettings.Development.json
@@ -0,0 +1,8 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.AspNetCore": "Warning"
+ }
+ }
+}
diff --git a/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web/appsettings.json b/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web/appsettings.json
new file mode 100644
index 00000000..5473a435
--- /dev/null
+++ b/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web/appsettings.json
@@ -0,0 +1,14 @@
+{
+ "AzureOpenAISettings": {
+ "Endpoint": "https://public-api.devexpress.com/demo-openai",
+ "Key": "DEMO",
+ "DeploymentName": "gpt-4.1"
+ },
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.AspNetCore": "Warning"
+ }
+ },
+ "AllowedHosts": "*"
+}
diff --git a/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web/wwwroot/css/icons.css b/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web/wwwroot/css/icons.css
new file mode 100644
index 00000000..85d0aec6
--- /dev/null
+++ b/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web/wwwroot/css/icons.css
@@ -0,0 +1,38 @@
+.icon {
+ width: 1.25rem;
+ height: 1.25rem;
+ background-color: currentcolor;
+ mask-image: var(--icon-mask-image);
+ mask-position: center;
+ mask-repeat: no-repeat;
+}
+
+.icon-back {
+ --icon-mask-image: url("/images/back.svg");
+}
+.icon-close {
+ --icon-mask-image: url("/images/close.svg");
+}
+.icon-demos {
+ --icon-mask-image: url("/images/demos.svg");
+}
+.icon-docs {
+ --icon-mask-image: url("/images/doc.svg");
+}
+.icon-menu {
+ --icon-mask-image: url("/images/menu.svg");
+}
+
+/* pages */
+.icon-counter {
+ --icon-mask-image: url("/images/pages/counter.svg");
+}
+.icon-home {
+ --icon-mask-image: url("/images/pages/home.svg");
+}
+.icon-pdf-viewer {
+ --icon-mask-image: url("/images/pages/document-pdf.svg");
+}
+.icon-weather {
+ --icon-mask-image: url("/images/pages/weather.svg");
+}
diff --git a/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web/wwwroot/css/open-iconic/README.md b/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web/wwwroot/css/open-iconic/README.md
new file mode 100644
index 00000000..6b810e47
--- /dev/null
+++ b/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web/wwwroot/css/open-iconic/README.md
@@ -0,0 +1,114 @@
+[Open Iconic v1.1.1](http://useiconic.com/open)
+===========
+
+### Open Iconic is the open source sibling of [Iconic](http://useiconic.com). It is a hyper-legible collection of 223 icons with a tiny footprint—ready to use with Bootstrap and Foundation. [View the collection](http://useiconic.com/open#icons)
+
+
+
+## What's in Open Iconic?
+
+* 223 icons designed to be legible down to 8 pixels
+* Super-light SVG files - 61.8 for the entire set
+* SVG sprite—the modern replacement for icon fonts
+* Webfont (EOT, OTF, SVG, TTF, WOFF), PNG and WebP formats
+* Webfont stylesheets (including versions for Bootstrap and Foundation) in CSS, LESS, SCSS and Stylus formats
+* PNG and WebP raster images in 8px, 16px, 24px, 32px, 48px and 64px.
+
+
+## Getting Started
+
+#### For code samples and everything else you need to get started with Open Iconic, check out our [Icons](http://useiconic.com/open#icons) and [Reference](http://useiconic.com/open#reference) sections.
+
+### General Usage
+
+#### Using Open Iconic's SVGs
+
+We like SVGs and we think they're the way to display icons on the web. Since Open Iconic are just basic SVGs, we suggest you display them like you would any other image (don't forget the `alt` attribute).
+
+```
+
+```
+
+#### Using Open Iconic's SVG Sprite
+
+Open Iconic also comes in a SVG sprite which allows you to display all the icons in the set with a single request. It's like an icon font, without being a hack.
+
+Adding an icon from an SVG sprite is a little different than what you're used to, but it's still a piece of cake. *Tip: To make your icons easily style able, we suggest adding a general class to the* `